From 3b1c082791592097e2c944ef98ec86e4234882bf Mon Sep 17 00:00:00 2001 From: Naisila Puka <37271756+naisila@users.noreply.github.com> Date: Mon, 3 Feb 2025 17:13:40 +0300 Subject: [PATCH] Drops PG14 support (#7753) DESCRIPTION: Drops PG14 support 1. Remove "$version_num" != 'xx' from configure file 2. delete all PG_VERSION_NUM = PG_VERSION_XX references in the code 3. Look at pg_version_compat.h file, remove all _compat functions etc defined specifically for PGXX differences 4. delete all PG_VERSION_NUM >= PG_VERSION_(XX+1), PG_VERSION_NUM < PG_VERSION_(XX+1) ifs in the codebase 5. delete ruleutils_xx.c file 6. cleanup normalize.sed file from pg14 specific lines 7. delete all alternative output files for that particular PG version, server_version_ge variable helps here --- .gitattributes | 2 - .github/workflows/build_and_test.yml | 31 +- configure | 2 +- configure.ac | 2 +- src/backend/columnar/columnar_customscan.c | 3 - src/backend/columnar/columnar_metadata.c | 2 +- src/backend/columnar/columnar_tableam.c | 13 +- src/backend/distributed/clock/causal_clock.c | 11 - src/backend/distributed/commands/collation.c | 30 - .../commands/create_distributed_table.c | 9 - src/backend/distributed/commands/database.c | 20 - .../commands/distribute_object_ops.c | 11 +- .../distributed/commands/foreign_constraint.c | 2 - .../distributed/commands/publication.c | 21 - src/backend/distributed/commands/role.c | 15 - src/backend/distributed/commands/sequence.c | 5 - src/backend/distributed/commands/table.c | 15 +- src/backend/distributed/commands/trigger.c | 95 - .../connection/shared_connection_stats.c | 10 - .../distributed/deparser/citus_ruleutils.c | 4 - .../deparser/deparse_database_stmts.c | 1 - .../deparser/deparse_publication_stmts.c | 136 - .../deparser/deparse_sequence_stmts.c | 7 - .../deparser/deparse_table_stmts.c | 2 - .../deparser/qualify_publication_stmt.c | 34 - .../deparser/qualify_sequence_stmt.c | 5 - .../distributed/deparser/ruleutils_14.c | 8638 ----------------- .../distributed/executor/adaptive_executor.c | 25 - .../distributed/executor/query_stats.c | 13 - src/backend/distributed/metadata/dependency.c | 2 - .../distributed/metadata/metadata_sync.c | 43 - .../metadata/pg_get_object_address_13_14_15.c | 4 - .../planner/combine_query_planner.c | 3 - .../distributed/planner/distributed_planner.c | 5 - .../distributed/planner/merge_planner.c | 37 - .../distributed/planner/multi_explain.c | 4 +- .../shardsplit/shardsplit_decoder.c | 4 - src/backend/distributed/shared_library_init.c | 11 - src/backend/distributed/test/fake_am.c | 2 +- .../test/shared_connection_counters.c | 5 - .../distributed/transaction/backend_data.c | 9 - .../distributed/utils/background_jobs.c | 81 - .../distributed/utils/citus_stat_tenants.c | 11 +- .../columnar/columnar_version_compat.h | 8 - src/include/distributed/commands.h | 6 - src/include/distributed/deparser.h | 4 - src/include/distributed/distributed_planner.h | 5 - src/include/distributed/metadata_sync.h | 3 - src/include/distributed/resource_lock.h | 2 - src/include/pg_version_compat.h | 75 +- src/include/pg_version_constants.h | 1 - src/test/regress/bin/normalize.sed | 6 - .../expected/citus_local_tables_queries.out | 11 - .../expected/citus_local_tables_queries_0.out | 1168 --- src/test/regress/expected/columnar_pg15.out | 7 - src/test/regress/expected/columnar_pg15_0.out | 6 - .../expected/columnar_vacuum_vs_insert.out | 2 +- .../expected/coordinator_shouldhaveshards.out | 11 - .../coordinator_shouldhaveshards_0.out | 1190 --- src/test/regress/expected/cte_inline.out | 11 - src/test/regress/expected/cte_inline_0.out | 1489 --- .../regress/expected/detect_conn_close.out | 7 - .../regress/expected/detect_conn_close_0.out | 9 - .../expected/grant_on_schema_propagation.out | 10 - .../grant_on_schema_propagation_0.out | 400 - .../expected/insert_select_repartition.out | 11 - .../expected/insert_select_repartition_0.out | 1334 --- .../expected/intermediate_result_pruning.out | 11 - .../intermediate_result_pruning_0.out | 1077 -- src/test/regress/expected/issue_5248.out | 12 - src/test/regress/expected/issue_5248_0.out | 230 - .../expected/local_shard_execution.out | 11 - .../expected/local_shard_execution_0.out | 3302 ------- .../local_shard_execution_replicated.out | 11 - .../local_shard_execution_replicated_0.out | 2462 ----- src/test/regress/expected/merge.out | 7 - src/test/regress/expected/merge_0.out | 6 - src/test/regress/expected/merge_arbitrary.out | 7 - .../regress/expected/merge_arbitrary_0.out | 6 - .../expected/merge_arbitrary_create.out | 7 - .../expected/merge_arbitrary_create_0.out | 6 - .../expected/merge_partition_tables.out | 7 - .../expected/merge_partition_tables_0.out | 6 - .../regress/expected/merge_repartition1.out | 7 - .../regress/expected/merge_repartition1_0.out | 6 - .../regress/expected/merge_repartition2.out | 7 - .../regress/expected/merge_repartition2_0.out | 6 - .../expected/merge_schema_sharding.out | 7 - .../expected/merge_schema_sharding_0.out | 6 - src/test/regress/expected/merge_vcore.out | 7 - src/test/regress/expected/merge_vcore_0.out | 6 - ...ter_table_add_constraints_without_name.out | 5 - .../expected/multi_deparse_shard_query.out | 11 - .../expected/multi_deparse_shard_query_0.out | 423 - src/test/regress/expected/multi_extension.out | 8 +- .../regress/expected/multi_insert_select.out | 11 - .../expected/multi_insert_select_0.out | 3507 ------- .../expected/multi_insert_select_conflict.out | 11 - .../multi_insert_select_conflict_0.out | 600 -- .../regress/expected/multi_metadata_sync.out | 10 - .../multi_mx_insert_select_repartition.out | 11 - .../mx_coordinator_shouldhaveshards.out | 11 - .../mx_coordinator_shouldhaveshards_0.out | 335 - src/test/regress/expected/pg15.out | 7 - src/test/regress/expected/pg15_0.out | 9 - src/test/regress/expected/pg15_jsonpath.out | 7 - src/test/regress/expected/pg15_jsonpath_0.out | 10 - src/test/regress/expected/pgmerge.out | 7 - src/test/regress/expected/pgmerge_0.out | 6 - src/test/regress/expected/publication.out | 12 - src/test/regress/expected/single_node.out | 11 - .../upgrade_citus_finish_citus_upgrade_1.out | 41 + .../sql/citus_local_tables_queries.sql | 6 - src/test/regress/sql/columnar_pg15.sql | 8 - .../sql/coordinator_shouldhaveshards.sql | 6 - src/test/regress/sql/cte_inline.sql | 6 - src/test/regress/sql/detect_conn_close.sql | 7 - .../sql/grant_on_schema_propagation.sql | 5 - .../regress/sql/insert_select_repartition.sql | 6 - .../sql/intermediate_result_pruning.sql | 6 - src/test/regress/sql/issue_5248.sql | 13 - .../regress/sql/local_shard_execution.sql | 6 - .../sql/local_shard_execution_replicated.sql | 6 - src/test/regress/sql/merge.sql | 8 - src/test/regress/sql/merge_arbitrary.sql | 8 - .../regress/sql/merge_arbitrary_create.sql | 8 - .../regress/sql/merge_partition_tables.sql | 9 - src/test/regress/sql/merge_repartition1.sql | 8 - src/test/regress/sql/merge_repartition2.sql | 9 - .../regress/sql/merge_schema_sharding.sql | 8 - src/test/regress/sql/merge_vcore.sql | 8 - ...ter_table_add_constraints_without_name.sql | 6 - .../regress/sql/multi_deparse_shard_query.sql | 6 - src/test/regress/sql/multi_extension.sql | 8 +- src/test/regress/sql/multi_insert_select.sql | 7 +- .../sql/multi_insert_select_conflict.sql | 6 - src/test/regress/sql/multi_metadata_sync.sql | 5 - .../multi_mx_insert_select_repartition.sql | 6 - .../sql/mx_coordinator_shouldhaveshards.sql | 6 - src/test/regress/sql/pg15.sql | 7 - src/test/regress/sql/pg15_jsonpath.sql | 8 - src/test/regress/sql/pgmerge.sql | 8 - src/test/regress/sql/publication.sql | 13 - src/test/regress/sql/single_node.sql | 6 - 144 files changed, 63 insertions(+), 27604 deletions(-) delete mode 100644 src/backend/distributed/deparser/ruleutils_14.c delete mode 100644 src/test/regress/expected/citus_local_tables_queries_0.out delete mode 100644 src/test/regress/expected/columnar_pg15_0.out delete mode 100644 src/test/regress/expected/coordinator_shouldhaveshards_0.out delete mode 100644 src/test/regress/expected/cte_inline_0.out delete mode 100644 src/test/regress/expected/detect_conn_close_0.out delete mode 100644 src/test/regress/expected/grant_on_schema_propagation_0.out delete mode 100644 src/test/regress/expected/insert_select_repartition_0.out delete mode 100644 src/test/regress/expected/intermediate_result_pruning_0.out delete mode 100644 src/test/regress/expected/issue_5248_0.out delete mode 100644 src/test/regress/expected/local_shard_execution_0.out delete mode 100644 src/test/regress/expected/local_shard_execution_replicated_0.out delete mode 100644 src/test/regress/expected/merge_0.out delete mode 100644 src/test/regress/expected/merge_arbitrary_0.out delete mode 100644 src/test/regress/expected/merge_arbitrary_create_0.out delete mode 100644 src/test/regress/expected/merge_partition_tables_0.out delete mode 100644 src/test/regress/expected/merge_repartition1_0.out delete mode 100644 src/test/regress/expected/merge_repartition2_0.out delete mode 100644 src/test/regress/expected/merge_schema_sharding_0.out delete mode 100644 src/test/regress/expected/merge_vcore_0.out delete mode 100644 src/test/regress/expected/multi_deparse_shard_query_0.out delete mode 100644 src/test/regress/expected/multi_insert_select_0.out delete mode 100644 src/test/regress/expected/multi_insert_select_conflict_0.out delete mode 100644 src/test/regress/expected/mx_coordinator_shouldhaveshards_0.out delete mode 100644 src/test/regress/expected/pg15_0.out delete mode 100644 src/test/regress/expected/pg15_jsonpath_0.out delete mode 100644 src/test/regress/expected/pgmerge_0.out create mode 100644 src/test/regress/expected/upgrade_citus_finish_citus_upgrade_1.out diff --git a/.gitattributes b/.gitattributes index c7c03e1ef..51520c243 100644 --- a/.gitattributes +++ b/.gitattributes @@ -25,8 +25,6 @@ configure -whitespace # except these exceptions... src/backend/distributed/utils/citus_outfuncs.c -citus-style -src/backend/distributed/deparser/ruleutils_13.c -citus-style -src/backend/distributed/deparser/ruleutils_14.c -citus-style src/backend/distributed/deparser/ruleutils_15.c -citus-style src/backend/distributed/deparser/ruleutils_16.c -citus-style src/backend/distributed/deparser/ruleutils_17.c -citus-style diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 075de0ce5..bf6c41eaf 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -33,7 +33,7 @@ jobs: style_checker_tools_version: "0.8.18" sql_snapshot_pg_version: "17.2" image_suffix: "-v889e4c1" - pg14_version: '{ "major": "14", "full": "14.15" }' + image_suffix_citus_upgrade: "-dev-2ad1f90" pg15_version: '{ "major": "15", "full": "15.10" }' pg16_version: '{ "major": "16", "full": "16.6" }' pg17_version: '{ "major": "17", "full": "17.2" }' @@ -111,7 +111,6 @@ jobs: image_suffix: - ${{ needs.params.outputs.image_suffix}} pg_version: - - ${{ needs.params.outputs.pg14_version }} - ${{ needs.params.outputs.pg15_version }} - ${{ needs.params.outputs.pg16_version }} - ${{ needs.params.outputs.pg17_version }} @@ -143,7 +142,6 @@ jobs: image_name: - ${{ needs.params.outputs.test_image_name }} pg_version: - - ${{ needs.params.outputs.pg14_version }} - ${{ needs.params.outputs.pg15_version }} - ${{ needs.params.outputs.pg16_version }} - ${{ needs.params.outputs.pg17_version }} @@ -164,10 +162,6 @@ jobs: - check-enterprise-isolation-logicalrep-2 - check-enterprise-isolation-logicalrep-3 include: - - make: check-failure - pg_version: ${{ needs.params.outputs.pg14_version }} - suite: regress - image_name: ${{ needs.params.outputs.fail_test_image_name }} - make: check-failure pg_version: ${{ needs.params.outputs.pg15_version }} suite: regress @@ -180,10 +174,6 @@ jobs: pg_version: ${{ needs.params.outputs.pg17_version }} suite: regress image_name: ${{ needs.params.outputs.fail_test_image_name }} - - make: check-enterprise-failure - pg_version: ${{ needs.params.outputs.pg14_version }} - suite: regress - image_name: ${{ needs.params.outputs.fail_test_image_name }} - make: check-enterprise-failure pg_version: ${{ needs.params.outputs.pg15_version }} suite: regress @@ -196,10 +186,6 @@ jobs: pg_version: ${{ needs.params.outputs.pg17_version }} suite: regress image_name: ${{ needs.params.outputs.fail_test_image_name }} - - make: check-pytest - pg_version: ${{ needs.params.outputs.pg14_version }} - suite: regress - image_name: ${{ needs.params.outputs.fail_test_image_name }} - make: check-pytest pg_version: ${{ needs.params.outputs.pg15_version }} suite: regress @@ -224,10 +210,6 @@ jobs: suite: cdc image_name: ${{ needs.params.outputs.test_image_name }} pg_version: ${{ needs.params.outputs.pg17_version }} - - make: check-query-generator - pg_version: ${{ needs.params.outputs.pg14_version }} - suite: regress - image_name: ${{ needs.params.outputs.fail_test_image_name }} - make: check-query-generator pg_version: ${{ needs.params.outputs.pg15_version }} suite: regress @@ -280,7 +262,6 @@ jobs: image_name: - ${{ needs.params.outputs.fail_test_image_name }} pg_version: - - ${{ needs.params.outputs.pg14_version }} - ${{ needs.params.outputs.pg15_version }} - ${{ needs.params.outputs.pg16_version }} - ${{ needs.params.outputs.pg17_version }} @@ -328,18 +309,12 @@ jobs: fail-fast: false matrix: include: - - old_pg_major: 14 - new_pg_major: 15 - old_pg_major: 15 new_pg_major: 16 - - old_pg_major: 14 - new_pg_major: 16 - old_pg_major: 16 new_pg_major: 17 - old_pg_major: 15 new_pg_major: 17 - - old_pg_major: 14 - new_pg_major: 17 env: old_pg_major: ${{ matrix.old_pg_major }} new_pg_major: ${{ matrix.new_pg_major }} @@ -375,10 +350,10 @@ jobs: flags: ${{ env.old_pg_major }}_${{ env.new_pg_major }}_upgrade codecov_token: ${{ secrets.CODECOV_TOKEN }} test-citus-upgrade: - name: PG${{ fromJson(needs.params.outputs.pg14_version).major }} - check-citus-upgrade + name: PG${{ fromJson(needs.params.outputs.pg15_version).major }} - check-citus-upgrade runs-on: ubuntu-20.04 container: - image: "${{ needs.params.outputs.citusupgrade_image_name }}:${{ fromJson(needs.params.outputs.pg14_version).full }}${{ needs.params.outputs.image_suffix }}" + image: "${{ needs.params.outputs.citusupgrade_image_name }}:${{ fromJson(needs.params.outputs.pg15_version).full }}${{ needs.params.outputs.image_suffix_citus_upgrade }}" options: --user root needs: - params diff --git a/configure b/configure index 5240df4db..d2f4060a7 100755 --- a/configure +++ b/configure @@ -2588,7 +2588,7 @@ fi if test "$with_pg_version_check" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: building against PostgreSQL $version_num (skipped compatibility check)" >&5 $as_echo "$as_me: building against PostgreSQL $version_num (skipped compatibility check)" >&6;} -elif test "$version_num" != '14' -a "$version_num" != '15' -a "$version_num" != '16' -a "$version_num" != '17'; then +elif test "$version_num" != '15' -a "$version_num" != '16' -a "$version_num" != '17'; then as_fn_error $? "Citus is not compatible with the detected PostgreSQL version ${version_num}." "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: building against PostgreSQL $version_num" >&5 diff --git a/configure.ac b/configure.ac index c7fde02de..0d79adce1 100644 --- a/configure.ac +++ b/configure.ac @@ -80,7 +80,7 @@ AC_SUBST(with_pg_version_check) if test "$with_pg_version_check" = no; then AC_MSG_NOTICE([building against PostgreSQL $version_num (skipped compatibility check)]) -elif test "$version_num" != '14' -a "$version_num" != '15' -a "$version_num" != '16' -a "$version_num" != '17'; then +elif test "$version_num" != '15' -a "$version_num" != '16' -a "$version_num" != '17'; then AC_MSG_ERROR([Citus is not compatible with the detected PostgreSQL version ${version_num}.]) else AC_MSG_NOTICE([building against PostgreSQL $version_num]) diff --git a/src/backend/columnar/columnar_customscan.c b/src/backend/columnar/columnar_customscan.c index 5288b8096..c836e84ce 100644 --- a/src/backend/columnar/columnar_customscan.c +++ b/src/backend/columnar/columnar_customscan.c @@ -1312,11 +1312,8 @@ AddColumnarScanPath(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte, cpath->methods = &ColumnarScanPathMethods; -#if (PG_VERSION_NUM >= PG_VERSION_15) - /* necessary to avoid extra Result node in PG15 */ cpath->flags = CUSTOMPATH_SUPPORT_PROJECTION; -#endif /* * populate generic path information diff --git a/src/backend/columnar/columnar_metadata.c b/src/backend/columnar/columnar_metadata.c index 192c4cc4b..a11138d0d 100644 --- a/src/backend/columnar/columnar_metadata.c +++ b/src/backend/columnar/columnar_metadata.c @@ -1685,7 +1685,7 @@ DeleteTupleAndEnforceConstraints(ModifyState *state, HeapTuple heapTuple) simple_heap_delete(state->rel, tid); /* execute AFTER ROW DELETE Triggers to enforce constraints */ - ExecARDeleteTriggers_compat(estate, resultRelInfo, tid, NULL, NULL, false); + ExecARDeleteTriggers(estate, resultRelInfo, tid, NULL, NULL, false); } diff --git a/src/backend/columnar/columnar_tableam.c b/src/backend/columnar/columnar_tableam.c index 83df11c42..4b777364e 100644 --- a/src/backend/columnar/columnar_tableam.c +++ b/src/backend/columnar/columnar_tableam.c @@ -877,7 +877,7 @@ columnar_relation_set_new_filelocator(Relation rel, *freezeXid = RecentXmin; *minmulti = GetOldestMultiXactId(); - SMgrRelation srel = RelationCreateStorage_compat(*newrlocator, persistence, true); + SMgrRelation srel = RelationCreateStorage(*newrlocator, persistence, true); ColumnarStorageInit(srel, ColumnarMetadataNewStorageId()); InitColumnarOptions(rel->rd_id); @@ -2245,7 +2245,6 @@ ColumnarProcessAlterTable(AlterTableStmt *alterTableStmt, List **columnarOptions columnarRangeVar = alterTableStmt->relation; } } -#if PG_VERSION_NUM >= PG_VERSION_15 else if (alterTableCmd->subtype == AT_SetAccessMethod) { if (columnarRangeVar || *columnarOptions) @@ -2265,7 +2264,6 @@ ColumnarProcessAlterTable(AlterTableStmt *alterTableStmt, List **columnarOptions DeleteColumnarTableOptions(RelationGetRelid(rel), true); } } -#endif /* PG_VERSION_15 */ } relation_close(rel, NoLock); @@ -2649,21 +2647,12 @@ ColumnarCheckLogicalReplication(Relation rel) return; } -#if PG_VERSION_NUM >= PG_VERSION_15 { PublicationDesc pubdesc; RelationBuildPublicationDesc(rel, &pubdesc); pubActionInsert = pubdesc.pubactions.pubinsert; } -#else - if (rel->rd_pubactions == NULL) - { - GetRelationPublicationActions(rel); - Assert(rel->rd_pubactions != NULL); - } - pubActionInsert = rel->rd_pubactions->pubinsert; -#endif if (pubActionInsert) { diff --git a/src/backend/distributed/clock/causal_clock.c b/src/backend/distributed/clock/causal_clock.c index be1ef11a2..ff05d03db 100644 --- a/src/backend/distributed/clock/causal_clock.c +++ b/src/backend/distributed/clock/causal_clock.c @@ -145,17 +145,6 @@ LogicalClockShmemSize(void) void InitializeClusterClockMem(void) { - /* On PG 15 and above, we use shmem_request_hook_type */ - #if PG_VERSION_NUM < PG_VERSION_15 - - /* allocate shared memory for pre PG-15 versions */ - if (!IsUnderPostmaster) - { - RequestAddinShmemSpace(LogicalClockShmemSize()); - } - - #endif - prev_shmem_startup_hook = shmem_startup_hook; shmem_startup_hook = LogicalClockShmemInit; } diff --git a/src/backend/distributed/commands/collation.c b/src/backend/distributed/commands/collation.c index 4a47b5c18..268694034 100644 --- a/src/backend/distributed/commands/collation.c +++ b/src/backend/distributed/commands/collation.c @@ -68,8 +68,6 @@ CreateCollationDDLInternal(Oid collationId, Oid *collowner, char **quotedCollati char *collcollate; char *collctype; -#if PG_VERSION_NUM >= PG_VERSION_15 - /* * In PG15, there is an added option to use ICU as global locale provider. * pg_collation has three locale-related fields: collcollate and collctype, @@ -112,16 +110,6 @@ CreateCollationDDLInternal(Oid collationId, Oid *collowner, char **quotedCollati } Assert((collcollate && collctype) || colllocale); -#else - - /* - * In versions before 15, collcollate and collctype were type "name". Use - * pstrdup() to match the interface of 15 so that we consistently free the - * result later. - */ - collcollate = pstrdup(NameStr(collationForm->collcollate)); - collctype = pstrdup(NameStr(collationForm->collctype)); -#endif if (collowner != NULL) { @@ -147,7 +135,6 @@ CreateCollationDDLInternal(Oid collationId, Oid *collowner, char **quotedCollati "CREATE COLLATION %s (provider = '%s'", *quotedCollationName, providerString); -#if PG_VERSION_NUM >= PG_VERSION_15 if (colllocale) { appendStringInfo(&collationNameDef, @@ -173,24 +160,7 @@ CreateCollationDDLInternal(Oid collationId, Oid *collowner, char **quotedCollati pfree(collcollate); pfree(collctype); } -#else - if (strcmp(collcollate, collctype) == 0) - { - appendStringInfo(&collationNameDef, - ", locale = %s", - quote_literal_cstr(collcollate)); - } - else - { - appendStringInfo(&collationNameDef, - ", lc_collate = %s, lc_ctype = %s", - quote_literal_cstr(collcollate), - quote_literal_cstr(collctype)); - } - pfree(collcollate); - pfree(collctype); -#endif #if PG_VERSION_NUM >= PG_VERSION_16 char *collicurules = NULL; datum = SysCacheGetAttr(COLLOID, heapTuple, Anum_pg_collation_collicurules, &isnull); diff --git a/src/backend/distributed/commands/create_distributed_table.c b/src/backend/distributed/commands/create_distributed_table.c index 7af6f2dd0..536f80291 100644 --- a/src/backend/distributed/commands/create_distributed_table.c +++ b/src/backend/distributed/commands/create_distributed_table.c @@ -170,12 +170,10 @@ static void EnsureDistributedSequencesHaveOneType(Oid relationId, static void CopyLocalDataIntoShards(Oid distributedTableId); static List * TupleDescColumnNameList(TupleDesc tupleDescriptor); -#if (PG_VERSION_NUM >= PG_VERSION_15) static bool DistributionColumnUsesNumericColumnNegativeScale(TupleDesc relationDesc, Var *distributionColumn); static int numeric_typmod_scale(int32 typmod); static bool is_valid_numeric_typmod(int32 typmod); -#endif static bool DistributionColumnUsesGeneratedStoredColumn(TupleDesc relationDesc, Var *distributionColumn); @@ -2114,8 +2112,6 @@ EnsureRelationCanBeDistributed(Oid relationId, Var *distributionColumn, "AS (...) STORED."))); } -#if (PG_VERSION_NUM >= PG_VERSION_15) - /* verify target relation is not distributed by a column of type numeric with negative scale */ if (distributionMethod != DISTRIBUTE_BY_NONE && DistributionColumnUsesNumericColumnNegativeScale(relationDesc, @@ -2126,7 +2122,6 @@ EnsureRelationCanBeDistributed(Oid relationId, Var *distributionColumn, errdetail("Distribution column must not use numeric type " "with negative scale"))); } -#endif /* check for support function needed by specified partition method */ if (distributionMethod == DISTRIBUTE_BY_HASH) @@ -2844,8 +2839,6 @@ TupleDescColumnNameList(TupleDesc tupleDescriptor) } -#if (PG_VERSION_NUM >= PG_VERSION_15) - /* * is_valid_numeric_typmod checks if the typmod value is valid * @@ -2895,8 +2888,6 @@ DistributionColumnUsesNumericColumnNegativeScale(TupleDesc relationDesc, } -#endif - /* * DistributionColumnUsesGeneratedStoredColumn returns whether a given relation uses * GENERATED ALWAYS AS (...) STORED on distribution column diff --git a/src/backend/distributed/commands/database.c b/src/backend/distributed/commands/database.c index 5479a59ed..ebca43f21 100644 --- a/src/backend/distributed/commands/database.c +++ b/src/backend/distributed/commands/database.c @@ -79,11 +79,8 @@ typedef struct DatabaseCollationInfo { char *datcollate; char *datctype; - -#if PG_VERSION_NUM >= PG_VERSION_15 char *daticulocale; char *datcollversion; -#endif #if PG_VERSION_NUM >= PG_VERSION_16 char *daticurules; @@ -94,9 +91,7 @@ static char * GenerateCreateDatabaseStatementFromPgDatabase(Form_pg_database databaseForm); static DatabaseCollationInfo GetDatabaseCollation(Oid dbOid); static AlterOwnerStmt * RecreateAlterDatabaseOwnerStmt(Oid databaseOid); -#if PG_VERSION_NUM >= PG_VERSION_15 static char * GetLocaleProviderString(char datlocprovider); -#endif static char * GetTablespaceName(Oid tablespaceOid); static ObjectAddress * GetDatabaseAddressFromDatabaseName(char *databaseName, bool missingOk); @@ -320,8 +315,6 @@ PreprocessAlterDatabaseStmt(Node *node, const char *queryString, } -#if PG_VERSION_NUM >= PG_VERSION_15 - /* * PreprocessAlterDatabaseRefreshCollStmt is executed before the statement is applied to * the local postgres instance. @@ -359,9 +352,6 @@ PreprocessAlterDatabaseRefreshCollStmt(Node *node, const char *queryString, } -#endif - - /* * PreprocessAlterDatabaseRenameStmt is executed before the statement is applied to * the local postgres instance. @@ -849,8 +839,6 @@ GetDatabaseCollation(Oid dbOid) Datum ctypeDatum = heap_getattr(tup, Anum_pg_database_datctype, tupdesc, &isNull); info.datctype = TextDatumGetCString(ctypeDatum); -#if PG_VERSION_NUM >= PG_VERSION_15 - Datum icuLocaleDatum = heap_getattr(tup, Anum_pg_database_daticulocale, tupdesc, &isNull); if (!isNull) @@ -864,7 +852,6 @@ GetDatabaseCollation(Oid dbOid) { info.datcollversion = TextDatumGetCString(collverDatum); } -#endif #if PG_VERSION_NUM >= PG_VERSION_16 Datum icurulesDatum = heap_getattr(tup, Anum_pg_database_daticurules, tupdesc, @@ -882,8 +869,6 @@ GetDatabaseCollation(Oid dbOid) } -#if PG_VERSION_NUM >= PG_VERSION_15 - /* * GetLocaleProviderString gets the datlocprovider stored in pg_database * and returns the string representation of the datlocprovider @@ -912,9 +897,6 @@ GetLocaleProviderString(char datlocprovider) } -#endif - - /* * GenerateCreateDatabaseStatementFromPgDatabase gets the pg_database tuple and returns the * CREATE DATABASE statement that can be used to create given database. @@ -956,7 +938,6 @@ GenerateCreateDatabaseStatementFromPgDatabase(Form_pg_database databaseForm) appendStringInfo(&str, " ENCODING = %s", quote_literal_cstr(pg_encoding_to_char(databaseForm->encoding))); -#if PG_VERSION_NUM >= PG_VERSION_15 if (collInfo.datcollversion != NULL) { appendStringInfo(&str, " COLLATION_VERSION = %s", @@ -972,7 +953,6 @@ GenerateCreateDatabaseStatementFromPgDatabase(Form_pg_database databaseForm) appendStringInfo(&str, " LOCALE_PROVIDER = %s", quote_identifier(GetLocaleProviderString( databaseForm->datlocprovider))); -#endif #if PG_VERSION_NUM >= PG_VERSION_16 if (collInfo.daticurules != NULL) diff --git a/src/backend/distributed/commands/distribute_object_ops.c b/src/backend/distributed/commands/distribute_object_ops.c index 5a62dd2c8..0e8887905 100644 --- a/src/backend/distributed/commands/distribute_object_ops.c +++ b/src/backend/distributed/commands/distribute_object_ops.c @@ -521,7 +521,6 @@ static DistributeObjectOps Database_Drop = { .markDistributed = false, }; -#if PG_VERSION_NUM >= PG_VERSION_15 static DistributeObjectOps Database_RefreshColl = { .deparse = DeparseAlterDatabaseRefreshCollStmt, .qualify = NULL, @@ -532,7 +531,6 @@ static DistributeObjectOps Database_RefreshColl = { .address = NULL, .markDistributed = false, }; -#endif static DistributeObjectOps Database_Set = { .deparse = DeparseAlterDatabaseSetStmt, @@ -926,7 +924,6 @@ static DistributeObjectOps Sequence_AlterOwner = { .address = AlterSequenceOwnerStmtObjectAddress, .markDistributed = false, }; -#if (PG_VERSION_NUM >= PG_VERSION_15) static DistributeObjectOps Sequence_AlterPersistence = { .deparse = DeparseAlterSequencePersistenceStmt, .qualify = QualifyAlterSequencePersistenceStmt, @@ -936,7 +933,6 @@ static DistributeObjectOps Sequence_AlterPersistence = { .address = AlterSequencePersistenceStmtObjectAddress, .markDistributed = false, }; -#endif static DistributeObjectOps Sequence_Drop = { .deparse = DeparseDropSequenceStmt, .qualify = QualifyDropSequenceStmt, @@ -1393,7 +1389,7 @@ static DistributeObjectOps View_Rename = { static DistributeObjectOps Trigger_Rename = { .deparse = NULL, .qualify = NULL, - .preprocess = PreprocessAlterTriggerRenameStmt, + .preprocess = NULL, .operationType = DIST_OPS_ALTER, .postprocess = PostprocessAlterTriggerRenameStmt, .address = NULL, @@ -1425,14 +1421,11 @@ GetDistributeObjectOps(Node *node) return &Database_Drop; } -#if PG_VERSION_NUM >= PG_VERSION_15 case T_AlterDatabaseRefreshCollStmt: { return &Database_RefreshColl; } -#endif - case T_AlterDatabaseSetStmt: { return &Database_Set; @@ -1723,7 +1716,6 @@ GetDistributeObjectOps(Node *node) case OBJECT_SEQUENCE: { -#if (PG_VERSION_NUM >= PG_VERSION_15) ListCell *cmdCell = NULL; foreach(cmdCell, stmt->cmds) { @@ -1751,7 +1743,6 @@ GetDistributeObjectOps(Node *node) } } } -#endif /* * Prior to PG15, the only Alter Table statement diff --git a/src/backend/distributed/commands/foreign_constraint.c b/src/backend/distributed/commands/foreign_constraint.c index b7162b1a4..bc12ccb4d 100644 --- a/src/backend/distributed/commands/foreign_constraint.c +++ b/src/backend/distributed/commands/foreign_constraint.c @@ -467,7 +467,6 @@ ForeignKeyGetDefaultingAttrs(HeapTuple pgConstraintTuple) } List *onDeleteSetDefColumnList = NIL; -#if PG_VERSION_NUM >= PG_VERSION_15 Datum onDeleteSetDefColumnsDatum = SysCacheGetAttr(CONSTROID, pgConstraintTuple, Anum_pg_constraint_confdelsetcols, &isNull); @@ -482,7 +481,6 @@ ForeignKeyGetDefaultingAttrs(HeapTuple pgConstraintTuple) onDeleteSetDefColumnList = IntegerArrayTypeToList(DatumGetArrayTypeP(onDeleteSetDefColumnsDatum)); } -#endif if (list_length(onDeleteSetDefColumnList) == 0) { diff --git a/src/backend/distributed/commands/publication.c b/src/backend/distributed/commands/publication.c index 16dbc9171..03b9bdb77 100644 --- a/src/backend/distributed/commands/publication.c +++ b/src/backend/distributed/commands/publication.c @@ -33,11 +33,9 @@ static CreatePublicationStmt * BuildCreatePublicationStmt(Oid publicationId); -#if (PG_VERSION_NUM >= PG_VERSION_15) static PublicationObjSpec * BuildPublicationRelationObjSpec(Oid relationId, Oid publicationId, bool tableOnly); -#endif static void AppendPublishOptionList(StringInfo str, List *strings); static char * AlterPublicationOwnerCommand(Oid publicationId); static bool ShouldPropagateCreatePublication(CreatePublicationStmt *stmt); @@ -154,7 +152,6 @@ BuildCreatePublicationStmt(Oid publicationId) ReleaseSysCache(publicationTuple); -#if (PG_VERSION_NUM >= PG_VERSION_15) List *schemaIds = GetPublicationSchemas(publicationId); Oid schemaId = InvalidOid; @@ -170,7 +167,6 @@ BuildCreatePublicationStmt(Oid publicationId) createPubStmt->pubobjects = lappend(createPubStmt->pubobjects, publicationObject); } -#endif List *relationIds = GetPublicationRelations(publicationId, publicationForm->pubviaroot ? @@ -183,7 +179,6 @@ BuildCreatePublicationStmt(Oid publicationId) foreach_declared_oid(relationId, relationIds) { -#if (PG_VERSION_NUM >= PG_VERSION_15) bool tableOnly = false; /* since postgres 15, tables can have a column list and filter */ @@ -270,8 +265,6 @@ AppendPublishOptionList(StringInfo str, List *options) } -#if (PG_VERSION_NUM >= PG_VERSION_15) - /* * BuildPublicationRelationObjSpec returns a PublicationObjSpec that * can be included in a CREATE or ALTER PUBLICATION statement. @@ -351,9 +344,6 @@ BuildPublicationRelationObjSpec(Oid relationId, Oid publicationId, } -#endif - - /* * PreprocessAlterPublicationStmt handles ALTER PUBLICATION statements * in a way that is mostly similar to PreprocessAlterDistributedObjectStmt, @@ -452,7 +442,6 @@ GetAlterPublicationTableDDLCommand(Oid publicationId, Oid relationId, ReleaseSysCache(pubTuple); -#if (PG_VERSION_NUM >= PG_VERSION_15) bool tableOnly = !isAdd; /* since postgres 15, tables can have a column list and filter */ @@ -461,16 +450,6 @@ GetAlterPublicationTableDDLCommand(Oid publicationId, Oid relationId, alterPubStmt->pubobjects = lappend(alterPubStmt->pubobjects, publicationObject); alterPubStmt->action = isAdd ? AP_AddObjects : AP_DropObjects; -#else - - /* before postgres 15, only full tables are supported */ - char *schemaName = get_namespace_name(get_rel_namespace(relationId)); - char *tableName = get_rel_name(relationId); - RangeVar *rangeVar = makeRangeVar(schemaName, tableName, -1); - - alterPubStmt->tables = lappend(alterPubStmt->tables, rangeVar); - alterPubStmt->tableAction = isAdd ? DEFELEM_ADD : DEFELEM_DROP; -#endif /* we take the WHERE clause from the catalog where it is already transformed */ bool whereClauseNeedsTransform = false; diff --git a/src/backend/distributed/commands/role.c b/src/backend/distributed/commands/role.c index bfbf606a4..599598731 100644 --- a/src/backend/distributed/commands/role.c +++ b/src/backend/distributed/commands/role.c @@ -1072,13 +1072,8 @@ makeStringConst(char *str, int location) { A_Const *n = makeNode(A_Const); -#if PG_VERSION_NUM >= PG_VERSION_15 n->val.sval.type = T_String; n->val.sval.sval = str; -#else - n->val.type = T_String; - n->val.val.str = str; -#endif n->location = location; return (Node *) n; @@ -1098,13 +1093,8 @@ makeIntConst(int val, int location) { A_Const *n = makeNode(A_Const); -#if PG_VERSION_NUM >= PG_VERSION_15 n->val.ival.type = T_Integer; n->val.ival.ival = val; -#else - n->val.type = T_Integer; - n->val.val.ival = val; -#endif n->location = location; return (Node *) n; @@ -1121,13 +1111,8 @@ makeFloatConst(char *str, int location) { A_Const *n = makeNode(A_Const); -#if PG_VERSION_NUM >= PG_VERSION_15 n->val.fval.type = T_Float; n->val.fval.fval = str; -#else - n->val.type = T_Float; - n->val.val.str = str; -#endif n->location = location; return (Node *) n; diff --git a/src/backend/distributed/commands/sequence.c b/src/backend/distributed/commands/sequence.c index 4af4c4853..0dd544cc6 100644 --- a/src/backend/distributed/commands/sequence.c +++ b/src/backend/distributed/commands/sequence.c @@ -735,8 +735,6 @@ PostprocessAlterSequenceOwnerStmt(Node *node, const char *queryString) } -#if (PG_VERSION_NUM >= PG_VERSION_15) - /* * PreprocessAlterSequencePersistenceStmt is called for change of persistence * of sequences before the persistence is changed on the local instance. @@ -847,9 +845,6 @@ PreprocessSequenceAlterTableStmt(Node *node, const char *queryString, } -#endif - - /* * PreprocessGrantOnSequenceStmt is executed before the statement is applied to the local * postgres instance. diff --git a/src/backend/distributed/commands/table.c b/src/backend/distributed/commands/table.c index 67b731a25..eaa8b1031 100644 --- a/src/backend/distributed/commands/table.c +++ b/src/backend/distributed/commands/table.c @@ -1153,7 +1153,6 @@ PreprocessAlterTableStmt(Node *node, const char *alterTableCommand, { AlterTableStmt *stmtCopy = copyObject(alterTableStatement); stmtCopy->objtype = OBJECT_SEQUENCE; -#if (PG_VERSION_NUM >= PG_VERSION_15) /* * it must be ALTER TABLE .. OWNER TO .. @@ -1163,16 +1162,6 @@ PreprocessAlterTableStmt(Node *node, const char *alterTableCommand, */ return PreprocessSequenceAlterTableStmt((Node *) stmtCopy, alterTableCommand, processUtilityContext); -#else - - /* - * it must be ALTER TABLE .. OWNER TO .. command - * since this is the only ALTER command of a sequence that - * passes through an AlterTableStmt - */ - return PreprocessAlterSequenceOwnerStmt((Node *) stmtCopy, alterTableCommand, - processUtilityContext); -#endif } else if (relKind == RELKIND_VIEW) { @@ -3673,9 +3662,8 @@ ErrorIfUnsupportedAlterTableStmt(AlterTableStmt *alterTableStatement) "are currently unsupported."))); break; } - #endif -#if PG_VERSION_NUM >= PG_VERSION_15 + case AT_SetAccessMethod: { /* @@ -3695,7 +3683,6 @@ ErrorIfUnsupportedAlterTableStmt(AlterTableStmt *alterTableStatement) break; } -#endif case AT_SetNotNull: case AT_ReplicaIdentity: case AT_ChangeOwner: diff --git a/src/backend/distributed/commands/trigger.c b/src/backend/distributed/commands/trigger.c index 01ee72d31..5b4d93584 100644 --- a/src/backend/distributed/commands/trigger.c +++ b/src/backend/distributed/commands/trigger.c @@ -57,9 +57,6 @@ static void ExtractDropStmtTriggerAndRelationName(DropStmt *dropTriggerStmt, static void ErrorIfDropStmtDropsMultipleTriggers(DropStmt *dropTriggerStmt); static char * GetTriggerNameById(Oid triggerId); static int16 GetTriggerTypeById(Oid triggerId); -#if (PG_VERSION_NUM < PG_VERSION_15) -static void ErrorOutIfCloneTrigger(Oid tgrelid, const char *tgname); -#endif /* GUC that overrides trigger checks for distributed tables and reference tables */ @@ -404,40 +401,6 @@ CreateTriggerEventExtendNames(CreateTrigStmt *createTriggerStmt, char *schemaNam } -/* - * PreprocessAlterTriggerRenameStmt is called before a ALTER TRIGGER RENAME - * command has been executed by standard process utility. This function errors - * out if we are trying to rename a child trigger on a partition of a distributed - * table. In PG15, this is not allowed anyway. - */ -List * -PreprocessAlterTriggerRenameStmt(Node *node, const char *queryString, - ProcessUtilityContext processUtilityContext) -{ -#if (PG_VERSION_NUM < PG_VERSION_15) - RenameStmt *renameTriggerStmt = castNode(RenameStmt, node); - Assert(renameTriggerStmt->renameType == OBJECT_TRIGGER); - - RangeVar *relation = renameTriggerStmt->relation; - - bool missingOk = false; - Oid relationId = RangeVarGetRelid(relation, ALTER_TRIGGER_LOCK_MODE, missingOk); - - if (!IsCitusTable(relationId)) - { - return NIL; - } - - EnsureCoordinator(); - ErrorOutForTriggerIfNotSupported(relationId); - - ErrorOutIfCloneTrigger(relationId, renameTriggerStmt->subname); -#endif - - return NIL; -} - - /* * PostprocessAlterTriggerRenameStmt is called after a ALTER TRIGGER RENAME * command has been executed by standard process utility. This function errors @@ -759,64 +722,6 @@ ErrorIfRelationHasUnsupportedTrigger(Oid relationId) } -#if (PG_VERSION_NUM < PG_VERSION_15) - -/* - * ErrorOutIfCloneTrigger is a helper function to error - * out if we are trying to rename a child trigger on a - * partition of a distributed table. - * A lot of this code is borrowed from PG15 because - * renaming clone triggers isn't allowed in PG15 anymore. - */ -static void -ErrorOutIfCloneTrigger(Oid tgrelid, const char *tgname) -{ - HeapTuple tuple; - ScanKeyData key[2]; - - Relation tgrel = table_open(TriggerRelationId, RowExclusiveLock); - - /* - * Search for the trigger to modify. - */ - ScanKeyInit(&key[0], - Anum_pg_trigger_tgrelid, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(tgrelid)); - ScanKeyInit(&key[1], - Anum_pg_trigger_tgname, - BTEqualStrategyNumber, F_NAMEEQ, - CStringGetDatum(tgname)); - SysScanDesc tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true, - NULL, 2, key); - - if (HeapTupleIsValid(tuple = systable_getnext(tgscan))) - { - Form_pg_trigger trigform = (Form_pg_trigger) GETSTRUCT(tuple); - - /* - * If the trigger descends from a trigger on a parent partitioned - * table, reject the rename. - * Appended shard ids to find the trigger on the partition's shards - * are not correct. Hence we would fail to find the trigger on the - * partition's shard. - */ - if (OidIsValid(trigform->tgparentid)) - { - ereport(ERROR, ( - errmsg( - "cannot rename child triggers on distributed partitions"))); - } - } - - systable_endscan(tgscan); - table_close(tgrel, RowExclusiveLock); -} - - -#endif - - /* * GetDropTriggerStmtRelation takes a DropStmt for a trigger object and returns * RangeVar for the relation that owns the trigger. diff --git a/src/backend/distributed/connection/shared_connection_stats.c b/src/backend/distributed/connection/shared_connection_stats.c index 26598b465..027bb46a2 100644 --- a/src/backend/distributed/connection/shared_connection_stats.c +++ b/src/backend/distributed/connection/shared_connection_stats.c @@ -614,16 +614,6 @@ WaitForSharedConnection(void) void InitializeSharedConnectionStats(void) { -/* on PG 15, we use shmem_request_hook_type */ -#if PG_VERSION_NUM < PG_VERSION_15 - - /* allocate shared memory */ - if (!IsUnderPostmaster) - { - RequestAddinShmemSpace(SharedConnectionStatsShmemSize()); - } -#endif - prev_shmem_startup_hook = shmem_startup_hook; shmem_startup_hook = SharedConnectionStatsShmemInit; } diff --git a/src/backend/distributed/deparser/citus_ruleutils.c b/src/backend/distributed/deparser/citus_ruleutils.c index d138f8859..bdba2bf6e 100644 --- a/src/backend/distributed/deparser/citus_ruleutils.c +++ b/src/backend/distributed/deparser/citus_ruleutils.c @@ -258,10 +258,8 @@ pg_get_sequencedef_string(Oid sequenceRelationId) char *typeName = format_type_be(pgSequenceForm->seqtypid); char *sequenceDef = psprintf(CREATE_SEQUENCE_COMMAND, -#if (PG_VERSION_NUM >= PG_VERSION_15) get_rel_persistence(sequenceRelationId) == RELPERSISTENCE_UNLOGGED ? "UNLOGGED " : "", -#endif qualifiedSequenceName, typeName, pgSequenceForm->seqincrement, pgSequenceForm->seqmin, @@ -857,12 +855,10 @@ deparse_shard_index_statement(IndexStmt *origStmt, Oid distrelid, int64 shardid, appendStringInfoString(buffer, ") "); } -#if PG_VERSION_NUM >= PG_VERSION_15 if (indexStmt->nulls_not_distinct) { appendStringInfoString(buffer, "NULLS NOT DISTINCT "); } -#endif /* PG_VERSION_15 */ if (indexStmt->options != NIL) { diff --git a/src/backend/distributed/deparser/deparse_database_stmts.c b/src/backend/distributed/deparser/deparse_database_stmts.c index 66df5361e..eac1945de 100644 --- a/src/backend/distributed/deparser/deparse_database_stmts.c +++ b/src/backend/distributed/deparser/deparse_database_stmts.c @@ -211,7 +211,6 @@ DeparseAlterDatabaseStmt(Node *node) } -#if PG_VERSION_NUM >= PG_VERSION_15 char * DeparseAlterDatabaseRefreshCollStmt(Node *node) { diff --git a/src/backend/distributed/deparser/deparse_publication_stmts.c b/src/backend/distributed/deparser/deparse_publication_stmts.c index 35068266e..37346eb5e 100644 --- a/src/backend/distributed/deparser/deparse_publication_stmts.c +++ b/src/backend/distributed/deparser/deparse_publication_stmts.c @@ -32,7 +32,6 @@ static void AppendCreatePublicationStmt(StringInfo buf, CreatePublicationStmt *stmt, bool whereClauseNeedsTransform, bool includeLocalTables); -#if (PG_VERSION_NUM >= PG_VERSION_15) static bool AppendPublicationObjects(StringInfo buf, List *publicationObjects, bool whereClauseNeedsTransform, bool includeLocalTables); @@ -40,10 +39,6 @@ static void AppendWhereClauseExpression(StringInfo buf, RangeVar *tableName, Node *whereClause, bool whereClauseNeedsTransform); static void AppendAlterPublicationAction(StringInfo buf, AlterPublicationAction action); -#else -static bool AppendTables(StringInfo buf, List *tables, bool includeLocalTables); -static void AppendDefElemAction(StringInfo buf, DefElemAction action); -#endif static bool AppendAlterPublicationStmt(StringInfo buf, AlterPublicationStmt *stmt, bool whereClauseNeedsTransform, bool includeLocalTables); @@ -108,7 +103,6 @@ AppendCreatePublicationStmt(StringInfo buf, CreatePublicationStmt *stmt, { appendStringInfoString(buf, " FOR ALL TABLES"); } -#if (PG_VERSION_NUM >= PG_VERSION_15) else if (stmt->pubobjects != NIL) { bool hasObjects = false; @@ -146,32 +140,6 @@ AppendCreatePublicationStmt(StringInfo buf, CreatePublicationStmt *stmt, includeLocalTables); } } -#else - else if (stmt->tables != NIL) - { - bool hasTables = false; - RangeVar *rangeVar = NULL; - - /* - * Check whether there are tables to propagate, mainly to know whether - * we should include "FOR". - */ - foreach_declared_ptr(rangeVar, stmt->tables) - { - if (includeLocalTables || IsCitusTableRangeVar(rangeVar, NoLock, false)) - { - hasTables = true; - break; - } - } - - if (hasTables) - { - appendStringInfoString(buf, " FOR"); - AppendTables(buf, stmt->tables, includeLocalTables); - } - } -#endif if (stmt->options != NIL) { @@ -182,8 +150,6 @@ AppendCreatePublicationStmt(StringInfo buf, CreatePublicationStmt *stmt, } -#if (PG_VERSION_NUM >= PG_VERSION_15) - /* * AppendPublicationObjects appends a string representing a list of publication * objects to a buffer. @@ -320,57 +286,6 @@ AppendWhereClauseExpression(StringInfo buf, RangeVar *tableName, } -#else - -/* - * AppendPublicationObjects appends a string representing a list of publication - * objects to a buffer. - * - * For instance: TABLE users, departments - */ -static bool -AppendTables(StringInfo buf, List *tables, bool includeLocalTables) -{ - RangeVar *rangeVar = NULL; - bool appendedObject = false; - - foreach_declared_ptr(rangeVar, tables) - { - if (!includeLocalTables && - !IsCitusTableRangeVar(rangeVar, NoLock, false)) - { - /* do not propagate local tables */ - continue; - } - - char *schemaName = rangeVar->schemaname; - char *tableName = rangeVar->relname; - - if (schemaName != NULL) - { - /* qualified table name */ - appendStringInfo(buf, "%s %s", - appendedObject ? "," : " TABLE", - quote_qualified_identifier(schemaName, tableName)); - } - else - { - /* unqualified table name */ - appendStringInfo(buf, "%s %s", - appendedObject ? "," : " TABLE", - quote_identifier(tableName)); - } - - appendedObject = true; - } - - return appendedObject; -} - - -#endif - - /* * DeparseAlterPublicationSchemaStmt builds and returns a string representing * an AlterPublicationStmt. @@ -439,19 +354,12 @@ AppendAlterPublicationStmt(StringInfo buf, AlterPublicationStmt *stmt, return true; } -#if (PG_VERSION_NUM >= PG_VERSION_15) AppendAlterPublicationAction(buf, stmt->action); return AppendPublicationObjects(buf, stmt->pubobjects, whereClauseNeedsTransform, includeLocalTables); -#else - AppendDefElemAction(buf, stmt->tableAction); - return AppendTables(buf, stmt->tables, includeLocalTables); -#endif } -#if (PG_VERSION_NUM >= PG_VERSION_15) - /* * AppendAlterPublicationAction appends a string representing an AlterPublicationAction * to a buffer. @@ -487,46 +395,6 @@ AppendAlterPublicationAction(StringInfo buf, AlterPublicationAction action) } -#else - -/* - * AppendDefElemAction appends a string representing a DefElemAction - * to a buffer. - */ -static void -AppendDefElemAction(StringInfo buf, DefElemAction action) -{ - switch (action) - { - case DEFELEM_ADD: - { - appendStringInfoString(buf, " ADD"); - break; - } - - case DEFELEM_DROP: - { - appendStringInfoString(buf, " DROP"); - break; - } - - case DEFELEM_SET: - { - appendStringInfoString(buf, " SET"); - break; - } - - default: - { - ereport(ERROR, (errmsg("unrecognized publication action: %d", action))); - } - } -} - - -#endif - - /* * DeparseDropPublicationStmt builds and returns a string representing the DropStmt */ @@ -651,11 +519,7 @@ AppendPublicationOptions(StringInfo stringBuffer, List *optionList) appendStringInfo(stringBuffer, "%s = ", quote_identifier(optionName)); -#if (PG_VERSION_NUM >= PG_VERSION_15) if (valueType == T_Integer || valueType == T_Float || valueType == T_Boolean) -#else - if (valueType == T_Integer || valueType == T_Float) -#endif { /* string escaping is unnecessary for numeric types and can cause issues */ appendStringInfo(stringBuffer, "%s", optionValue); diff --git a/src/backend/distributed/deparser/deparse_sequence_stmts.c b/src/backend/distributed/deparser/deparse_sequence_stmts.c index 9e5fab2c8..b16751d7f 100644 --- a/src/backend/distributed/deparser/deparse_sequence_stmts.c +++ b/src/backend/distributed/deparser/deparse_sequence_stmts.c @@ -28,9 +28,7 @@ static void AppendSequenceNameList(StringInfo buf, List *objects, ObjectType obj static void AppendRenameSequenceStmt(StringInfo buf, RenameStmt *stmt); static void AppendAlterSequenceSchemaStmt(StringInfo buf, AlterObjectSchemaStmt *stmt); static void AppendAlterSequenceOwnerStmt(StringInfo buf, AlterTableStmt *stmt); -#if (PG_VERSION_NUM >= PG_VERSION_15) static void AppendAlterSequencePersistenceStmt(StringInfo buf, AlterTableStmt *stmt); -#endif static void AppendGrantOnSequenceStmt(StringInfo buf, GrantStmt *stmt); static void AppendGrantOnSequenceSequences(StringInfo buf, GrantStmt *stmt); @@ -262,8 +260,6 @@ AppendAlterSequenceOwnerStmt(StringInfo buf, AlterTableStmt *stmt) } -#if (PG_VERSION_NUM >= PG_VERSION_15) - /* * DeparseAlterSequencePersistenceStmt builds and returns a string representing * the AlterTableStmt consisting of changing the persistence of a sequence @@ -349,9 +345,6 @@ AppendAlterSequencePersistenceStmt(StringInfo buf, AlterTableStmt *stmt) } -#endif - - /* * DeparseGrantOnSequenceStmt builds and returns a string representing the GrantOnSequenceStmt */ diff --git a/src/backend/distributed/deparser/deparse_table_stmts.c b/src/backend/distributed/deparser/deparse_table_stmts.c index 5d184fa66..d58fbabcc 100644 --- a/src/backend/distributed/deparser/deparse_table_stmts.c +++ b/src/backend/distributed/deparser/deparse_table_stmts.c @@ -193,12 +193,10 @@ AppendAlterTableCmdConstraint(StringInfo buf, Constraint *constraint, { appendStringInfoString(buf, " UNIQUE"); -#if (PG_VERSION_NUM >= PG_VERSION_15) if (constraint->nulls_not_distinct == true) { appendStringInfoString(buf, " NULLS NOT DISTINCT"); } -#endif } if (subtype == AT_AddConstraint) diff --git a/src/backend/distributed/deparser/qualify_publication_stmt.c b/src/backend/distributed/deparser/qualify_publication_stmt.c index c47f52e15..0790dc06b 100644 --- a/src/backend/distributed/deparser/qualify_publication_stmt.c +++ b/src/backend/distributed/deparser/qualify_publication_stmt.c @@ -19,11 +19,7 @@ #include "distributed/deparser.h" #include "distributed/listutils.h" -#if (PG_VERSION_NUM >= PG_VERSION_15) static void QualifyPublicationObjects(List *publicationObjects); -#else -static void QualifyTables(List *tables); -#endif static void QualifyPublicationRangeVar(RangeVar *publication); @@ -36,16 +32,10 @@ QualifyCreatePublicationStmt(Node *node) { CreatePublicationStmt *stmt = castNode(CreatePublicationStmt, node); -#if (PG_VERSION_NUM >= PG_VERSION_15) QualifyPublicationObjects(stmt->pubobjects); -#else - QualifyTables(stmt->tables); -#endif } -#if (PG_VERSION_NUM >= PG_VERSION_15) - /* * QualifyPublicationObjects ensures all table names in a list of * publication objects are fully qualified. @@ -68,26 +58,6 @@ QualifyPublicationObjects(List *publicationObjects) } -#else - -/* - * QualifyTables ensures all table names in a list are fully qualified. - */ -static void -QualifyTables(List *tables) -{ - RangeVar *rangeVar = NULL; - - foreach_declared_ptr(rangeVar, tables) - { - QualifyPublicationRangeVar(rangeVar); - } -} - - -#endif - - /* * QualifyPublicationObjects ensures all table names in a list of * publication objects are fully qualified. @@ -97,11 +67,7 @@ QualifyAlterPublicationStmt(Node *node) { AlterPublicationStmt *stmt = castNode(AlterPublicationStmt, node); -#if (PG_VERSION_NUM >= PG_VERSION_15) QualifyPublicationObjects(stmt->pubobjects); -#else - QualifyTables(stmt->tables); -#endif } diff --git a/src/backend/distributed/deparser/qualify_sequence_stmt.c b/src/backend/distributed/deparser/qualify_sequence_stmt.c index c56d0fda0..402a661ce 100644 --- a/src/backend/distributed/deparser/qualify_sequence_stmt.c +++ b/src/backend/distributed/deparser/qualify_sequence_stmt.c @@ -52,8 +52,6 @@ QualifyAlterSequenceOwnerStmt(Node *node) } -#if (PG_VERSION_NUM >= PG_VERSION_15) - /* * QualifyAlterSequencePersistenceStmt transforms a * ALTER SEQUENCE .. SET LOGGED/UNLOGGED @@ -80,9 +78,6 @@ QualifyAlterSequencePersistenceStmt(Node *node) } -#endif - - /* * QualifyAlterSequenceSchemaStmt transforms a * ALTER SEQUENCE .. SET SCHEMA .. diff --git a/src/backend/distributed/deparser/ruleutils_14.c b/src/backend/distributed/deparser/ruleutils_14.c deleted file mode 100644 index 88948cff5..000000000 --- a/src/backend/distributed/deparser/ruleutils_14.c +++ /dev/null @@ -1,8638 +0,0 @@ -/*------------------------------------------------------------------------- - * - * ruleutils_14.c - * Functions to convert stored expressions/querytrees back to - * source text - * - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * src/backend/distributed/deparser/ruleutils_14.c - * - * This needs to be closely in sync with the core code. - *------------------------------------------------------------------------- - */ -#include "pg_version_constants.h" - -#include "pg_config.h" - -#if (PG_VERSION_NUM >= PG_VERSION_14) && (PG_VERSION_NUM < PG_VERSION_15) - -#include "postgres.h" - -#include -#include -#include - -#include "access/amapi.h" -#include "access/htup_details.h" -#include "access/relation.h" -#include "access/sysattr.h" -#include "access/table.h" -#include "catalog/pg_aggregate.h" -#include "catalog/pg_am.h" -#include "catalog/pg_authid.h" -#include "catalog/pg_collation.h" -#include "catalog/pg_constraint.h" -#include "catalog/pg_depend.h" -#include "catalog/pg_extension.h" -#include "catalog/pg_foreign_data_wrapper.h" -#include "catalog/pg_language.h" -#include "catalog/pg_opclass.h" -#include "catalog/pg_operator.h" -#include "catalog/pg_partitioned_table.h" -#include "catalog/pg_proc.h" -#include "catalog/pg_statistic_ext.h" -#include "catalog/pg_trigger.h" -#include "catalog/pg_type.h" -#include "commands/defrem.h" -#include "commands/extension.h" -#include "commands/tablespace.h" -#include "common/keywords.h" -#include "distributed/citus_nodefuncs.h" -#include "distributed/citus_ruleutils.h" -#include "distributed/namespace_utils.h" -#include "executor/spi.h" -#include "foreign/foreign.h" -#include "funcapi.h" -#include "mb/pg_wchar.h" -#include "miscadmin.h" -#include "nodes/makefuncs.h" -#include "nodes/nodeFuncs.h" -#include "nodes/pathnodes.h" -#include "optimizer/optimizer.h" -#include "parser/parse_node.h" -#include "parser/parse_agg.h" -#include "parser/parse_func.h" -#include "parser/parse_node.h" -#include "parser/parse_oper.h" -#include "parser/parser.h" -#include "parser/parsetree.h" -#include "rewrite/rewriteHandler.h" -#include "rewrite/rewriteManip.h" -#include "rewrite/rewriteSupport.h" -#include "utils/array.h" -#include "utils/builtins.h" -#include "utils/fmgroids.h" -#include "utils/hsearch.h" -#include "utils/lsyscache.h" -#include "utils/rel.h" -#include "utils/ruleutils.h" -#include "utils/snapmgr.h" -#include "utils/syscache.h" -#include "utils/typcache.h" -#include "utils/varlena.h" -#include "utils/xml.h" - - -/* ---------- - * Pretty formatting constants - * ---------- - */ - -/* Indent counts */ -#define PRETTYINDENT_STD 8 -#define PRETTYINDENT_JOIN 4 -#define PRETTYINDENT_VAR 4 - -#define PRETTYINDENT_LIMIT 40 /* wrap limit */ - -/* Pretty flags */ -#define PRETTYFLAG_PAREN 0x0001 -#define PRETTYFLAG_INDENT 0x0002 - -/* Default line length for pretty-print wrapping: 0 means wrap always */ -#define WRAP_COLUMN_DEFAULT 0 - -/* macros to test if pretty action needed */ -#define PRETTY_PAREN(context) ((context)->prettyFlags & PRETTYFLAG_PAREN) -#define PRETTY_INDENT(context) ((context)->prettyFlags & PRETTYFLAG_INDENT) - - -/* ---------- - * Local data types - * ---------- - */ - -/* Context info needed for invoking a recursive querytree display routine */ -typedef struct -{ - StringInfo buf; /* output buffer to append to */ - List *namespaces; /* List of deparse_namespace nodes */ - List *windowClause; /* Current query level's WINDOW clause */ - List *windowTList; /* targetlist for resolving WINDOW clause */ - int prettyFlags; /* enabling of pretty-print functions */ - int wrapColumn; /* max line length, or -1 for no limit */ - int indentLevel; /* current indent level for prettyprint */ - bool varprefix; /* true to print prefixes on Vars */ - Oid distrelid; /* the distributed table being modified, if valid */ - int64 shardid; /* a distributed table's shardid, if positive */ - ParseExprKind special_exprkind; /* set only for exprkinds needing special - * handling */ - Bitmapset *appendparents; /* if not null, map child Vars of these relids - * back to the parent rel */ -} deparse_context; - -/* - * Each level of query context around a subtree needs a level of Var namespace. - * A Var having varlevelsup=N refers to the N'th item (counting from 0) in - * the current context's namespaces list. - * - * The rangetable is the list of actual RTEs from the query tree, and the - * cte list is the list of actual CTEs. - * - * rtable_names holds the alias name to be used for each RTE (either a C - * string, or NULL for nameless RTEs such as unnamed joins). - * rtable_columns holds the column alias names to be used for each RTE. - * - * In some cases we need to make names of merged JOIN USING columns unique - * across the whole query, not only per-RTE. If so, unique_using is true - * and using_names is a list of C strings representing names already assigned - * to USING columns. - * - * When deparsing plan trees, there is always just a single item in the - * deparse_namespace list (since a plan tree never contains Vars with - * varlevelsup > 0). We store the PlanState node that is the immediate - * parent of the expression to be deparsed, as well as a list of that - * PlanState's ancestors. In addition, we store its outer and inner subplan - * state nodes, as well as their plan nodes' targetlists, and the index tlist - * if the current plan node might contain INDEX_VAR Vars. (These fields could - * be derived on-the-fly from the current PlanState, but it seems notationally - * clearer to set them up as separate fields.) - */ -typedef struct -{ - List *rtable; /* List of RangeTblEntry nodes */ - List *rtable_names; /* Parallel list of names for RTEs */ - List *rtable_columns; /* Parallel list of deparse_columns structs */ - List *subplans; /* List of Plan trees for SubPlans */ - List *ctes; /* List of CommonTableExpr nodes */ - AppendRelInfo **appendrels; /* Array of AppendRelInfo nodes, or NULL */ - /* Workspace for column alias assignment: */ - bool unique_using; /* Are we making USING names globally unique */ - List *using_names; /* List of assigned names for USING columns */ - /* Remaining fields are used only when deparsing a Plan tree: */ - Plan *plan; /* immediate parent of current expression */ - List *ancestors; /* ancestors of planstate */ - Plan *outer_plan; /* outer subnode, or NULL if none */ - Plan *inner_plan; /* inner subnode, or NULL if none */ - List *outer_tlist; /* referent for OUTER_VAR Vars */ - List *inner_tlist; /* referent for INNER_VAR Vars */ - List *index_tlist; /* referent for INDEX_VAR Vars */ - /* Special namespace representing a function signature: */ - char *funcname; - int numargs; - char **argnames; -} deparse_namespace; - -/* Callback signature for resolve_special_varno() */ -typedef void (*rsv_callback) (Node *node, deparse_context *context, - void *callback_arg); - -/* - * Per-relation data about column alias names. - * - * Selecting aliases is unreasonably complicated because of the need to dump - * rules/views whose underlying tables may have had columns added, deleted, or - * renamed since the query was parsed. We must nonetheless print the rule/view - * in a form that can be reloaded and will produce the same results as before. - * - * For each RTE used in the query, we must assign column aliases that are - * unique within that RTE. SQL does not require this of the original query, - * but due to factors such as *-expansion we need to be able to uniquely - * reference every column in a decompiled query. As long as we qualify all - * column references, per-RTE uniqueness is sufficient for that. - * - * However, we can't ensure per-column name uniqueness for unnamed join RTEs, - * since they just inherit column names from their input RTEs, and we can't - * rename the columns at the join level. Most of the time this isn't an issue - * because we don't need to reference the join's output columns as such; we - * can reference the input columns instead. That approach can fail for merged - * JOIN USING columns, however, so when we have one of those in an unnamed - * join, we have to make that column's alias globally unique across the whole - * query to ensure it can be referenced unambiguously. - * - * Another problem is that a JOIN USING clause requires the columns to be - * merged to have the same aliases in both input RTEs, and that no other - * columns in those RTEs or their children conflict with the USING names. - * To handle that, we do USING-column alias assignment in a recursive - * traversal of the query's jointree. When descending through a JOIN with - * USING, we preassign the USING column names to the child columns, overriding - * other rules for column alias assignment. We also mark each RTE with a list - * of all USING column names selected for joins containing that RTE, so that - * when we assign other columns' aliases later, we can avoid conflicts. - * - * Another problem is that if a JOIN's input tables have had columns added or - * deleted since the query was parsed, we must generate a column alias list - * for the join that matches the current set of input columns --- otherwise, a - * change in the number of columns in the left input would throw off matching - * of aliases to columns of the right input. Thus, positions in the printable - * column alias list are not necessarily one-for-one with varattnos of the - * JOIN, so we need a separate new_colnames[] array for printing purposes. - */ -typedef struct -{ - /* - * colnames is an array containing column aliases to use for columns that - * existed when the query was parsed. Dropped columns have NULL entries. - * This array can be directly indexed by varattno to get a Var's name. - * - * Non-NULL entries are guaranteed unique within the RTE, *except* when - * this is for an unnamed JOIN RTE. In that case we merely copy up names - * from the two input RTEs. - * - * During the recursive descent in set_using_names(), forcible assignment - * of a child RTE's column name is represented by pre-setting that element - * of the child's colnames array. So at that stage, NULL entries in this - * array just mean that no name has been preassigned, not necessarily that - * the column is dropped. - */ - int num_cols; /* length of colnames[] array */ - char **colnames; /* array of C strings and NULLs */ - - /* - * new_colnames is an array containing column aliases to use for columns - * that would exist if the query was re-parsed against the current - * definitions of its base tables. This is what to print as the column - * alias list for the RTE. This array does not include dropped columns, - * but it will include columns added since original parsing. Indexes in - * it therefore have little to do with current varattno values. As above, - * entries are unique unless this is for an unnamed JOIN RTE. (In such an - * RTE, we never actually print this array, but we must compute it anyway - * for possible use in computing column names of upper joins.) The - * parallel array is_new_col marks which of these columns are new since - * original parsing. Entries with is_new_col false must match the - * non-NULL colnames entries one-for-one. - */ - int num_new_cols; /* length of new_colnames[] array */ - char **new_colnames; /* array of C strings */ - bool *is_new_col; /* array of bool flags */ - - /* This flag tells whether we should actually print a column alias list */ - bool printaliases; - - /* This list has all names used as USING names in joins above this RTE */ - List *parentUsing; /* names assigned to parent merged columns */ - - /* - * If this struct is for a JOIN RTE, we fill these fields during the - * set_using_names() pass to describe its relationship to its child RTEs. - * - * leftattnos and rightattnos are arrays with one entry per existing - * output column of the join (hence, indexable by join varattno). For a - * simple reference to a column of the left child, leftattnos[i] is the - * child RTE's attno and rightattnos[i] is zero; and conversely for a - * column of the right child. But for merged columns produced by JOIN - * USING/NATURAL JOIN, both leftattnos[i] and rightattnos[i] are nonzero. - * Also, if the column has been dropped, both are zero. - * - * If it's a JOIN USING, usingNames holds the alias names selected for the - * merged columns (these might be different from the original USING list, - * if we had to modify names to achieve uniqueness). - */ - int leftrti; /* rangetable index of left child */ - int rightrti; /* rangetable index of right child */ - int *leftattnos; /* left-child varattnos of join cols, or 0 */ - int *rightattnos; /* right-child varattnos of join cols, or 0 */ - List *usingNames; /* names assigned to merged columns */ -} deparse_columns; - -/* This macro is analogous to rt_fetch(), but for deparse_columns structs */ -#define deparse_columns_fetch(rangetable_index, dpns) \ - ((deparse_columns *) list_nth((dpns)->rtable_columns, (rangetable_index)-1)) - -/* - * Entry in set_rtable_names' hash table - */ -typedef struct -{ - char name[NAMEDATALEN]; /* Hash key --- must be first */ - int counter; /* Largest addition used so far for name */ -} NameHashEntry; - - -/* ---------- - * Local functions - * - * Most of these functions used to use fixed-size buffers to build their - * results. Now, they take an (already initialized) StringInfo object - * as a parameter, and append their text output to its contents. - * ---------- - */ -static void set_rtable_names(deparse_namespace *dpns, List *parent_namespaces, - Bitmapset *rels_used); -static void set_deparse_for_query(deparse_namespace *dpns, Query *query, - List *parent_namespaces); -static bool has_dangerous_join_using(deparse_namespace *dpns, Node *jtnode); -static void set_using_names(deparse_namespace *dpns, Node *jtnode, - List *parentUsing); -static void set_relation_column_names(deparse_namespace *dpns, - RangeTblEntry *rte, - deparse_columns *colinfo); -static void set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte, - deparse_columns *colinfo); -static bool colname_is_unique(const char *colname, deparse_namespace *dpns, - deparse_columns *colinfo); -static char *make_colname_unique(char *colname, deparse_namespace *dpns, - deparse_columns *colinfo); -static void expand_colnames_array_to(deparse_columns *colinfo, int n); -static void identify_join_columns(JoinExpr *j, RangeTblEntry *jrte, - deparse_columns *colinfo); -static char *get_rtable_name(int rtindex, deparse_context *context); -static void set_deparse_plan(deparse_namespace *dpns, Plan *plan); -static void push_child_plan(deparse_namespace *dpns, Plan *plan, - deparse_namespace *save_dpns); -static void pop_child_plan(deparse_namespace *dpns, - deparse_namespace *save_dpns); -static void push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell, - deparse_namespace *save_dpns); -static void pop_ancestor_plan(deparse_namespace *dpns, - deparse_namespace *save_dpns); -static void get_query_def(Query *query, StringInfo buf, List *parentnamespace, - TupleDesc resultDesc, - int prettyFlags, int wrapColumn, int startIndent); -static void get_query_def_extended(Query *query, StringInfo buf, - List *parentnamespace, Oid distrelid, int64 shardid, - TupleDesc resultDesc, int prettyFlags, int wrapColumn, - int startIndent); -static void get_values_def(List *values_lists, deparse_context *context); -static void get_with_clause(Query *query, deparse_context *context); -static void get_select_query_def(Query *query, deparse_context *context, - TupleDesc resultDesc); -static void get_insert_query_def(Query *query, deparse_context *context); -static void get_update_query_def(Query *query, deparse_context *context); -static void get_update_query_targetlist_def(Query *query, List *targetList, - deparse_context *context, - RangeTblEntry *rte); -static void get_delete_query_def(Query *query, deparse_context *context); -static void get_utility_query_def(Query *query, deparse_context *context); -static void get_basic_select_query(Query *query, deparse_context *context, - TupleDesc resultDesc); -static void get_target_list(List *targetList, deparse_context *context, - TupleDesc resultDesc); -static void get_setop_query(Node *setOp, Query *query, - deparse_context *context, - TupleDesc resultDesc); -static Node *get_rule_sortgroupclause(Index ref, List *tlist, - bool force_colno, - deparse_context *context); -static void get_rule_groupingset(GroupingSet *gset, List *targetlist, - bool omit_parens, deparse_context *context); -static void get_rule_orderby(List *orderList, List *targetList, - bool force_colno, deparse_context *context); -static void get_rule_windowclause(Query *query, deparse_context *context); -static void get_rule_windowspec(WindowClause *wc, List *targetList, - deparse_context *context); -static char *get_variable(Var *var, int levelsup, bool istoplevel, - deparse_context *context); -static void get_special_variable(Node *node, deparse_context *context, - void *callback_arg); -static void resolve_special_varno(Node *node, deparse_context *context, - rsv_callback callback, void *callback_arg); -static Node *find_param_referent(Param *param, deparse_context *context, - deparse_namespace **dpns_p, ListCell **ancestor_cell_p); -static void get_parameter(Param *param, deparse_context *context); -static const char *get_simple_binary_op_name(OpExpr *expr); -static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags); -static void appendContextKeyword(deparse_context *context, const char *str, - int indentBefore, int indentAfter, int indentPlus); -static void removeStringInfoSpaces(StringInfo str); -static void get_rule_expr(Node *node, deparse_context *context, - bool showimplicit); -static void get_rule_expr_toplevel(Node *node, deparse_context *context, - bool showimplicit); -static void get_rule_expr_funccall(Node *node, deparse_context *context, - bool showimplicit); -static bool looks_like_function(Node *node); -static void get_oper_expr(OpExpr *expr, deparse_context *context); -static void get_func_expr(FuncExpr *expr, deparse_context *context, - bool showimplicit); -static void get_proc_expr(CallStmt *stmt, deparse_context *context, - bool showimplicit); -static void get_agg_expr(Aggref *aggref, deparse_context *context, - Aggref *original_aggref); -static void get_agg_combine_expr(Node *node, deparse_context *context, - void *callback_arg); -static void get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context); -static bool get_func_sql_syntax(FuncExpr *expr, deparse_context *context); -static void get_coercion_expr(Node *arg, deparse_context *context, - Oid resulttype, int32 resulttypmod, - Node *parentNode); -static void get_const_expr(Const *constval, deparse_context *context, - int showtype); -static void get_const_collation(Const *constval, deparse_context *context); -static void simple_quote_literal(StringInfo buf, const char *val); -static void get_sublink_expr(SubLink *sublink, deparse_context *context); -static void get_tablefunc(TableFunc *tf, deparse_context *context, - bool showimplicit); -static void get_from_clause(Query *query, const char *prefix, - deparse_context *context); -static void get_from_clause_item(Node *jtnode, Query *query, - deparse_context *context); -static void get_column_alias_list(deparse_columns *colinfo, - deparse_context *context); -static void get_from_clause_coldeflist(RangeTblFunction *rtfunc, - deparse_columns *colinfo, - deparse_context *context); -static void get_tablesample_def(TableSampleClause *tablesample, - deparse_context *context); -static void get_opclass_name(Oid opclass, Oid actual_datatype, - StringInfo buf); -static Node *processIndirection(Node *node, deparse_context *context); -static void printSubscripts(SubscriptingRef *aref, deparse_context *context); -static char *get_relation_name(Oid relid); -static char *generate_relation_or_shard_name(Oid relid, Oid distrelid, - int64 shardid, List *namespaces); -static char *generate_rte_shard_name(RangeTblEntry *rangeTableEntry); -static char *generate_fragment_name(char *schemaName, char *tableName); -static char *generate_function_name(Oid funcid, int nargs, - List *argnames, Oid *argtypes, - bool has_variadic, bool *use_variadic_p, - ParseExprKind special_exprkind); - -#define only_marker(rte) ((rte)->inh ? "" : "ONLY ") - - - -/* - * pg_get_query_def parses back one query tree, and outputs the resulting query - * string into given buffer. - */ -void -pg_get_query_def(Query *query, StringInfo buffer) -{ - get_query_def(query, buffer, NIL, NULL, 0, WRAP_COLUMN_DEFAULT, 0); -} - -/* - * get_merged_argument_list merges both the IN and OUT arguments lists into one and - * also eliminates the INOUT duplicates(present in both the lists). After merging both - * the lists, it returns all the named-arguments in a list(mergedNamedArgList) along - * with their types(mergedNamedArgTypes), final argument list(mergedArgumentList), and - * the total number of arguments(totalArguments). - */ -bool -get_merged_argument_list(CallStmt *stmt, List **mergedNamedArgList, - Oid **mergedNamedArgTypes, - List **mergedArgumentList, - int *totalArguments) -{ - - Oid functionOid = stmt->funcexpr->funcid; - List *namedArgList = NIL; - List *finalArgumentList = NIL; - Oid *finalArgTypes; - Oid *argTypes = NULL; - char *argModes = NULL; - char **argNames = NULL; - int argIndex = 0; - - HeapTuple proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(functionOid)); - if (!HeapTupleIsValid(proctup)) - { - elog(ERROR, "cache lookup failed for function %u", functionOid); - } - - int defArgs = get_func_arg_info(proctup, &argTypes, &argNames, &argModes); - ReleaseSysCache(proctup); - - if (argModes == NULL) - { - /* No OUT arguments */ - return false; - } - - /* - * Passed arguments Includes IN, OUT, INOUT (in both the lists) and VARIADIC arguments, - * which means INOUT arguments are double counted. - */ - int numberOfArgs = list_length(stmt->funcexpr->args) + list_length(stmt->outargs); - int totalInoutArgs = 0; - - /* Let's count INOUT arguments from the defined number of arguments */ - for (argIndex=0; argIndex < defArgs; ++argIndex) - { - if (argModes[argIndex] == PROARGMODE_INOUT) - totalInoutArgs++; - } - - /* Remove the duplicate INOUT counting */ - numberOfArgs = numberOfArgs - totalInoutArgs; - finalArgTypes = palloc0(sizeof(Oid) * numberOfArgs); - - ListCell *inArgCell = list_head(stmt->funcexpr->args); - ListCell *outArgCell = list_head(stmt->outargs); - - for (argIndex=0; argIndex < numberOfArgs; ++argIndex) - { - switch (argModes[argIndex]) - { - case PROARGMODE_IN: - case PROARGMODE_VARIADIC: - { - Node *arg = (Node *) lfirst(inArgCell); - - if (IsA(arg, NamedArgExpr)) - namedArgList = lappend(namedArgList, ((NamedArgExpr *) arg)->name); - finalArgTypes[argIndex] = exprType(arg); - finalArgumentList = lappend(finalArgumentList, arg); - inArgCell = lnext(stmt->funcexpr->args, inArgCell); - break; - } - - case PROARGMODE_OUT: - { - Node *arg = (Node *) lfirst(outArgCell); - - if (IsA(arg, NamedArgExpr)) - namedArgList = lappend(namedArgList, ((NamedArgExpr *) arg)->name); - finalArgTypes[argIndex] = exprType(arg); - finalArgumentList = lappend(finalArgumentList, arg); - outArgCell = lnext(stmt->outargs, outArgCell); - break; - } - - case PROARGMODE_INOUT: - { - Node *arg = (Node *) lfirst(inArgCell); - - if (IsA(arg, NamedArgExpr)) - namedArgList = lappend(namedArgList, ((NamedArgExpr *) arg)->name); - finalArgTypes[argIndex] = exprType(arg); - finalArgumentList = lappend(finalArgumentList, arg); - inArgCell = lnext(stmt->funcexpr->args, inArgCell); - outArgCell = lnext(stmt->outargs, outArgCell); - break; - } - - case PROARGMODE_TABLE: - default: - { - elog(ERROR, "Unhandled procedure argument mode[%d]", argModes[argIndex]); - break; - } - } - } - - /* - * After eliminating INOUT duplicates and merging OUT arguments, we now - * have the final list of arguments. - */ - if (defArgs != list_length(finalArgumentList)) - { - elog(ERROR, "Insufficient number of args passed[%d] for function[%s]", - list_length(finalArgumentList), - get_func_name(functionOid)); - } - - if (list_length(finalArgumentList) > FUNC_MAX_ARGS) - { - ereport(ERROR, - (errcode(ERRCODE_TOO_MANY_ARGUMENTS), - errmsg("too many arguments[%d] for function[%s]", - list_length(finalArgumentList), - get_func_name(functionOid)))); - } - - *mergedNamedArgList = namedArgList; - *mergedNamedArgTypes = finalArgTypes; - *mergedArgumentList = finalArgumentList; - *totalArguments = numberOfArgs; - - return true; -} -/* - * pg_get_rule_expr deparses an expression and returns the result as a string. - */ -char * -pg_get_rule_expr(Node *expression) -{ - bool showImplicitCasts = true; - deparse_context context; - StringInfo buffer = makeStringInfo(); - - /* - * Set search_path to NIL so that all objects outside of pg_catalog will be - * schema-prefixed. pg_catalog will be added automatically when we call - * PushEmptySearchPath(). - */ - int saveNestLevel = PushEmptySearchPath(); - - context.buf = buffer; - context.namespaces = NIL; - context.windowClause = NIL; - context.windowTList = NIL; - context.varprefix = false; - context.prettyFlags = 0; - context.wrapColumn = WRAP_COLUMN_DEFAULT; - context.indentLevel = 0; - context.special_exprkind = EXPR_KIND_NONE; - context.distrelid = InvalidOid; - context.shardid = INVALID_SHARD_ID; - - get_rule_expr(expression, &context, showImplicitCasts); - - /* revert back to original search_path */ - PopEmptySearchPath(saveNestLevel); - - return buffer->data; -} - - -/* - * set_rtable_names: select RTE aliases to be used in printing a query - * - * We fill in dpns->rtable_names with a list of names that is one-for-one with - * the already-filled dpns->rtable list. Each RTE name is unique among those - * in the new namespace plus any ancestor namespaces listed in - * parent_namespaces. - * - * If rels_used isn't NULL, only RTE indexes listed in it are given aliases. - * - * Note that this function is only concerned with relation names, not column - * names. - */ -static void -set_rtable_names(deparse_namespace *dpns, List *parent_namespaces, - Bitmapset *rels_used) -{ - HASHCTL hash_ctl; - HTAB *names_hash; - NameHashEntry *hentry; - bool found; - int rtindex; - ListCell *lc; - - dpns->rtable_names = NIL; - /* nothing more to do if empty rtable */ - if (dpns->rtable == NIL) - return; - - /* - * We use a hash table to hold known names, so that this process is O(N) - * not O(N^2) for N names. - */ - hash_ctl.keysize = NAMEDATALEN; - hash_ctl.entrysize = sizeof(NameHashEntry); - hash_ctl.hcxt = CurrentMemoryContext; - names_hash = hash_create("set_rtable_names names", - list_length(dpns->rtable), - &hash_ctl, - HASH_ELEM | HASH_STRINGS | HASH_CONTEXT); - - /* Preload the hash table with names appearing in parent_namespaces */ - foreach(lc, parent_namespaces) - { - deparse_namespace *olddpns = (deparse_namespace *) lfirst(lc); - ListCell *lc2; - - foreach(lc2, olddpns->rtable_names) - { - char *oldname = (char *) lfirst(lc2); - - if (oldname == NULL) - continue; - hentry = (NameHashEntry *) hash_search(names_hash, - oldname, - HASH_ENTER, - &found); - /* we do not complain about duplicate names in parent namespaces */ - hentry->counter = 0; - } - } - - /* Now we can scan the rtable */ - rtindex = 1; - foreach(lc, dpns->rtable) - { - RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc); - char *refname; - - /* Just in case this takes an unreasonable amount of time ... */ - CHECK_FOR_INTERRUPTS(); - - if (rels_used && !bms_is_member(rtindex, rels_used)) - { - /* Ignore unreferenced RTE */ - refname = NULL; - } - else if (rte->alias) - { - /* If RTE has a user-defined alias, prefer that */ - refname = rte->alias->aliasname; - } - else if (rte->rtekind == RTE_RELATION) - { - /* Use the current actual name of the relation */ - refname = get_rel_name(rte->relid); - } - else if (rte->rtekind == RTE_JOIN) - { - /* Unnamed join has no refname */ - refname = NULL; - } - else - { - /* Otherwise use whatever the parser assigned */ - refname = rte->eref->aliasname; - } - - /* - * If the selected name isn't unique, append digits to make it so, and - * make a new hash entry for it once we've got a unique name. For a - * very long input name, we might have to truncate to stay within - * NAMEDATALEN. - */ - if (refname) - { - hentry = (NameHashEntry *) hash_search(names_hash, - refname, - HASH_ENTER, - &found); - if (found) - { - /* Name already in use, must choose a new one */ - int refnamelen = strlen(refname); - char *modname = (char *) palloc(refnamelen + 16); - NameHashEntry *hentry2; - - do - { - hentry->counter++; - for (;;) - { - memcpy(modname, refname, refnamelen); - sprintf(modname + refnamelen, "_%d", hentry->counter); - if (strlen(modname) < NAMEDATALEN) - break; - /* drop chars from refname to keep all the digits */ - refnamelen = pg_mbcliplen(refname, refnamelen, - refnamelen - 1); - } - hentry2 = (NameHashEntry *) hash_search(names_hash, - modname, - HASH_ENTER, - &found); - } while (found); - hentry2->counter = 0; /* init new hash entry */ - refname = modname; - } - else - { - /* Name not previously used, need only initialize hentry */ - hentry->counter = 0; - } - } - - dpns->rtable_names = lappend(dpns->rtable_names, refname); - rtindex++; - } - - hash_destroy(names_hash); -} - -/* - * set_deparse_for_query: set up deparse_namespace for deparsing a Query tree - * - * For convenience, this is defined to initialize the deparse_namespace struct - * from scratch. - */ -static void -set_deparse_for_query(deparse_namespace *dpns, Query *query, - List *parent_namespaces) -{ - ListCell *lc; - ListCell *lc2; - - /* Initialize *dpns and fill rtable/ctes links */ - memset(dpns, 0, sizeof(deparse_namespace)); - dpns->rtable = query->rtable; - dpns->subplans = NIL; - dpns->ctes = query->cteList; - dpns->appendrels = NULL; - - /* Assign a unique relation alias to each RTE */ - set_rtable_names(dpns, parent_namespaces, NULL); - - /* Initialize dpns->rtable_columns to contain zeroed structs */ - dpns->rtable_columns = NIL; - while (list_length(dpns->rtable_columns) < list_length(dpns->rtable)) - dpns->rtable_columns = lappend(dpns->rtable_columns, - palloc0(sizeof(deparse_columns))); - - /* If it's a utility query, it won't have a jointree */ - if (query->jointree) - { - /* Detect whether global uniqueness of USING names is needed */ - dpns->unique_using = - has_dangerous_join_using(dpns, (Node *) query->jointree); - - /* - * Select names for columns merged by USING, via a recursive pass over - * the query jointree. - */ - set_using_names(dpns, (Node *) query->jointree, NIL); - } - - /* - * Now assign remaining column aliases for each RTE. We do this in a - * linear scan of the rtable, so as to process RTEs whether or not they - * are in the jointree (we mustn't miss NEW.*, INSERT target relations, - * etc). JOIN RTEs must be processed after their children, but this is - * okay because they appear later in the rtable list than their children - * (cf Asserts in identify_join_columns()). - */ - forboth(lc, dpns->rtable, lc2, dpns->rtable_columns) - { - RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc); - deparse_columns *colinfo = (deparse_columns *) lfirst(lc2); - - if (rte->rtekind == RTE_JOIN) - set_join_column_names(dpns, rte, colinfo); - else - set_relation_column_names(dpns, rte, colinfo); - } -} - -/* - * has_dangerous_join_using: search jointree for unnamed JOIN USING - * - * Merged columns of a JOIN USING may act differently from either of the input - * columns, either because they are merged with COALESCE (in a FULL JOIN) or - * because an implicit coercion of the underlying input column is required. - * In such a case the column must be referenced as a column of the JOIN not as - * a column of either input. And this is problematic if the join is unnamed - * (alias-less): we cannot qualify the column's name with an RTE name, since - * there is none. (Forcibly assigning an alias to the join is not a solution, - * since that will prevent legal references to tables below the join.) - * To ensure that every column in the query is unambiguously referenceable, - * we must assign such merged columns names that are globally unique across - * the whole query, aliasing other columns out of the way as necessary. - * - * Because the ensuing re-aliasing is fairly damaging to the readability of - * the query, we don't do this unless we have to. So, we must pre-scan - * the join tree to see if we have to, before starting set_using_names(). - */ -static bool -has_dangerous_join_using(deparse_namespace *dpns, Node *jtnode) -{ - if (IsA(jtnode, RangeTblRef)) - { - /* nothing to do here */ - } - else if (IsA(jtnode, FromExpr)) - { - FromExpr *f = (FromExpr *) jtnode; - ListCell *lc; - - foreach(lc, f->fromlist) - { - if (has_dangerous_join_using(dpns, (Node *) lfirst(lc))) - return true; - } - } - else if (IsA(jtnode, JoinExpr)) - { - JoinExpr *j = (JoinExpr *) jtnode; - - /* Is it an unnamed JOIN with USING? */ - if (j->alias == NULL && j->usingClause) - { - /* - * Yes, so check each join alias var to see if any of them are not - * simple references to underlying columns. If so, we have a - * dangerous situation and must pick unique aliases. - */ - RangeTblEntry *jrte = rt_fetch(j->rtindex, dpns->rtable); - - /* We need only examine the merged columns */ - for (int i = 0; i < jrte->joinmergedcols; i++) - { - Node *aliasvar = list_nth(jrte->joinaliasvars, i); - - if (!IsA(aliasvar, Var)) - return true; - } - } - - /* Nope, but inspect children */ - if (has_dangerous_join_using(dpns, j->larg)) - return true; - if (has_dangerous_join_using(dpns, j->rarg)) - return true; - } - else - elog(ERROR, "unrecognized node type: %d", - (int) nodeTag(jtnode)); - return false; -} - -/* - * set_using_names: select column aliases to be used for merged USING columns - * - * We do this during a recursive descent of the query jointree. - * dpns->unique_using must already be set to determine the global strategy. - * - * Column alias info is saved in the dpns->rtable_columns list, which is - * assumed to be filled with pre-zeroed deparse_columns structs. - * - * parentUsing is a list of all USING aliases assigned in parent joins of - * the current jointree node. (The passed-in list must not be modified.) - */ -static void -set_using_names(deparse_namespace *dpns, Node *jtnode, List *parentUsing) -{ - if (IsA(jtnode, RangeTblRef)) - { - /* nothing to do now */ - } - else if (IsA(jtnode, FromExpr)) - { - FromExpr *f = (FromExpr *) jtnode; - ListCell *lc; - - foreach(lc, f->fromlist) - set_using_names(dpns, (Node *) lfirst(lc), parentUsing); - } - else if (IsA(jtnode, JoinExpr)) - { - JoinExpr *j = (JoinExpr *) jtnode; - RangeTblEntry *rte = rt_fetch(j->rtindex, dpns->rtable); - deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns); - int *leftattnos; - int *rightattnos; - deparse_columns *leftcolinfo; - deparse_columns *rightcolinfo; - int i; - ListCell *lc; - - /* Get info about the shape of the join */ - identify_join_columns(j, rte, colinfo); - leftattnos = colinfo->leftattnos; - rightattnos = colinfo->rightattnos; - - /* Look up the not-yet-filled-in child deparse_columns structs */ - leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns); - rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns); - - /* - * If this join is unnamed, then we cannot substitute new aliases at - * this level, so any name requirements pushed down to here must be - * pushed down again to the children. - */ - if (rte->alias == NULL) - { - for (i = 0; i < colinfo->num_cols; i++) - { - char *colname = colinfo->colnames[i]; - - if (colname == NULL) - continue; - - /* Push down to left column, unless it's a system column */ - if (leftattnos[i] > 0) - { - expand_colnames_array_to(leftcolinfo, leftattnos[i]); - leftcolinfo->colnames[leftattnos[i] - 1] = colname; - } - - /* Same on the righthand side */ - if (rightattnos[i] > 0) - { - expand_colnames_array_to(rightcolinfo, rightattnos[i]); - rightcolinfo->colnames[rightattnos[i] - 1] = colname; - } - } - } - - /* - * If there's a USING clause, select the USING column names and push - * those names down to the children. We have two strategies: - * - * If dpns->unique_using is true, we force all USING names to be - * unique across the whole query level. In principle we'd only need - * the names of dangerous USING columns to be globally unique, but to - * safely assign all USING names in a single pass, we have to enforce - * the same uniqueness rule for all of them. However, if a USING - * column's name has been pushed down from the parent, we should use - * it as-is rather than making a uniqueness adjustment. This is - * necessary when we're at an unnamed join, and it creates no risk of - * ambiguity. Also, if there's a user-written output alias for a - * merged column, we prefer to use that rather than the input name; - * this simplifies the logic and seems likely to lead to less aliasing - * overall. - * - * If dpns->unique_using is false, we only need USING names to be - * unique within their own join RTE. We still need to honor - * pushed-down names, though. - * - * Though significantly different in results, these two strategies are - * implemented by the same code, with only the difference of whether - * to put assigned names into dpns->using_names. - */ - if (j->usingClause) - { - /* Copy the input parentUsing list so we don't modify it */ - parentUsing = list_copy(parentUsing); - - /* USING names must correspond to the first join output columns */ - expand_colnames_array_to(colinfo, list_length(j->usingClause)); - i = 0; - foreach(lc, j->usingClause) - { - char *colname = strVal(lfirst(lc)); - - /* Assert it's a merged column */ - Assert(leftattnos[i] != 0 && rightattnos[i] != 0); - - /* Adopt passed-down name if any, else select unique name */ - if (colinfo->colnames[i] != NULL) - colname = colinfo->colnames[i]; - else - { - /* Prefer user-written output alias if any */ - if (rte->alias && i < list_length(rte->alias->colnames)) - colname = strVal(list_nth(rte->alias->colnames, i)); - /* Make it appropriately unique */ - colname = make_colname_unique(colname, dpns, colinfo); - if (dpns->unique_using) - dpns->using_names = lappend(dpns->using_names, - colname); - /* Save it as output column name, too */ - colinfo->colnames[i] = colname; - } - - /* Remember selected names for use later */ - colinfo->usingNames = lappend(colinfo->usingNames, colname); - parentUsing = lappend(parentUsing, colname); - - /* Push down to left column, unless it's a system column */ - if (leftattnos[i] > 0) - { - expand_colnames_array_to(leftcolinfo, leftattnos[i]); - leftcolinfo->colnames[leftattnos[i] - 1] = colname; - } - - /* Same on the righthand side */ - if (rightattnos[i] > 0) - { - expand_colnames_array_to(rightcolinfo, rightattnos[i]); - rightcolinfo->colnames[rightattnos[i] - 1] = colname; - } - - i++; - } - } - - /* Mark child deparse_columns structs with correct parentUsing info */ - leftcolinfo->parentUsing = parentUsing; - rightcolinfo->parentUsing = parentUsing; - - /* Now recursively assign USING column names in children */ - set_using_names(dpns, j->larg, parentUsing); - set_using_names(dpns, j->rarg, parentUsing); - } - else - elog(ERROR, "unrecognized node type: %d", - (int) nodeTag(jtnode)); -} - -/* - * set_relation_column_names: select column aliases for a non-join RTE - * - * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed. - * If any colnames entries are already filled in, those override local - * choices. - */ -static void -set_relation_column_names(deparse_namespace *dpns, RangeTblEntry *rte, - deparse_columns *colinfo) -{ - int ncolumns; - char **real_colnames; - bool changed_any; - bool has_anonymous; - int noldcolumns; - int i; - int j; - - /* - * Extract the RTE's "real" column names. This is comparable to - * get_rte_attribute_name, except that it's important to disregard dropped - * columns. We put NULL into the array for a dropped column. - */ - if (rte->rtekind == RTE_RELATION || - GetRangeTblKind(rte) == CITUS_RTE_SHARD) - { - /* Relation --- look to the system catalogs for up-to-date info */ - Relation rel; - TupleDesc tupdesc; - - rel = relation_open(rte->relid, AccessShareLock); - tupdesc = RelationGetDescr(rel); - - ncolumns = tupdesc->natts; - real_colnames = (char **) palloc(ncolumns * sizeof(char *)); - - for (i = 0; i < ncolumns; i++) - { - Form_pg_attribute attr = TupleDescAttr(tupdesc, i); - - if (attr->attisdropped) - real_colnames[i] = NULL; - else - real_colnames[i] = pstrdup(NameStr(attr->attname)); - } - relation_close(rel, AccessShareLock); - } - else - { - /* Otherwise use the column names from eref */ - ListCell *lc; - - ncolumns = list_length(rte->eref->colnames); - real_colnames = (char **) palloc(ncolumns * sizeof(char *)); - - i = 0; - foreach(lc, rte->eref->colnames) - { - /* - * If the column name shown in eref is an empty string, then it's - * a column that was dropped at the time of parsing the query, so - * treat it as dropped. - */ - char *cname = strVal(lfirst(lc)); - - if (cname[0] == '\0') - cname = NULL; - real_colnames[i] = cname; - i++; - } - } - - /* - * Ensure colinfo->colnames has a slot for each column. (It could be long - * enough already, if we pushed down a name for the last column.) Note: - * it's possible that there are now more columns than there were when the - * query was parsed, ie colnames could be longer than rte->eref->colnames. - * We must assign unique aliases to the new columns too, else there could - * be unresolved conflicts when the view/rule is reloaded. - */ - expand_colnames_array_to(colinfo, ncolumns); - Assert(colinfo->num_cols == ncolumns); - - /* - * Make sufficiently large new_colnames and is_new_col arrays, too. - * - * Note: because we leave colinfo->num_new_cols zero until after the loop, - * colname_is_unique will not consult that array, which is fine because it - * would only be duplicate effort. - */ - colinfo->new_colnames = (char **) palloc(ncolumns * sizeof(char *)); - colinfo->is_new_col = (bool *) palloc(ncolumns * sizeof(bool)); - - /* - * Scan the columns, select a unique alias for each one, and store it in - * colinfo->colnames and colinfo->new_colnames. The former array has NULL - * entries for dropped columns, the latter omits them. Also mark - * new_colnames entries as to whether they are new since parse time; this - * is the case for entries beyond the length of rte->eref->colnames. - */ - noldcolumns = list_length(rte->eref->colnames); - changed_any = false; - has_anonymous = false; - j = 0; - for (i = 0; i < ncolumns; i++) - { - char *real_colname = real_colnames[i]; - char *colname = colinfo->colnames[i]; - - /* Skip dropped columns */ - if (real_colname == NULL) - { - Assert(colname == NULL); /* colnames[i] is already NULL */ - continue; - } - - /* If alias already assigned, that's what to use */ - if (colname == NULL) - { - /* If user wrote an alias, prefer that over real column name */ - if (rte->alias && i < list_length(rte->alias->colnames)) - colname = strVal(list_nth(rte->alias->colnames, i)); - else - colname = real_colname; - - /* Unique-ify and insert into colinfo */ - colname = make_colname_unique(colname, dpns, colinfo); - - colinfo->colnames[i] = colname; - } - - /* Put names of non-dropped columns in new_colnames[] too */ - colinfo->new_colnames[j] = colname; - /* And mark them as new or not */ - colinfo->is_new_col[j] = (i >= noldcolumns); - j++; - - /* Remember if any assigned aliases differ from "real" name */ - if (!changed_any && strcmp(colname, real_colname) != 0) - changed_any = true; - - /* - * Remember if there is a reference to an anonymous column as named by - * char * FigureColname(Node *node) - */ - if (!has_anonymous && strcmp(real_colname, "?column?") == 0) - has_anonymous = true; - } - - /* - * Set correct length for new_colnames[] array. (Note: if columns have - * been added, colinfo->num_cols includes them, which is not really quite - * right but is harmless, since any new columns must be at the end where - * they won't affect varattnos of pre-existing columns.) - */ - colinfo->num_new_cols = j; - - /* - * For a relation RTE, we need only print the alias column names if any - * are different from the underlying "real" names. For a function RTE, - * always emit a complete column alias list; this is to protect against - * possible instability of the default column names (eg, from altering - * parameter names). For tablefunc RTEs, we never print aliases, because - * the column names are part of the clause itself. For other RTE types, - * print if we changed anything OR if there were user-written column - * aliases (since the latter would be part of the underlying "reality"). - */ - if (rte->rtekind == RTE_RELATION) - colinfo->printaliases = changed_any; - else if (rte->rtekind == RTE_FUNCTION) - colinfo->printaliases = true; - else if (rte->rtekind == RTE_TABLEFUNC) - colinfo->printaliases = false; - else if (rte->alias && rte->alias->colnames != NIL) - colinfo->printaliases = true; - else - colinfo->printaliases = changed_any || has_anonymous; -} - -/* - * set_join_column_names: select column aliases for a join RTE - * - * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed. - * If any colnames entries are already filled in, those override local - * choices. Also, names for USING columns were already chosen by - * set_using_names(). We further expect that column alias selection has been - * completed for both input RTEs. - */ -static void -set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte, - deparse_columns *colinfo) -{ - deparse_columns *leftcolinfo; - deparse_columns *rightcolinfo; - bool changed_any; - int noldcolumns; - int nnewcolumns; - Bitmapset *leftmerged = NULL; - Bitmapset *rightmerged = NULL; - int i; - int j; - int ic; - int jc; - - /* Look up the previously-filled-in child deparse_columns structs */ - leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns); - rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns); - - /* - * Ensure colinfo->colnames has a slot for each column. (It could be long - * enough already, if we pushed down a name for the last column.) Note: - * it's possible that one or both inputs now have more columns than there - * were when the query was parsed, but we'll deal with that below. We - * only need entries in colnames for pre-existing columns. - */ - noldcolumns = list_length(rte->eref->colnames); - expand_colnames_array_to(colinfo, noldcolumns); - Assert(colinfo->num_cols == noldcolumns); - - /* - * Scan the join output columns, select an alias for each one, and store - * it in colinfo->colnames. If there are USING columns, set_using_names() - * already selected their names, so we can start the loop at the first - * non-merged column. - */ - changed_any = false; - for (i = list_length(colinfo->usingNames); i < noldcolumns; i++) - { - char *colname = colinfo->colnames[i]; - char *real_colname; - - /* Join column must refer to at least one input column */ - Assert(colinfo->leftattnos[i] != 0 || colinfo->rightattnos[i] != 0); - - /* Get the child column name */ - if (colinfo->leftattnos[i] > 0) - real_colname = leftcolinfo->colnames[colinfo->leftattnos[i] - 1]; - else if (colinfo->rightattnos[i] > 0) - real_colname = rightcolinfo->colnames[colinfo->rightattnos[i] - 1]; - else - { - /* We're joining system columns --- use eref name */ - real_colname = strVal(list_nth(rte->eref->colnames, i)); - } - /* If child col has been dropped, no need to assign a join colname */ - if (real_colname == NULL) - { - colinfo->colnames[i] = NULL; - continue; - } - - /* In an unnamed join, just report child column names as-is */ - if (rte->alias == NULL) - { - colinfo->colnames[i] = real_colname; - continue; - } - - /* If alias already assigned, that's what to use */ - if (colname == NULL) - { - /* If user wrote an alias, prefer that over real column name */ - if (rte->alias && i < list_length(rte->alias->colnames)) - colname = strVal(list_nth(rte->alias->colnames, i)); - else - colname = real_colname; - - /* Unique-ify and insert into colinfo */ - colname = make_colname_unique(colname, dpns, colinfo); - - colinfo->colnames[i] = colname; - } - - /* Remember if any assigned aliases differ from "real" name */ - if (!changed_any && strcmp(colname, real_colname) != 0) - changed_any = true; - } - - /* - * Calculate number of columns the join would have if it were re-parsed - * now, and create storage for the new_colnames and is_new_col arrays. - * - * Note: colname_is_unique will be consulting new_colnames[] during the - * loops below, so its not-yet-filled entries must be zeroes. - */ - nnewcolumns = leftcolinfo->num_new_cols + rightcolinfo->num_new_cols - - list_length(colinfo->usingNames); - colinfo->num_new_cols = nnewcolumns; - colinfo->new_colnames = (char **) palloc0(nnewcolumns * sizeof(char *)); - colinfo->is_new_col = (bool *) palloc0(nnewcolumns * sizeof(bool)); - - /* - * Generating the new_colnames array is a bit tricky since any new columns - * added since parse time must be inserted in the right places. This code - * must match the parser, which will order a join's columns as merged - * columns first (in USING-clause order), then non-merged columns from the - * left input (in attnum order), then non-merged columns from the right - * input (ditto). If one of the inputs is itself a join, its columns will - * be ordered according to the same rule, which means newly-added columns - * might not be at the end. We can figure out what's what by consulting - * the leftattnos and rightattnos arrays plus the input is_new_col arrays. - * - * In these loops, i indexes leftattnos/rightattnos (so it's join varattno - * less one), j indexes new_colnames/is_new_col, and ic/jc have similar - * meanings for the current child RTE. - */ - - /* Handle merged columns; they are first and can't be new */ - i = j = 0; - while (i < noldcolumns && - colinfo->leftattnos[i] != 0 && - colinfo->rightattnos[i] != 0) - { - /* column name is already determined and known unique */ - colinfo->new_colnames[j] = colinfo->colnames[i]; - colinfo->is_new_col[j] = false; - - /* build bitmapsets of child attnums of merged columns */ - if (colinfo->leftattnos[i] > 0) - leftmerged = bms_add_member(leftmerged, colinfo->leftattnos[i]); - if (colinfo->rightattnos[i] > 0) - rightmerged = bms_add_member(rightmerged, colinfo->rightattnos[i]); - - i++, j++; - } - - /* Handle non-merged left-child columns */ - ic = 0; - for (jc = 0; jc < leftcolinfo->num_new_cols; jc++) - { - char *child_colname = leftcolinfo->new_colnames[jc]; - - if (!leftcolinfo->is_new_col[jc]) - { - /* Advance ic to next non-dropped old column of left child */ - while (ic < leftcolinfo->num_cols && - leftcolinfo->colnames[ic] == NULL) - ic++; - Assert(ic < leftcolinfo->num_cols); - ic++; - /* If it is a merged column, we already processed it */ - if (bms_is_member(ic, leftmerged)) - continue; - /* Else, advance i to the corresponding existing join column */ - while (i < colinfo->num_cols && - colinfo->colnames[i] == NULL) - i++; - Assert(i < colinfo->num_cols); - Assert(ic == colinfo->leftattnos[i]); - /* Use the already-assigned name of this column */ - colinfo->new_colnames[j] = colinfo->colnames[i]; - i++; - } - else - { - /* - * Unique-ify the new child column name and assign, unless we're - * in an unnamed join, in which case just copy - */ - if (rte->alias != NULL) - { - colinfo->new_colnames[j] = - make_colname_unique(child_colname, dpns, colinfo); - if (!changed_any && - strcmp(colinfo->new_colnames[j], child_colname) != 0) - changed_any = true; - } - else - colinfo->new_colnames[j] = child_colname; - } - - colinfo->is_new_col[j] = leftcolinfo->is_new_col[jc]; - j++; - } - - /* Handle non-merged right-child columns in exactly the same way */ - ic = 0; - for (jc = 0; jc < rightcolinfo->num_new_cols; jc++) - { - char *child_colname = rightcolinfo->new_colnames[jc]; - - if (!rightcolinfo->is_new_col[jc]) - { - /* Advance ic to next non-dropped old column of right child */ - while (ic < rightcolinfo->num_cols && - rightcolinfo->colnames[ic] == NULL) - ic++; - Assert(ic < rightcolinfo->num_cols); - ic++; - /* If it is a merged column, we already processed it */ - if (bms_is_member(ic, rightmerged)) - continue; - /* Else, advance i to the corresponding existing join column */ - while (i < colinfo->num_cols && - colinfo->colnames[i] == NULL) - i++; - Assert(i < colinfo->num_cols); - Assert(ic == colinfo->rightattnos[i]); - /* Use the already-assigned name of this column */ - colinfo->new_colnames[j] = colinfo->colnames[i]; - i++; - } - else - { - /* - * Unique-ify the new child column name and assign, unless we're - * in an unnamed join, in which case just copy - */ - if (rte->alias != NULL) - { - colinfo->new_colnames[j] = - make_colname_unique(child_colname, dpns, colinfo); - if (!changed_any && - strcmp(colinfo->new_colnames[j], child_colname) != 0) - changed_any = true; - } - else - colinfo->new_colnames[j] = child_colname; - } - - colinfo->is_new_col[j] = rightcolinfo->is_new_col[jc]; - j++; - } - - /* Assert we processed the right number of columns */ -#ifdef USE_ASSERT_CHECKING - for (int col_index = 0; col_index < colinfo->num_cols; col_index++) - { - /* - * In the above processing-loops, "i" advances only if - * the column is not new, check if this is a new column. - */ - if (colinfo->is_new_col[col_index]) - i++; - } - Assert(i == colinfo->num_cols); - Assert(j == nnewcolumns); -#endif - - /* - * For a named join, print column aliases if we changed any from the child - * names. Unnamed joins cannot print aliases. - */ - if (rte->alias != NULL) - colinfo->printaliases = changed_any; - else - colinfo->printaliases = false; -} - -/* - * colname_is_unique: is colname distinct from already-chosen column names? - * - * dpns is query-wide info, colinfo is for the column's RTE - */ -static bool -colname_is_unique(const char *colname, deparse_namespace *dpns, - deparse_columns *colinfo) -{ - int i; - ListCell *lc; - - /* Check against already-assigned column aliases within RTE */ - for (i = 0; i < colinfo->num_cols; i++) - { - char *oldname = colinfo->colnames[i]; - - if (oldname && strcmp(oldname, colname) == 0) - return false; - } - - /* - * If we're building a new_colnames array, check that too (this will be - * partially but not completely redundant with the previous checks) - */ - for (i = 0; i < colinfo->num_new_cols; i++) - { - char *oldname = colinfo->new_colnames[i]; - - if (oldname && strcmp(oldname, colname) == 0) - return false; - } - - /* Also check against USING-column names that must be globally unique */ - foreach(lc, dpns->using_names) - { - char *oldname = (char *) lfirst(lc); - - if (strcmp(oldname, colname) == 0) - return false; - } - - /* Also check against names already assigned for parent-join USING cols */ - foreach(lc, colinfo->parentUsing) - { - char *oldname = (char *) lfirst(lc); - - if (strcmp(oldname, colname) == 0) - return false; - } - - return true; -} - -/* - * make_colname_unique: modify colname if necessary to make it unique - * - * dpns is query-wide info, colinfo is for the column's RTE - */ -static char * -make_colname_unique(char *colname, deparse_namespace *dpns, - deparse_columns *colinfo) -{ - /* - * If the selected name isn't unique, append digits to make it so. For a - * very long input name, we might have to truncate to stay within - * NAMEDATALEN. - */ - if (!colname_is_unique(colname, dpns, colinfo)) - { - int colnamelen = strlen(colname); - char *modname = (char *) palloc(colnamelen + 16); - int i = 0; - - do - { - i++; - for (;;) - { - memcpy(modname, colname, colnamelen); - sprintf(modname + colnamelen, "_%d", i); - if (strlen(modname) < NAMEDATALEN) - break; - /* drop chars from colname to keep all the digits */ - colnamelen = pg_mbcliplen(colname, colnamelen, - colnamelen - 1); - } - } while (!colname_is_unique(modname, dpns, colinfo)); - colname = modname; - } - return colname; -} - -/* - * expand_colnames_array_to: make colinfo->colnames at least n items long - * - * Any added array entries are initialized to zero. - */ -static void -expand_colnames_array_to(deparse_columns *colinfo, int n) -{ - if (n > colinfo->num_cols) - { - if (colinfo->colnames == NULL) - colinfo->colnames = (char **) palloc0(n * sizeof(char *)); - else - { - colinfo->colnames = (char **) repalloc(colinfo->colnames, - n * sizeof(char *)); - memset(colinfo->colnames + colinfo->num_cols, 0, - (n - colinfo->num_cols) * sizeof(char *)); - } - colinfo->num_cols = n; - } -} - -/* - * identify_join_columns: figure out where columns of a join come from - * - * Fills the join-specific fields of the colinfo struct, except for - * usingNames which is filled later. - */ -static void -identify_join_columns(JoinExpr *j, RangeTblEntry *jrte, - deparse_columns *colinfo) -{ - int numjoincols; - int jcolno; - int rcolno; - ListCell *lc; - - /* Extract left/right child RT indexes */ - if (IsA(j->larg, RangeTblRef)) - colinfo->leftrti = ((RangeTblRef *) j->larg)->rtindex; - else if (IsA(j->larg, JoinExpr)) - colinfo->leftrti = ((JoinExpr *) j->larg)->rtindex; - else - elog(ERROR, "unrecognized node type in jointree: %d", - (int) nodeTag(j->larg)); - if (IsA(j->rarg, RangeTblRef)) - colinfo->rightrti = ((RangeTblRef *) j->rarg)->rtindex; - else if (IsA(j->rarg, JoinExpr)) - colinfo->rightrti = ((JoinExpr *) j->rarg)->rtindex; - else - elog(ERROR, "unrecognized node type in jointree: %d", - (int) nodeTag(j->rarg)); - - /* Assert children will be processed earlier than join in second pass */ - Assert(colinfo->leftrti < j->rtindex); - Assert(colinfo->rightrti < j->rtindex); - - /* Initialize result arrays with zeroes */ - numjoincols = list_length(jrte->joinaliasvars); - Assert(numjoincols == list_length(jrte->eref->colnames)); - colinfo->leftattnos = (int *) palloc0(numjoincols * sizeof(int)); - colinfo->rightattnos = (int *) palloc0(numjoincols * sizeof(int)); - - /* - * Deconstruct RTE's joinleftcols/joinrightcols into desired format. - * Recall that the column(s) merged due to USING are the first column(s) - * of the join output. We need not do anything special while scanning - * joinleftcols, but while scanning joinrightcols we must distinguish - * merged from unmerged columns. - */ - jcolno = 0; - foreach(lc, jrte->joinleftcols) - { - int leftattno = lfirst_int(lc); - - colinfo->leftattnos[jcolno++] = leftattno; - } - rcolno = 0; - foreach(lc, jrte->joinrightcols) - { - int rightattno = lfirst_int(lc); - - if (rcolno < jrte->joinmergedcols) /* merged column? */ - colinfo->rightattnos[rcolno] = rightattno; - else - colinfo->rightattnos[jcolno++] = rightattno; - rcolno++; - } - Assert(jcolno == numjoincols); -} - -/* - * get_rtable_name: convenience function to get a previously assigned RTE alias - * - * The RTE must belong to the topmost namespace level in "context". - */ -static char * -get_rtable_name(int rtindex, deparse_context *context) -{ - deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces); - - Assert(rtindex > 0 && rtindex <= list_length(dpns->rtable_names)); - return (char *) list_nth(dpns->rtable_names, rtindex - 1); -} - -/* - * set_deparse_plan: set up deparse_namespace to parse subexpressions - * of a given Plan node - * - * This sets the plan, outer_planstate, inner_planstate, outer_tlist, - * inner_tlist, and index_tlist fields. Caller is responsible for adjusting - * the ancestors list if necessary. Note that the rtable and ctes fields do - * not need to change when shifting attention to different plan nodes in a - * single plan tree. - */ -static void -set_deparse_plan(deparse_namespace *dpns, Plan *plan) -{ - dpns->plan = plan; - - /* - * We special-case Append and MergeAppend to pretend that the first child - * plan is the OUTER referent; we have to interpret OUTER Vars in their - * tlists according to one of the children, and the first one is the most - * natural choice. - */ - if (IsA(plan, Append)) - dpns->outer_plan = linitial(((Append *) plan)->appendplans); - else if (IsA(plan, MergeAppend)) - dpns->outer_plan = linitial(((MergeAppend *) plan)->mergeplans); - else - dpns->outer_plan = outerPlan(plan); - - if (dpns->outer_plan) - dpns->outer_tlist = dpns->outer_plan->targetlist; - else - dpns->outer_tlist = NIL; - - /* - * For a SubqueryScan, pretend the subplan is INNER referent. (We don't - * use OUTER because that could someday conflict with the normal meaning.) - * Likewise, for a CteScan, pretend the subquery's plan is INNER referent. - * For ON CONFLICT .. UPDATE we just need the inner tlist to point to the - * excluded expression's tlist. (Similar to the SubqueryScan we don't want - * to reuse OUTER, it's used for RETURNING in some modify table cases, - * although not INSERT .. CONFLICT). - */ - if (IsA(plan, SubqueryScan)) - dpns->inner_plan = ((SubqueryScan *) plan)->subplan; - else if (IsA(plan, CteScan)) - dpns->inner_plan = list_nth(dpns->subplans, - ((CteScan *) plan)->ctePlanId - 1); - else if (IsA(plan, ModifyTable)) - dpns->inner_plan = plan; - else - dpns->inner_plan = innerPlan(plan); - - if (IsA(plan, ModifyTable)) - dpns->inner_tlist = ((ModifyTable *) plan)->exclRelTlist; - else if (dpns->inner_plan) - dpns->inner_tlist = dpns->inner_plan->targetlist; - else - dpns->inner_tlist = NIL; - - /* Set up referent for INDEX_VAR Vars, if needed */ - if (IsA(plan, IndexOnlyScan)) - dpns->index_tlist = ((IndexOnlyScan *) plan)->indextlist; - else if (IsA(plan, ForeignScan)) - dpns->index_tlist = ((ForeignScan *) plan)->fdw_scan_tlist; - else if (IsA(plan, CustomScan)) - dpns->index_tlist = ((CustomScan *) plan)->custom_scan_tlist; - else - dpns->index_tlist = NIL; -} - -/* - * push_child_plan: temporarily transfer deparsing attention to a child plan - * - * When expanding an OUTER_VAR or INNER_VAR reference, we must adjust the - * deparse context in case the referenced expression itself uses - * OUTER_VAR/INNER_VAR. We modify the top stack entry in-place to avoid - * affecting levelsup issues (although in a Plan tree there really shouldn't - * be any). - * - * Caller must provide a local deparse_namespace variable to save the - * previous state for pop_child_plan. - */ -static void -push_child_plan(deparse_namespace *dpns, Plan *plan, - deparse_namespace *save_dpns) -{ - /* Save state for restoration later */ - *save_dpns = *dpns; - - /* Link current plan node into ancestors list */ - dpns->ancestors = lcons(dpns->plan, dpns->ancestors); - - /* Set attention on selected child */ - set_deparse_plan(dpns, plan); -} - -/* - * pop_child_plan: undo the effects of push_child_plan - */ -static void -pop_child_plan(deparse_namespace *dpns, deparse_namespace *save_dpns) -{ - List *ancestors; - - /* Get rid of ancestors list cell added by push_child_plan */ - ancestors = list_delete_first(dpns->ancestors); - - /* Restore fields changed by push_child_plan */ - *dpns = *save_dpns; - - /* Make sure dpns->ancestors is right (may be unnecessary) */ - dpns->ancestors = ancestors; -} - -/* - * push_ancestor_plan: temporarily transfer deparsing attention to an - * ancestor plan - * - * When expanding a Param reference, we must adjust the deparse context - * to match the plan node that contains the expression being printed; - * otherwise we'd fail if that expression itself contains a Param or - * OUTER_VAR/INNER_VAR/INDEX_VAR variable. - * - * The target ancestor is conveniently identified by the ListCell holding it - * in dpns->ancestors. - * - * Caller must provide a local deparse_namespace variable to save the - * previous state for pop_ancestor_plan. - */ -static void -push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell, - deparse_namespace *save_dpns) -{ - Plan *plan = (Plan *) lfirst(ancestor_cell); - - /* Save state for restoration later */ - *save_dpns = *dpns; - - /* Build a new ancestor list with just this node's ancestors */ - dpns->ancestors = - list_copy_tail(dpns->ancestors, - list_cell_number(dpns->ancestors, ancestor_cell) + 1); - - /* Set attention on selected ancestor */ - set_deparse_plan(dpns, plan); -} - -/* - * pop_ancestor_plan: undo the effects of push_ancestor_plan - */ -static void -pop_ancestor_plan(deparse_namespace *dpns, deparse_namespace *save_dpns) -{ - /* Free the ancestor list made in push_ancestor_plan */ - list_free(dpns->ancestors); - - /* Restore fields changed by push_ancestor_plan */ - *dpns = *save_dpns; -} - - -/* ---------- - * deparse_shard_query - Parse back a query for execution on a shard - * - * Builds an SQL string to perform the provided query on a specific shard and - * places this string into the provided buffer. - * ---------- - */ -void -deparse_shard_query(Query *query, Oid distrelid, int64 shardid, - StringInfo buffer) -{ - get_query_def_extended(query, buffer, NIL, distrelid, shardid, NULL, 0, - WRAP_COLUMN_DEFAULT, 0); -} - - -/* ---------- - * get_query_def - Parse back one query parsetree - * - * If resultDesc is not NULL, then it is the output tuple descriptor for - * the view represented by a SELECT query. - * ---------- - */ -static void -get_query_def(Query *query, StringInfo buf, List *parentnamespace, - TupleDesc resultDesc, - int prettyFlags, int wrapColumn, int startIndent) -{ - get_query_def_extended(query, buf, parentnamespace, InvalidOid, 0, resultDesc, - prettyFlags, wrapColumn, startIndent); -} - - -/* ---------- - * get_query_def_extended - Parse back one query parsetree, optionally - * with extension using a shard identifier. - * - * If distrelid is valid and shardid is positive, the provided shardid is added - * any time the provided relid is deparsed, so that the query may be executed - * on a placement for the given shard. - * ---------- - */ -static void -get_query_def_extended(Query *query, StringInfo buf, List *parentnamespace, - Oid distrelid, int64 shardid, TupleDesc resultDesc, - int prettyFlags, int wrapColumn, int startIndent) -{ - deparse_context context; - deparse_namespace dpns; - - /* Guard against excessively long or deeply-nested queries */ - CHECK_FOR_INTERRUPTS(); - check_stack_depth(); - - /* - * Before we begin to examine the query, acquire locks on referenced - * relations, and fix up deleted columns in JOIN RTEs. This ensures - * consistent results. Note we assume it's OK to scribble on the passed - * querytree! - * - * We are only deparsing the query (we are not about to execute it), so we - * only need AccessShareLock on the relations it mentions. - */ - AcquireRewriteLocks(query, false, false); - - /* - * Set search_path to NIL so that all objects outside of pg_catalog will be - * schema-prefixed. pg_catalog will be added automatically when we call - * PushEmptySearchPath(). - */ - int saveNestLevel = PushEmptySearchPath(); - - context.buf = buf; - context.namespaces = lcons(&dpns, list_copy(parentnamespace)); - context.windowClause = NIL; - context.windowTList = NIL; - context.varprefix = (parentnamespace != NIL || - list_length(query->rtable) != 1); - context.prettyFlags = prettyFlags; - context.wrapColumn = wrapColumn; - context.indentLevel = startIndent; - context.special_exprkind = EXPR_KIND_NONE; - context.appendparents = NULL; - context.distrelid = distrelid; - context.shardid = shardid; - - set_deparse_for_query(&dpns, query, parentnamespace); - - switch (query->commandType) - { - case CMD_SELECT: - get_select_query_def(query, &context, resultDesc); - break; - - case CMD_UPDATE: - get_update_query_def(query, &context); - break; - - case CMD_INSERT: - get_insert_query_def(query, &context); - break; - - case CMD_DELETE: - get_delete_query_def(query, &context); - break; - - case CMD_NOTHING: - appendStringInfoString(buf, "NOTHING"); - break; - - case CMD_UTILITY: - get_utility_query_def(query, &context); - break; - - default: - elog(ERROR, "unrecognized query command type: %d", - query->commandType); - break; - } - - /* revert back to original search_path */ - PopEmptySearchPath(saveNestLevel); -} - -/* ---------- - * get_values_def - Parse back a VALUES list - * ---------- - */ -static void -get_values_def(List *values_lists, deparse_context *context) -{ - StringInfo buf = context->buf; - bool first_list = true; - ListCell *vtl; - - appendStringInfoString(buf, "VALUES "); - - foreach(vtl, values_lists) - { - List *sublist = (List *) lfirst(vtl); - bool first_col = true; - ListCell *lc; - - if (first_list) - first_list = false; - else - appendStringInfoString(buf, ", "); - - appendStringInfoChar(buf, '('); - foreach(lc, sublist) - { - Node *col = (Node *) lfirst(lc); - - if (first_col) - first_col = false; - else - appendStringInfoChar(buf, ','); - - /* - * Print the value. Whole-row Vars need special treatment. - */ - get_rule_expr_toplevel(col, context, false); - } - appendStringInfoChar(buf, ')'); - } -} - -/* ---------- - * get_with_clause - Parse back a WITH clause - * ---------- - */ -static void -get_with_clause(Query *query, deparse_context *context) -{ - StringInfo buf = context->buf; - const char *sep; - ListCell *l; - - if (query->cteList == NIL) - return; - - if (PRETTY_INDENT(context)) - { - context->indentLevel += PRETTYINDENT_STD; - appendStringInfoChar(buf, ' '); - } - - if (query->hasRecursive) - sep = "WITH RECURSIVE "; - else - sep = "WITH "; - foreach(l, query->cteList) - { - CommonTableExpr *cte = (CommonTableExpr *) lfirst(l); - - appendStringInfoString(buf, sep); - appendStringInfoString(buf, quote_identifier(cte->ctename)); - if (cte->aliascolnames) - { - bool first = true; - ListCell *col; - - appendStringInfoChar(buf, '('); - foreach(col, cte->aliascolnames) - { - if (first) - first = false; - else - appendStringInfoString(buf, ", "); - appendStringInfoString(buf, - quote_identifier(strVal(lfirst(col)))); - } - appendStringInfoChar(buf, ')'); - } - appendStringInfoString(buf, " AS "); - switch (cte->ctematerialized) - { - case CTEMaterializeDefault: - break; - case CTEMaterializeAlways: - appendStringInfoString(buf, "MATERIALIZED "); - break; - case CTEMaterializeNever: - appendStringInfoString(buf, "NOT MATERIALIZED "); - break; - } - appendStringInfoChar(buf, '('); - if (PRETTY_INDENT(context)) - appendContextKeyword(context, "", 0, 0, 0); - get_query_def((Query *) cte->ctequery, buf, context->namespaces, NULL, - context->prettyFlags, context->wrapColumn, - context->indentLevel); - if (PRETTY_INDENT(context)) - appendContextKeyword(context, "", 0, 0, 0); - appendStringInfoChar(buf, ')'); - - if (cte->search_clause) - { - bool first = true; - ListCell *lc; - - appendStringInfo(buf, " SEARCH %s FIRST BY ", - cte->search_clause->search_breadth_first ? "BREADTH" : "DEPTH"); - - foreach(lc, cte->search_clause->search_col_list) - { - if (first) - first = false; - else - appendStringInfoString(buf, ", "); - appendStringInfoString(buf, - quote_identifier(strVal(lfirst(lc)))); - } - - appendStringInfo(buf, " SET %s", quote_identifier(cte->search_clause->search_seq_column)); - } - - if (cte->cycle_clause) - { - bool first = true; - ListCell *lc; - - appendStringInfoString(buf, " CYCLE "); - - foreach(lc, cte->cycle_clause->cycle_col_list) - { - if (first) - first = false; - else - appendStringInfoString(buf, ", "); - appendStringInfoString(buf, - quote_identifier(strVal(lfirst(lc)))); - } - - appendStringInfo(buf, " SET %s", quote_identifier(cte->cycle_clause->cycle_mark_column)); - - { - Const *cmv = castNode(Const, cte->cycle_clause->cycle_mark_value); - Const *cmd = castNode(Const, cte->cycle_clause->cycle_mark_default); - - if (!(cmv->consttype == BOOLOID && !cmv->constisnull && DatumGetBool(cmv->constvalue) == true && - cmd->consttype == BOOLOID && !cmd->constisnull && DatumGetBool(cmd->constvalue) == false)) - { - appendStringInfoString(buf, " TO "); - get_rule_expr(cte->cycle_clause->cycle_mark_value, context, false); - appendStringInfoString(buf, " DEFAULT "); - get_rule_expr(cte->cycle_clause->cycle_mark_default, context, false); - } - } - - appendStringInfo(buf, " USING %s", quote_identifier(cte->cycle_clause->cycle_path_column)); - } - - sep = ", "; - } - - if (PRETTY_INDENT(context)) - { - context->indentLevel -= PRETTYINDENT_STD; - appendContextKeyword(context, "", 0, 0, 0); - } - else - appendStringInfoChar(buf, ' '); -} - -/* ---------- - * get_select_query_def - Parse back a SELECT parsetree - * ---------- - */ -static void -get_select_query_def(Query *query, deparse_context *context, - TupleDesc resultDesc) -{ - StringInfo buf = context->buf; - List *save_windowclause; - List *save_windowtlist; - bool force_colno; - ListCell *l; - - /* Insert the WITH clause if given */ - get_with_clause(query, context); - - /* Set up context for possible window functions */ - save_windowclause = context->windowClause; - context->windowClause = query->windowClause; - save_windowtlist = context->windowTList; - context->windowTList = query->targetList; - - /* - * If the Query node has a setOperations tree, then it's the top level of - * a UNION/INTERSECT/EXCEPT query; only the WITH, ORDER BY and LIMIT - * fields are interesting in the top query itself. - */ - if (query->setOperations) - { - get_setop_query(query->setOperations, query, context, resultDesc); - /* ORDER BY clauses must be simple in this case */ - force_colno = true; - } - else - { - get_basic_select_query(query, context, resultDesc); - force_colno = false; - } - - /* Add the ORDER BY clause if given */ - if (query->sortClause != NIL) - { - appendContextKeyword(context, " ORDER BY ", - -PRETTYINDENT_STD, PRETTYINDENT_STD, 1); - get_rule_orderby(query->sortClause, query->targetList, - force_colno, context); - } - - /* - * Add the LIMIT/OFFSET clauses if given. If non-default options, use the - * standard spelling of LIMIT. - */ - if (query->limitOffset != NULL) - { - appendContextKeyword(context, " OFFSET ", - -PRETTYINDENT_STD, PRETTYINDENT_STD, 0); - get_rule_expr(query->limitOffset, context, false); - } - if (query->limitCount != NULL) - { - if (query->limitOption == LIMIT_OPTION_WITH_TIES) - { - // had to add '(' and ')' here because it fails with casting - appendContextKeyword(context, " FETCH FIRST (", - -PRETTYINDENT_STD, PRETTYINDENT_STD, 0); - get_rule_expr(query->limitCount, context, false); - appendStringInfoString(buf, ") ROWS WITH TIES"); - } - else - { - appendContextKeyword(context, " LIMIT ", - -PRETTYINDENT_STD, PRETTYINDENT_STD, 0); - if (IsA(query->limitCount, Const) && - ((Const *) query->limitCount)->constisnull) - appendStringInfoString(buf, "ALL"); - else - get_rule_expr(query->limitCount, context, false); - } - } - - /* Add FOR [KEY] UPDATE/SHARE clauses if present */ - if (query->hasForUpdate) - { - foreach(l, query->rowMarks) - { - RowMarkClause *rc = (RowMarkClause *) lfirst(l); - - /* don't print implicit clauses */ - if (rc->pushedDown) - continue; - - switch (rc->strength) - { - case LCS_NONE: - /* we intentionally throw an error for LCS_NONE */ - elog(ERROR, "unrecognized LockClauseStrength %d", - (int) rc->strength); - break; - case LCS_FORKEYSHARE: - appendContextKeyword(context, " FOR KEY SHARE", - -PRETTYINDENT_STD, PRETTYINDENT_STD, 0); - break; - case LCS_FORSHARE: - appendContextKeyword(context, " FOR SHARE", - -PRETTYINDENT_STD, PRETTYINDENT_STD, 0); - break; - case LCS_FORNOKEYUPDATE: - appendContextKeyword(context, " FOR NO KEY UPDATE", - -PRETTYINDENT_STD, PRETTYINDENT_STD, 0); - break; - case LCS_FORUPDATE: - appendContextKeyword(context, " FOR UPDATE", - -PRETTYINDENT_STD, PRETTYINDENT_STD, 0); - break; - } - - appendStringInfo(buf, " OF %s", - quote_identifier(get_rtable_name(rc->rti, - context))); - if (rc->waitPolicy == LockWaitError) - appendStringInfoString(buf, " NOWAIT"); - else if (rc->waitPolicy == LockWaitSkip) - appendStringInfoString(buf, " SKIP LOCKED"); - } - } - - context->windowClause = save_windowclause; - context->windowTList = save_windowtlist; -} - -/* - * Detect whether query looks like SELECT ... FROM VALUES(); - * if so, return the VALUES RTE. Otherwise return NULL. - */ -static RangeTblEntry * -get_simple_values_rte(Query *query, TupleDesc resultDesc) -{ - RangeTblEntry *result = NULL; - ListCell *lc; - int colno; - - /* - * We want to return true even if the Query also contains OLD or NEW rule - * RTEs. So the idea is to scan the rtable and see if there is only one - * inFromCl RTE that is a VALUES RTE. - */ - foreach(lc, query->rtable) - { - RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc); - - if (rte->rtekind == RTE_VALUES && rte->inFromCl) - { - if (result) - return NULL; /* multiple VALUES (probably not possible) */ - result = rte; - } - else if (rte->rtekind == RTE_RELATION && !rte->inFromCl) - continue; /* ignore rule entries */ - else - return NULL; /* something else -> not simple VALUES */ - } - - /* - * We don't need to check the targetlist in any great detail, because - * parser/analyze.c will never generate a "bare" VALUES RTE --- they only - * appear inside auto-generated sub-queries with very restricted - * structure. However, DefineView might have modified the tlist by - * injecting new column aliases; so compare tlist resnames against the - * RTE's names to detect that. - */ - if (result) - { - ListCell *lcn; - - if (list_length(query->targetList) != list_length(result->eref->colnames)) - return NULL; /* this probably cannot happen */ - colno = 0; - forboth(lc, query->targetList, lcn, result->eref->colnames) - { - TargetEntry *tle = (TargetEntry *) lfirst(lc); - char *cname = strVal(lfirst(lcn)); - char *colname; - - if (tle->resjunk) - return NULL; /* this probably cannot happen */ - /* compute name that get_target_list would use for column */ - colno++; - if (resultDesc && colno <= resultDesc->natts) - colname = NameStr(TupleDescAttr(resultDesc, colno - 1)->attname); - else - colname = tle->resname; - - /* does it match the VALUES RTE? */ - if (colname == NULL || strcmp(colname, cname) != 0) - return NULL; /* column name has been changed */ - } - } - - return result; -} - -static void -get_basic_select_query(Query *query, deparse_context *context, - TupleDesc resultDesc) -{ - StringInfo buf = context->buf; - RangeTblEntry *values_rte; - char *sep; - ListCell *l; - - if (PRETTY_INDENT(context)) - { - context->indentLevel += PRETTYINDENT_STD; - appendStringInfoChar(buf, ' '); - } - - /* - * If the query looks like SELECT * FROM (VALUES ...), then print just the - * VALUES part. This reverses what transformValuesClause() did at parse - * time. - */ - values_rte = get_simple_values_rte(query, resultDesc); - if (values_rte) - { - get_values_def(values_rte->values_lists, context); - return; - } - - /* - * Build up the query string - first we say SELECT - */ - if (query->isReturn) - appendStringInfoString(buf, "RETURN"); - else - appendStringInfoString(buf, "SELECT"); - - /* Add the DISTINCT clause if given */ - if (query->distinctClause != NIL) - { - if (query->hasDistinctOn) - { - appendStringInfoString(buf, " DISTINCT ON ("); - sep = ""; - foreach(l, query->distinctClause) - { - SortGroupClause *srt = (SortGroupClause *) lfirst(l); - - appendStringInfoString(buf, sep); - get_rule_sortgroupclause(srt->tleSortGroupRef, query->targetList, - false, context); - sep = ", "; - } - appendStringInfoChar(buf, ')'); - } - else - appendStringInfoString(buf, " DISTINCT"); - } - - /* Then we tell what to select (the targetlist) */ - get_target_list(query->targetList, context, resultDesc); - - /* Add the FROM clause if needed */ - get_from_clause(query, " FROM ", context); - - /* Add the WHERE clause if given */ - if (query->jointree->quals != NULL) - { - appendContextKeyword(context, " WHERE ", - -PRETTYINDENT_STD, PRETTYINDENT_STD, 1); - get_rule_expr(query->jointree->quals, context, false); - } - - /* Add the GROUP BY clause if given */ - if (query->groupClause != NULL || query->groupingSets != NULL) - { - ParseExprKind save_exprkind; - - appendContextKeyword(context, " GROUP BY ", - -PRETTYINDENT_STD, PRETTYINDENT_STD, 1); - if (query->groupDistinct) - appendStringInfoString(buf, "DISTINCT "); - - save_exprkind = context->special_exprkind; - context->special_exprkind = EXPR_KIND_GROUP_BY; - - if (query->groupingSets == NIL) - { - sep = ""; - foreach(l, query->groupClause) - { - SortGroupClause *grp = (SortGroupClause *) lfirst(l); - - appendStringInfoString(buf, sep); - get_rule_sortgroupclause(grp->tleSortGroupRef, query->targetList, - false, context); - sep = ", "; - } - } - else - { - sep = ""; - foreach(l, query->groupingSets) - { - GroupingSet *grp = lfirst(l); - - appendStringInfoString(buf, sep); - get_rule_groupingset(grp, query->targetList, true, context); - sep = ", "; - } - } - - context->special_exprkind = save_exprkind; - } - - /* Add the HAVING clause if given */ - if (query->havingQual != NULL) - { - appendContextKeyword(context, " HAVING ", - -PRETTYINDENT_STD, PRETTYINDENT_STD, 0); - get_rule_expr(query->havingQual, context, false); - } - - /* Add the WINDOW clause if needed */ - if (query->windowClause != NIL) - get_rule_windowclause(query, context); -} - -/* ---------- - * get_target_list - Parse back a SELECT target list - * - * This is also used for RETURNING lists in INSERT/UPDATE/DELETE. - * ---------- - */ -static void -get_target_list(List *targetList, deparse_context *context, - TupleDesc resultDesc) -{ - StringInfo buf = context->buf; - StringInfoData targetbuf; - bool last_was_multiline = false; - char *sep; - int colno; - ListCell *l; - - /* we use targetbuf to hold each TLE's text temporarily */ - initStringInfo(&targetbuf); - - sep = " "; - colno = 0; - foreach(l, targetList) - { - TargetEntry *tle = (TargetEntry *) lfirst(l); - char *colname; - char *attname; - - if (tle->resjunk) - continue; /* ignore junk entries */ - - appendStringInfoString(buf, sep); - sep = ", "; - colno++; - - /* - * Put the new field text into targetbuf so we can decide after we've - * got it whether or not it needs to go on a new line. - */ - resetStringInfo(&targetbuf); - context->buf = &targetbuf; - - /* - * We special-case Var nodes rather than using get_rule_expr. This is - * needed because get_rule_expr will display a whole-row Var as - * "foo.*", which is the preferred notation in most contexts, but at - * the top level of a SELECT list it's not right (the parser will - * expand that notation into multiple columns, yielding behavior - * different from a whole-row Var). We need to call get_variable - * directly so that we can tell it to do the right thing, and so that - * we can get the attribute name which is the default AS label. - */ - if (tle->expr && (IsA(tle->expr, Var))) - { - attname = get_variable((Var *) tle->expr, 0, true, context); - } - else - { - get_rule_expr((Node *) tle->expr, context, true); - /* We'll show the AS name unless it's this: */ - attname = "?column?"; - } - - /* - * Figure out what the result column should be called. In the context - * of a view, use the view's tuple descriptor (so as to pick up the - * effects of any column RENAME that's been done on the view). - * Otherwise, just use what we can find in the TLE. - */ - if (resultDesc && colno <= resultDesc->natts) - colname = NameStr(TupleDescAttr(resultDesc, colno - 1)->attname); - else - colname = tle->resname; - - /* Show AS unless the column's name is correct as-is */ - if (colname) /* resname could be NULL */ - { - if (attname == NULL || strcmp(attname, colname) != 0) - appendStringInfo(&targetbuf, " AS %s", quote_identifier(colname)); - } - - /* Restore context's output buffer */ - context->buf = buf; - - /* Consider line-wrapping if enabled */ - if (PRETTY_INDENT(context) && context->wrapColumn >= 0) - { - int leading_nl_pos; - - /* Does the new field start with a new line? */ - if (targetbuf.len > 0 && targetbuf.data[0] == '\n') - leading_nl_pos = 0; - else - leading_nl_pos = -1; - - /* If so, we shouldn't add anything */ - if (leading_nl_pos >= 0) - { - /* instead, remove any trailing spaces currently in buf */ - removeStringInfoSpaces(buf); - } - else - { - char *trailing_nl; - - /* Locate the start of the current line in the output buffer */ - trailing_nl = strrchr(buf->data, '\n'); - if (trailing_nl == NULL) - trailing_nl = buf->data; - else - trailing_nl++; - - /* - * Add a newline, plus some indentation, if the new field is - * not the first and either the new field would cause an - * overflow or the last field used more than one line. - */ - if (colno > 1 && - ((strlen(trailing_nl) + targetbuf.len > context->wrapColumn) || - last_was_multiline)) - appendContextKeyword(context, "", -PRETTYINDENT_STD, - PRETTYINDENT_STD, PRETTYINDENT_VAR); - } - - /* Remember this field's multiline status for next iteration */ - last_was_multiline = - (strchr(targetbuf.data + leading_nl_pos + 1, '\n') != NULL); - } - - /* Add the new field */ - appendStringInfoString(buf, targetbuf.data); - } - - /* clean up */ - pfree(targetbuf.data); -} - -static void -get_setop_query(Node *setOp, Query *query, deparse_context *context, - TupleDesc resultDesc) -{ - StringInfo buf = context->buf; - bool need_paren; - - /* Guard against excessively long or deeply-nested queries */ - CHECK_FOR_INTERRUPTS(); - check_stack_depth(); - - if (IsA(setOp, RangeTblRef)) - { - RangeTblRef *rtr = (RangeTblRef *) setOp; - RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable); - Query *subquery = rte->subquery; - - Assert(subquery != NULL); - Assert(subquery->setOperations == NULL); - /* Need parens if WITH, ORDER BY, FOR UPDATE, or LIMIT; see gram.y */ - need_paren = (subquery->cteList || - subquery->sortClause || - subquery->rowMarks || - subquery->limitOffset || - subquery->limitCount); - if (need_paren) - appendStringInfoChar(buf, '('); - get_query_def(subquery, buf, context->namespaces, resultDesc, - context->prettyFlags, context->wrapColumn, - context->indentLevel); - if (need_paren) - appendStringInfoChar(buf, ')'); - } - else if (IsA(setOp, SetOperationStmt)) - { - SetOperationStmt *op = (SetOperationStmt *) setOp; - int subindent; - - /* - * We force parens when nesting two SetOperationStmts, except when the - * lefthand input is another setop of the same kind. Syntactically, - * we could omit parens in rather more cases, but it seems best to use - * parens to flag cases where the setop operator changes. If we use - * parens, we also increase the indentation level for the child query. - * - * There are some cases in which parens are needed around a leaf query - * too, but those are more easily handled at the next level down (see - * code above). - */ - if (IsA(op->larg, SetOperationStmt)) - { - SetOperationStmt *lop = (SetOperationStmt *) op->larg; - - if (op->op == lop->op && op->all == lop->all) - need_paren = false; - else - need_paren = true; - } - else - need_paren = false; - - if (need_paren) - { - appendStringInfoChar(buf, '('); - subindent = PRETTYINDENT_STD; - appendContextKeyword(context, "", subindent, 0, 0); - } - else - subindent = 0; - - get_setop_query(op->larg, query, context, resultDesc); - - if (need_paren) - appendContextKeyword(context, ") ", -subindent, 0, 0); - else if (PRETTY_INDENT(context)) - appendContextKeyword(context, "", -subindent, 0, 0); - else - appendStringInfoChar(buf, ' '); - - switch (op->op) - { - case SETOP_UNION: - appendStringInfoString(buf, "UNION "); - break; - case SETOP_INTERSECT: - appendStringInfoString(buf, "INTERSECT "); - break; - case SETOP_EXCEPT: - appendStringInfoString(buf, "EXCEPT "); - break; - default: - elog(ERROR, "unrecognized set op: %d", - (int) op->op); - } - if (op->all) - appendStringInfoString(buf, "ALL "); - - /* Always parenthesize if RHS is another setop */ - need_paren = IsA(op->rarg, SetOperationStmt); - - /* - * The indentation code here is deliberately a bit different from that - * for the lefthand input, because we want the line breaks in - * different places. - */ - if (need_paren) - { - appendStringInfoChar(buf, '('); - subindent = PRETTYINDENT_STD; - } - else - subindent = 0; - appendContextKeyword(context, "", subindent, 0, 0); - - get_setop_query(op->rarg, query, context, resultDesc); - - if (PRETTY_INDENT(context)) - context->indentLevel -= subindent; - if (need_paren) - appendContextKeyword(context, ")", 0, 0, 0); - } - else - { - elog(ERROR, "unrecognized node type: %d", - (int) nodeTag(setOp)); - } -} - -/* - * Display a sort/group clause. - * - * Also returns the expression tree, so caller need not find it again. - */ -static Node * -get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno, - deparse_context *context) -{ - StringInfo buf = context->buf; - TargetEntry *tle; - Node *expr; - - tle = get_sortgroupref_tle(ref, tlist); - expr = (Node *) tle->expr; - - /* - * Use column-number form if requested by caller. Otherwise, if - * expression is a constant, force it to be dumped with an explicit cast - * as decoration --- this is because a simple integer constant is - * ambiguous (and will be misinterpreted by findTargetlistEntry()) if we - * dump it without any decoration. If it's anything more complex than a - * simple Var, then force extra parens around it, to ensure it can't be - * misinterpreted as a cube() or rollup() construct. - */ - if (force_colno) - { - Assert(!tle->resjunk); - appendStringInfo(buf, "%d", tle->resno); - } - else if (expr && IsA(expr, Const)) - get_const_expr((Const *) expr, context, 1); - else if (!expr || IsA(expr, Var)) - get_rule_expr(expr, context, true); - else - { - /* - * We must force parens for function-like expressions even if - * PRETTY_PAREN is off, since those are the ones in danger of - * misparsing. For other expressions we need to force them only if - * PRETTY_PAREN is on, since otherwise the expression will output them - * itself. (We can't skip the parens.) - */ - bool need_paren = (PRETTY_PAREN(context) - || IsA(expr, FuncExpr) - || IsA(expr, Aggref) - || IsA(expr, WindowFunc)); - - if (need_paren) - appendStringInfoChar(context->buf, '('); - get_rule_expr(expr, context, true); - if (need_paren) - appendStringInfoChar(context->buf, ')'); - } - - return expr; -} - -/* - * Display a GroupingSet - */ -static void -get_rule_groupingset(GroupingSet *gset, List *targetlist, - bool omit_parens, deparse_context *context) -{ - ListCell *l; - StringInfo buf = context->buf; - bool omit_child_parens = true; - char *sep = ""; - - switch (gset->kind) - { - case GROUPING_SET_EMPTY: - appendStringInfoString(buf, "()"); - return; - - case GROUPING_SET_SIMPLE: - { - if (!omit_parens || list_length(gset->content) != 1) - appendStringInfoChar(buf, '('); - - foreach(l, gset->content) - { - Index ref = lfirst_int(l); - - appendStringInfoString(buf, sep); - get_rule_sortgroupclause(ref, targetlist, - false, context); - sep = ", "; - } - - if (!omit_parens || list_length(gset->content) != 1) - appendStringInfoChar(buf, ')'); - } - return; - - case GROUPING_SET_ROLLUP: - appendStringInfoString(buf, "ROLLUP("); - break; - case GROUPING_SET_CUBE: - appendStringInfoString(buf, "CUBE("); - break; - case GROUPING_SET_SETS: - appendStringInfoString(buf, "GROUPING SETS ("); - omit_child_parens = false; - break; - } - - foreach(l, gset->content) - { - appendStringInfoString(buf, sep); - get_rule_groupingset(lfirst(l), targetlist, omit_child_parens, context); - sep = ", "; - } - - appendStringInfoChar(buf, ')'); -} - -/* - * Display an ORDER BY list. - */ -static void -get_rule_orderby(List *orderList, List *targetList, - bool force_colno, deparse_context *context) -{ - StringInfo buf = context->buf; - const char *sep; - ListCell *l; - - sep = ""; - foreach(l, orderList) - { - SortGroupClause *srt = (SortGroupClause *) lfirst(l); - Node *sortexpr; - Oid sortcoltype; - TypeCacheEntry *typentry; - - appendStringInfoString(buf, sep); - sortexpr = get_rule_sortgroupclause(srt->tleSortGroupRef, targetList, - force_colno, context); - sortcoltype = exprType(sortexpr); - /* See whether operator is default < or > for datatype */ - typentry = lookup_type_cache(sortcoltype, - TYPECACHE_LT_OPR | TYPECACHE_GT_OPR); - if (srt->sortop == typentry->lt_opr) - { - /* ASC is default, so emit nothing for it */ - if (srt->nulls_first) - appendStringInfoString(buf, " NULLS FIRST"); - } - else if (srt->sortop == typentry->gt_opr) - { - appendStringInfoString(buf, " DESC"); - /* DESC defaults to NULLS FIRST */ - if (!srt->nulls_first) - appendStringInfoString(buf, " NULLS LAST"); - } - else - { - appendStringInfo(buf, " USING %s", - generate_operator_name(srt->sortop, - sortcoltype, - sortcoltype)); - /* be specific to eliminate ambiguity */ - if (srt->nulls_first) - appendStringInfoString(buf, " NULLS FIRST"); - else - appendStringInfoString(buf, " NULLS LAST"); - } - sep = ", "; - } -} - -/* - * Display a WINDOW clause. - * - * Note that the windowClause list might contain only anonymous window - * specifications, in which case we should print nothing here. - */ -static void -get_rule_windowclause(Query *query, deparse_context *context) -{ - StringInfo buf = context->buf; - const char *sep; - ListCell *l; - - sep = NULL; - foreach(l, query->windowClause) - { - WindowClause *wc = (WindowClause *) lfirst(l); - - if (wc->name == NULL) - continue; /* ignore anonymous windows */ - - if (sep == NULL) - appendContextKeyword(context, " WINDOW ", - -PRETTYINDENT_STD, PRETTYINDENT_STD, 1); - else - appendStringInfoString(buf, sep); - - appendStringInfo(buf, "%s AS ", quote_identifier(wc->name)); - - get_rule_windowspec(wc, query->targetList, context); - - sep = ", "; - } -} - -/* - * Display a window definition - */ -static void -get_rule_windowspec(WindowClause *wc, List *targetList, - deparse_context *context) -{ - StringInfo buf = context->buf; - bool needspace = false; - const char *sep; - ListCell *l; - - appendStringInfoChar(buf, '('); - if (wc->refname) - { - appendStringInfoString(buf, quote_identifier(wc->refname)); - needspace = true; - } - /* partition clauses are always inherited, so only print if no refname */ - if (wc->partitionClause && !wc->refname) - { - if (needspace) - appendStringInfoChar(buf, ' '); - appendStringInfoString(buf, "PARTITION BY "); - sep = ""; - foreach(l, wc->partitionClause) - { - SortGroupClause *grp = (SortGroupClause *) lfirst(l); - - appendStringInfoString(buf, sep); - get_rule_sortgroupclause(grp->tleSortGroupRef, targetList, - false, context); - sep = ", "; - } - needspace = true; - } - /* print ordering clause only if not inherited */ - if (wc->orderClause && !wc->copiedOrder) - { - if (needspace) - appendStringInfoChar(buf, ' '); - appendStringInfoString(buf, "ORDER BY "); - get_rule_orderby(wc->orderClause, targetList, false, context); - needspace = true; - } - /* framing clause is never inherited, so print unless it's default */ - if (wc->frameOptions & FRAMEOPTION_NONDEFAULT) - { - if (needspace) - appendStringInfoChar(buf, ' '); - if (wc->frameOptions & FRAMEOPTION_RANGE) - appendStringInfoString(buf, "RANGE "); - else if (wc->frameOptions & FRAMEOPTION_ROWS) - appendStringInfoString(buf, "ROWS "); - else if (wc->frameOptions & FRAMEOPTION_GROUPS) - appendStringInfoString(buf, "GROUPS "); - else - Assert(false); - if (wc->frameOptions & FRAMEOPTION_BETWEEN) - appendStringInfoString(buf, "BETWEEN "); - if (wc->frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING) - appendStringInfoString(buf, "UNBOUNDED PRECEDING "); - else if (wc->frameOptions & FRAMEOPTION_START_CURRENT_ROW) - appendStringInfoString(buf, "CURRENT ROW "); - else if (wc->frameOptions & FRAMEOPTION_START_OFFSET) - { - get_rule_expr(wc->startOffset, context, false); - if (wc->frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING) - appendStringInfoString(buf, " PRECEDING "); - else if (wc->frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING) - appendStringInfoString(buf, " FOLLOWING "); - else - Assert(false); - } - else - Assert(false); - if (wc->frameOptions & FRAMEOPTION_BETWEEN) - { - appendStringInfoString(buf, "AND "); - if (wc->frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING) - appendStringInfoString(buf, "UNBOUNDED FOLLOWING "); - else if (wc->frameOptions & FRAMEOPTION_END_CURRENT_ROW) - appendStringInfoString(buf, "CURRENT ROW "); - else if (wc->frameOptions & FRAMEOPTION_END_OFFSET) - { - get_rule_expr(wc->endOffset, context, false); - if (wc->frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING) - appendStringInfoString(buf, " PRECEDING "); - else if (wc->frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING) - appendStringInfoString(buf, " FOLLOWING "); - else - Assert(false); - } - else - Assert(false); - } - if (wc->frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW) - appendStringInfoString(buf, "EXCLUDE CURRENT ROW "); - else if (wc->frameOptions & FRAMEOPTION_EXCLUDE_GROUP) - appendStringInfoString(buf, "EXCLUDE GROUP "); - else if (wc->frameOptions & FRAMEOPTION_EXCLUDE_TIES) - appendStringInfoString(buf, "EXCLUDE TIES "); - /* we will now have a trailing space; remove it */ - buf->len--; - } - appendStringInfoChar(buf, ')'); -} - -/* ---------- - * get_insert_query_def - Parse back an INSERT parsetree - * ---------- - */ -static void -get_insert_query_def(Query *query, deparse_context *context) -{ - StringInfo buf = context->buf; - RangeTblEntry *select_rte = NULL; - RangeTblEntry *values_rte = NULL; - RangeTblEntry *rte; - char *sep; - ListCell *l; - List *strippedexprs; - - /* Insert the WITH clause if given */ - get_with_clause(query, context); - - /* - * If it's an INSERT ... SELECT or multi-row VALUES, there will be a - * single RTE for the SELECT or VALUES. Plain VALUES has neither. - */ - foreach(l, query->rtable) - { - rte = (RangeTblEntry *) lfirst(l); - - if (rte->rtekind == RTE_SUBQUERY) - { - if (select_rte) - elog(ERROR, "too many subquery RTEs in INSERT"); - select_rte = rte; - } - - if (rte->rtekind == RTE_VALUES) - { - if (values_rte) - elog(ERROR, "too many values RTEs in INSERT"); - values_rte = rte; - } - } - if (select_rte && values_rte) - elog(ERROR, "both subquery and values RTEs in INSERT"); - - /* - * Start the query with INSERT INTO relname - */ - rte = rt_fetch(query->resultRelation, query->rtable); - Assert(rte->rtekind == RTE_RELATION); - - if (PRETTY_INDENT(context)) - { - context->indentLevel += PRETTYINDENT_STD; - appendStringInfoChar(buf, ' '); - } - appendStringInfo(buf, "INSERT INTO %s ", - generate_relation_or_shard_name(rte->relid, - context->distrelid, - context->shardid, NIL)); - /* INSERT requires AS keyword for target alias */ - if (rte->alias != NULL) - appendStringInfo(buf, "AS %s ", - quote_identifier(get_rtable_name(query->resultRelation, context))); - - /* - * Add the insert-column-names list. Any indirection decoration needed on - * the column names can be inferred from the top targetlist. - */ - strippedexprs = NIL; - sep = ""; - if (query->targetList) - appendStringInfoChar(buf, '('); - foreach(l, query->targetList) - { - TargetEntry *tle = (TargetEntry *) lfirst(l); - - if (tle->resjunk) - continue; /* ignore junk entries */ - - appendStringInfoString(buf, sep); - sep = ", "; - - /* - * Put out name of target column; look in the catalogs, not at - * tle->resname, since resname will fail to track RENAME. - */ - appendStringInfoString(buf, - quote_identifier(get_attname(rte->relid, - tle->resno, - false))); - - /* - * Print any indirection needed (subfields or subscripts), and strip - * off the top-level nodes representing the indirection assignments. - * Add the stripped expressions to strippedexprs. (If it's a - * single-VALUES statement, the stripped expressions are the VALUES to - * print below. Otherwise they're just Vars and not really - * interesting.) - */ - strippedexprs = lappend(strippedexprs, - processIndirection((Node *) tle->expr, - context)); - } - if (query->targetList) - appendStringInfoString(buf, ") "); - - if (query->override) - { - if (query->override == OVERRIDING_SYSTEM_VALUE) - appendStringInfoString(buf, "OVERRIDING SYSTEM VALUE "); - else if (query->override == OVERRIDING_USER_VALUE) - appendStringInfoString(buf, "OVERRIDING USER VALUE "); - } - - if (select_rte) - { - /* Add the SELECT */ - get_query_def(select_rte->subquery, buf, NIL, NULL, - context->prettyFlags, context->wrapColumn, - context->indentLevel); - } - else if (values_rte) - { - /* Add the multi-VALUES expression lists */ - get_values_def(values_rte->values_lists, context); - } - else if (strippedexprs) - { - /* Add the single-VALUES expression list */ - appendContextKeyword(context, "VALUES (", - -PRETTYINDENT_STD, PRETTYINDENT_STD, 2); - get_rule_expr((Node *) strippedexprs, context, false); - appendStringInfoChar(buf, ')'); - } - else - { - /* No expressions, so it must be DEFAULT VALUES */ - appendStringInfoString(buf, "DEFAULT VALUES"); - } - - /* Add ON CONFLICT if present */ - if (query->onConflict) - { - OnConflictExpr *confl = query->onConflict; - - appendStringInfoString(buf, " ON CONFLICT"); - - if (confl->arbiterElems) - { - /* Add the single-VALUES expression list */ - appendStringInfoChar(buf, '('); - get_rule_expr((Node *) confl->arbiterElems, context, false); - appendStringInfoChar(buf, ')'); - - /* Add a WHERE clause (for partial indexes) if given */ - if (confl->arbiterWhere != NULL) - { - bool save_varprefix; - - /* - * Force non-prefixing of Vars, since parser assumes that they - * belong to target relation. WHERE clause does not use - * InferenceElem, so this is separately required. - */ - save_varprefix = context->varprefix; - context->varprefix = false; - - appendContextKeyword(context, " WHERE ", - -PRETTYINDENT_STD, PRETTYINDENT_STD, 1); - get_rule_expr(confl->arbiterWhere, context, false); - - context->varprefix = save_varprefix; - } - } - else if (OidIsValid(confl->constraint)) - { - char *constraint = get_constraint_name(confl->constraint); - int64 shardId = context->shardid; - - if (shardId > 0) - { - AppendShardIdToName(&constraint, shardId); - } - - if (!constraint) - elog(ERROR, "cache lookup failed for constraint %u", - confl->constraint); - appendStringInfo(buf, " ON CONSTRAINT %s", - quote_identifier(constraint)); - } - - if (confl->action == ONCONFLICT_NOTHING) - { - appendStringInfoString(buf, " DO NOTHING"); - } - else - { - appendStringInfoString(buf, " DO UPDATE SET "); - /* Deparse targetlist */ - get_update_query_targetlist_def(query, confl->onConflictSet, - context, rte); - - /* Add a WHERE clause if given */ - if (confl->onConflictWhere != NULL) - { - appendContextKeyword(context, " WHERE ", - -PRETTYINDENT_STD, PRETTYINDENT_STD, 1); - get_rule_expr(confl->onConflictWhere, context, false); - } - } - } - - /* Add RETURNING if present */ - if (query->returningList) - { - appendContextKeyword(context, " RETURNING", - -PRETTYINDENT_STD, PRETTYINDENT_STD, 1); - get_target_list(query->returningList, context, NULL); - } -} - - -/* ---------- - * get_update_query_def - Parse back an UPDATE parsetree - * ---------- - */ -static void -get_update_query_def(Query *query, deparse_context *context) -{ - StringInfo buf = context->buf; - RangeTblEntry *rte; - - /* Insert the WITH clause if given */ - get_with_clause(query, context); - - /* - * Start the query with UPDATE relname SET - */ - rte = rt_fetch(query->resultRelation, query->rtable); - - if (PRETTY_INDENT(context)) - { - appendStringInfoChar(buf, ' '); - context->indentLevel += PRETTYINDENT_STD; - } - - /* if it's a shard, do differently */ - if (GetRangeTblKind(rte) == CITUS_RTE_SHARD) - { - char *fragmentSchemaName = NULL; - char *fragmentTableName = NULL; - - ExtractRangeTblExtraData(rte, NULL, &fragmentSchemaName, &fragmentTableName, NULL); - - /* use schema and table name from the remote alias */ - appendStringInfo(buf, "UPDATE %s%s", - only_marker(rte), - generate_fragment_name(fragmentSchemaName, fragmentTableName)); - - if(rte->eref != NULL) - appendStringInfo(buf, " %s", - quote_identifier(get_rtable_name(query->resultRelation, context))); - } - else - { - appendStringInfo(buf, "UPDATE %s%s", - only_marker(rte), - generate_relation_or_shard_name(rte->relid, - context->distrelid, - context->shardid, NIL)); - - if (rte->alias != NULL) - appendStringInfo(buf, " %s", - quote_identifier(get_rtable_name(query->resultRelation, context))); - } - - appendStringInfoString(buf, " SET "); - - /* Deparse targetlist */ - get_update_query_targetlist_def(query, query->targetList, context, rte); - - /* Add the FROM clause if needed */ - get_from_clause(query, " FROM ", context); - - /* Add a WHERE clause if given */ - if (query->jointree->quals != NULL) - { - appendContextKeyword(context, " WHERE ", - -PRETTYINDENT_STD, PRETTYINDENT_STD, 1); - get_rule_expr(query->jointree->quals, context, false); - } - - /* Add RETURNING if present */ - if (query->returningList) - { - appendContextKeyword(context, " RETURNING", - -PRETTYINDENT_STD, PRETTYINDENT_STD, 1); - get_target_list(query->returningList, context, NULL); - } -} - - -/* ---------- - * get_update_query_targetlist_def - Parse back an UPDATE targetlist - * ---------- - */ -static void -get_update_query_targetlist_def(Query *query, List *targetList, - deparse_context *context, RangeTblEntry *rte) -{ - StringInfo buf = context->buf; - ListCell *l; - ListCell *next_ma_cell; - int remaining_ma_columns; - const char *sep; - SubLink *cur_ma_sublink; - List *ma_sublinks; - - /* - * Prepare to deal with MULTIEXPR assignments: collect the source SubLinks - * into a list. We expect them to appear, in ID order, in resjunk tlist - * entries. - */ - ma_sublinks = NIL; - if (query->hasSubLinks) /* else there can't be any */ - { - foreach(l, targetList) - { - TargetEntry *tle = (TargetEntry *) lfirst(l); - - if (tle->resjunk && IsA(tle->expr, SubLink)) - { - SubLink *sl = (SubLink *) tle->expr; - - if (sl->subLinkType == MULTIEXPR_SUBLINK) - { - ma_sublinks = lappend(ma_sublinks, sl); - Assert(sl->subLinkId == list_length(ma_sublinks)); - } - } - } - } - next_ma_cell = list_head(ma_sublinks); - cur_ma_sublink = NULL; - remaining_ma_columns = 0; - - /* Add the comma separated list of 'attname = value' */ - sep = ""; - foreach(l, targetList) - { - TargetEntry *tle = (TargetEntry *) lfirst(l); - Node *expr; - - if (tle->resjunk) - continue; /* ignore junk entries */ - - /* Emit separator (OK whether we're in multiassignment or not) */ - appendStringInfoString(buf, sep); - sep = ", "; - - /* - * Check to see if we're starting a multiassignment group: if so, - * output a left paren. - */ - if (next_ma_cell != NULL && cur_ma_sublink == NULL) - { - /* - * We must dig down into the expr to see if it's a PARAM_MULTIEXPR - * Param. That could be buried under FieldStores and - * SubscriptingRefs and CoerceToDomains (cf processIndirection()), - * and underneath those there could be an implicit type coercion. - * Because we would ignore implicit type coercions anyway, we - * don't need to be as careful as processIndirection() is about - * descending past implicit CoerceToDomains. - */ - expr = (Node *) tle->expr; - while (expr) - { - if (IsA(expr, FieldStore)) - { - FieldStore *fstore = (FieldStore *) expr; - - expr = (Node *) linitial(fstore->newvals); - } - else if (IsA(expr, SubscriptingRef)) - { - SubscriptingRef *sbsref = (SubscriptingRef *) expr; - - if (sbsref->refassgnexpr == NULL) - break; - expr = (Node *) sbsref->refassgnexpr; - } - else if (IsA(expr, CoerceToDomain)) - { - CoerceToDomain *cdomain = (CoerceToDomain *) expr; - - if (cdomain->coercionformat != COERCE_IMPLICIT_CAST) - break; - expr = (Node *) cdomain->arg; - } - else - break; - } - expr = strip_implicit_coercions(expr); - - if (expr && IsA(expr, Param) && - ((Param *) expr)->paramkind == PARAM_MULTIEXPR) - { - cur_ma_sublink = (SubLink *) lfirst(next_ma_cell); - next_ma_cell = lnext(ma_sublinks, next_ma_cell); - remaining_ma_columns = count_nonjunk_tlist_entries( - ((Query *) cur_ma_sublink->subselect)->targetList); - Assert(((Param *) expr)->paramid == - ((cur_ma_sublink->subLinkId << 16) | 1)); - appendStringInfoChar(buf, '('); - } - } - - /* - * Put out name of target column; look in the catalogs, not at - * tle->resname, since resname will fail to track RENAME. - */ - appendStringInfoString(buf, - quote_identifier(get_attname(rte->relid, - tle->resno, - false))); - - /* - * Print any indirection needed (subfields or subscripts), and strip - * off the top-level nodes representing the indirection assignments. - */ - expr = processIndirection((Node *) tle->expr, context); - - /* - * If we're in a multiassignment, skip printing anything more, unless - * this is the last column; in which case, what we print should be the - * sublink, not the Param. - */ - if (cur_ma_sublink != NULL) - { - if (--remaining_ma_columns > 0) - continue; /* not the last column of multiassignment */ - appendStringInfoChar(buf, ')'); - expr = (Node *) cur_ma_sublink; - cur_ma_sublink = NULL; - } - - appendStringInfoString(buf, " = "); - - get_rule_expr(expr, context, false); - } -} - - -/* ---------- - * get_delete_query_def - Parse back a DELETE parsetree - * ---------- - */ -static void -get_delete_query_def(Query *query, deparse_context *context) -{ - StringInfo buf = context->buf; - RangeTblEntry *rte; - - /* Insert the WITH clause if given */ - get_with_clause(query, context); - - /* - * Start the query with DELETE FROM relname - */ - rte = rt_fetch(query->resultRelation, query->rtable); - - if (PRETTY_INDENT(context)) - { - appendStringInfoChar(buf, ' '); - context->indentLevel += PRETTYINDENT_STD; - } - - /* if it's a shard, do differently */ - if (GetRangeTblKind(rte) == CITUS_RTE_SHARD) - { - char *fragmentSchemaName = NULL; - char *fragmentTableName = NULL; - - ExtractRangeTblExtraData(rte, NULL, &fragmentSchemaName, &fragmentTableName, NULL); - - /* use schema and table name from the remote alias */ - appendStringInfo(buf, "DELETE FROM %s%s", - only_marker(rte), - generate_fragment_name(fragmentSchemaName, fragmentTableName)); - - if(rte->eref != NULL) - appendStringInfo(buf, " %s", - quote_identifier(get_rtable_name(query->resultRelation, context))); - } - else - { - appendStringInfo(buf, "DELETE FROM %s%s", - only_marker(rte), - generate_relation_or_shard_name(rte->relid, - context->distrelid, - context->shardid, NIL)); - - if (rte->alias != NULL) - appendStringInfo(buf, " %s", - quote_identifier(get_rtable_name(query->resultRelation, context))); - } - - /* Add the USING clause if given */ - get_from_clause(query, " USING ", context); - - /* Add a WHERE clause if given */ - if (query->jointree->quals != NULL) - { - appendContextKeyword(context, " WHERE ", - -PRETTYINDENT_STD, PRETTYINDENT_STD, 1); - get_rule_expr(query->jointree->quals, context, false); - } - - /* Add RETURNING if present */ - if (query->returningList) - { - appendContextKeyword(context, " RETURNING", - -PRETTYINDENT_STD, PRETTYINDENT_STD, 1); - get_target_list(query->returningList, context, NULL); - } -} - - -/* ---------- - * get_utility_query_def - Parse back a UTILITY parsetree - * ---------- - */ -static void -get_utility_query_def(Query *query, deparse_context *context) -{ - StringInfo buf = context->buf; - - if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt)) - { - NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt; - - appendContextKeyword(context, "", - 0, PRETTYINDENT_STD, 1); - appendStringInfo(buf, "NOTIFY %s", - quote_identifier(stmt->conditionname)); - if (stmt->payload) - { - appendStringInfoString(buf, ", "); - simple_quote_literal(buf, stmt->payload); - } - } - else if (query->utilityStmt && IsA(query->utilityStmt, TruncateStmt)) - { - TruncateStmt *stmt = (TruncateStmt *) query->utilityStmt; - List *relationList = stmt->relations; - ListCell *relationCell = NULL; - - appendContextKeyword(context, "", - 0, PRETTYINDENT_STD, 1); - - appendStringInfo(buf, "TRUNCATE TABLE"); - - foreach(relationCell, relationList) - { - RangeVar *relationVar = (RangeVar *) lfirst(relationCell); - Oid relationId = RangeVarGetRelid(relationVar, NoLock, false); - char *relationName = generate_relation_or_shard_name(relationId, - context->distrelid, - context->shardid, NIL); - appendStringInfo(buf, " %s", relationName); - - if (lnext(relationList, relationCell) != NULL) - { - appendStringInfo(buf, ","); - } - } - - if (stmt->restart_seqs) - { - appendStringInfo(buf, " RESTART IDENTITY"); - } - - if (stmt->behavior == DROP_CASCADE) - { - appendStringInfo(buf, " CASCADE"); - } - } - else - { - /* Currently only NOTIFY utility commands can appear in rules */ - elog(ERROR, "unexpected utility statement type"); - } -} - -/* - * Display a Var appropriately. - * - * In some cases (currently only when recursing into an unnamed join) - * the Var's varlevelsup has to be interpreted with respect to a context - * above the current one; levelsup indicates the offset. - * - * If istoplevel is true, the Var is at the top level of a SELECT's - * targetlist, which means we need special treatment of whole-row Vars. - * Instead of the normal "tab.*", we'll print "tab.*::typename", which is a - * dirty hack to prevent "tab.*" from being expanded into multiple columns. - * (The parser will strip the useless coercion, so no inefficiency is added in - * dump and reload.) We used to print just "tab" in such cases, but that is - * ambiguous and will yield the wrong result if "tab" is also a plain column - * name in the query. - * - * Returns the attname of the Var, or NULL if the Var has no attname (because - * it is a whole-row Var or a subplan output reference). - */ -static char * -get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context) -{ - StringInfo buf = context->buf; - RangeTblEntry *rte; - AttrNumber attnum; - Index varno; - AttrNumber varattno; - int netlevelsup; - deparse_namespace *dpns; - deparse_columns *colinfo; - char *refname; - char *attname; - - /* Find appropriate nesting depth */ - netlevelsup = var->varlevelsup + levelsup; - if (netlevelsup >= list_length(context->namespaces)) - elog(ERROR, "bogus varlevelsup: %d offset %d", - var->varlevelsup, levelsup); - dpns = (deparse_namespace *) list_nth(context->namespaces, - netlevelsup); - - varno = var->varno; - varattno = var->varattno; - - - if (var->varnosyn > 0 && var->varnosyn <= list_length(dpns->rtable) && dpns->plan == NULL) { - rte = rt_fetch(var->varnosyn, dpns->rtable); - - /* - * if the rte var->varnosyn points to is not a regular table and it is a join - * then the correct relname will be found with var->varnosyn and var->varattnosyn - */ - if (rte->rtekind == RTE_JOIN && rte->relid == 0 && var->varnosyn != var->varno) { - varno = var->varnosyn; - varattno = var->varattnosyn; - } - } - - /* - * Try to find the relevant RTE in this rtable. In a plan tree, it's - * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig - * down into the subplans, or INDEX_VAR, which is resolved similarly. Also - * find the aliases previously assigned for this RTE. - */ - if (varno >= 1 && varno <= list_length(dpns->rtable)) - { - - /* - * We might have been asked to map child Vars to some parent relation. - */ - if (context->appendparents && dpns->appendrels) - { - - Index pvarno = varno; - AttrNumber pvarattno = varattno; - AppendRelInfo *appinfo = dpns->appendrels[pvarno]; - bool found = false; - - /* Only map up to inheritance parents, not UNION ALL appendrels */ - while (appinfo && - rt_fetch(appinfo->parent_relid, - dpns->rtable)->rtekind == RTE_RELATION) - { - found = false; - if (pvarattno > 0) /* system columns stay as-is */ - { - if (pvarattno > appinfo->num_child_cols) - break; /* safety check */ - pvarattno = appinfo->parent_colnos[pvarattno - 1]; - if (pvarattno == 0) - break; /* Var is local to child */ - } - - pvarno = appinfo->parent_relid; - found = true; - - /* If the parent is itself a child, continue up. */ - Assert(pvarno > 0 && pvarno <= list_length(dpns->rtable)); - appinfo = dpns->appendrels[pvarno]; - } - - /* - * If we found an ancestral rel, and that rel is included in - * appendparents, print that column not the original one. - */ - if (found && bms_is_member(pvarno, context->appendparents)) - { - varno = pvarno; - varattno = pvarattno; - } - } - - rte = rt_fetch(varno, dpns->rtable); - refname = (char *) list_nth(dpns->rtable_names, varno - 1); - colinfo = deparse_columns_fetch(varno, dpns); - attnum = varattno; - } - else - { - resolve_special_varno((Node *) var, context, get_special_variable, - NULL); - return NULL; - } - - /* - * The planner will sometimes emit Vars referencing resjunk elements of a - * subquery's target list (this is currently only possible if it chooses - * to generate a "physical tlist" for a SubqueryScan or CteScan node). - * Although we prefer to print subquery-referencing Vars using the - * subquery's alias, that's not possible for resjunk items since they have - * no alias. So in that case, drill down to the subplan and print the - * contents of the referenced tlist item. This works because in a plan - * tree, such Vars can only occur in a SubqueryScan or CteScan node, and - * we'll have set dpns->inner_plan to reference the child plan node. - */ - if ((rte->rtekind == RTE_SUBQUERY || rte->rtekind == RTE_CTE) && - attnum > list_length(rte->eref->colnames) && - dpns->inner_plan) - { - TargetEntry *tle; - deparse_namespace save_dpns; - - tle = get_tle_by_resno(dpns->inner_tlist, attnum); - if (!tle) - elog(ERROR, "invalid attnum %d for relation \"%s\"", - attnum, rte->eref->aliasname); - - Assert(netlevelsup == 0); - push_child_plan(dpns, dpns->inner_plan, &save_dpns); - - /* - * Force parentheses because our caller probably assumed a Var is a - * simple expression. - */ - if (!IsA(tle->expr, Var)) - appendStringInfoChar(buf, '('); - get_rule_expr((Node *) tle->expr, context, true); - if (!IsA(tle->expr, Var)) - appendStringInfoChar(buf, ')'); - - pop_child_plan(dpns, &save_dpns); - return NULL; - } - - /* - * If it's an unnamed join, look at the expansion of the alias variable. - * If it's a simple reference to one of the input vars, then recursively - * print the name of that var instead. When it's not a simple reference, - * we have to just print the unqualified join column name. (This can only - * happen with "dangerous" merged columns in a JOIN USING; we took pains - * previously to make the unqualified column name unique in such cases.) - * - * This wouldn't work in decompiling plan trees, because we don't store - * joinaliasvars lists after planning; but a plan tree should never - * contain a join alias variable. - */ - if (rte->rtekind == RTE_JOIN && rte->alias == NULL) - { - if (rte->joinaliasvars == NIL) - elog(ERROR, "cannot decompile join alias var in plan tree"); - if (attnum > 0) - { - Var *aliasvar; - - aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1); - /* we intentionally don't strip implicit coercions here */ - if (aliasvar && IsA(aliasvar, Var)) - { - return get_variable(aliasvar, var->varlevelsup + levelsup, - istoplevel, context); - } - } - - /* - * Unnamed join has no refname. (Note: since it's unnamed, there is - * no way the user could have referenced it to create a whole-row Var - * for it. So we don't have to cover that case below.) - */ - Assert(refname == NULL); - } - - if (attnum == InvalidAttrNumber) - attname = NULL; - else if (attnum > 0) - { - /* Get column name to use from the colinfo struct */ - if (attnum > colinfo->num_cols) - elog(ERROR, "invalid attnum %d for relation \"%s\"", - attnum, rte->eref->aliasname); - attname = colinfo->colnames[attnum - 1]; - if (attname == NULL) /* dropped column? */ - elog(ERROR, "invalid attnum %d for relation \"%s\"", - attnum, rte->eref->aliasname); - } - else if (GetRangeTblKind(rte) == CITUS_RTE_SHARD) - { - /* System column on a Citus shard */ - attname = get_attname(rte->relid, attnum, false); - } - else - { - /* System column - name is fixed, get it from the catalog */ - attname = get_rte_attribute_name(rte, attnum); - } - - if (refname && (context->varprefix || attname == NULL)) - { - appendStringInfoString(buf, quote_identifier(refname)); - appendStringInfoChar(buf, '.'); - } - if (attname) - appendStringInfoString(buf, quote_identifier(attname)); - else - { - appendStringInfoChar(buf, '*'); - - if (istoplevel) - { - if (GetRangeTblKind(rte) == CITUS_RTE_SHARD) - { - /* use rel.*::shard_name instead of rel.*::table_name */ - appendStringInfo(buf, "::%s", - generate_rte_shard_name(rte)); - } - else - { - appendStringInfo(buf, "::%s", - format_type_with_typemod(var->vartype, - var->vartypmod)); - } - } - } - - return attname; -} - -/* - * Deparse a Var which references OUTER_VAR, INNER_VAR, or INDEX_VAR. This - * routine is actually a callback for get_special_varno, which handles finding - * the correct TargetEntry. We get the expression contained in that - * TargetEntry and just need to deparse it, a job we can throw back on - * get_rule_expr. - */ -static void -get_special_variable(Node *node, deparse_context *context, void *callback_arg) -{ - StringInfo buf = context->buf; - - /* - * For a non-Var referent, force parentheses because our caller probably - * assumed a Var is a simple expression. - */ - if (!IsA(node, Var)) - appendStringInfoChar(buf, '('); - get_rule_expr(node, context, true); - if (!IsA(node, Var)) - appendStringInfoChar(buf, ')'); -} - -/* - * Chase through plan references to special varnos (OUTER_VAR, INNER_VAR, - * INDEX_VAR) until we find a real Var or some kind of non-Var node; then, - * invoke the callback provided. - */ -static void -resolve_special_varno(Node *node, deparse_context *context, rsv_callback callback, void *callback_arg) -{ - Var *var; - deparse_namespace *dpns; - - /* This function is recursive, so let's be paranoid. */ - check_stack_depth(); - - /* If it's not a Var, invoke the callback. */ - if (!IsA(node, Var)) - { - (*callback) (node, context, callback_arg); - return; - } - - /* Find appropriate nesting depth */ - var = (Var *) node; - dpns = (deparse_namespace *) list_nth(context->namespaces, - var->varlevelsup); - - /* - * It's a special RTE, so recurse. - */ - if (var->varno == OUTER_VAR && dpns->outer_tlist) - { - TargetEntry *tle; - deparse_namespace save_dpns; - Bitmapset *save_appendparents; - - tle = get_tle_by_resno(dpns->outer_tlist, var->varattno); - if (!tle) - elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno); - - /* If we're descending to the first child of an Append or MergeAppend, - * update appendparents. This will affect deparsing of all Vars - * appearing within the eventually-resolved subexpression. - */ - save_appendparents = context->appendparents; - - if (IsA(dpns->plan, Append)) - context->appendparents = bms_union(context->appendparents, - ((Append *) dpns->plan)->apprelids); - else if (IsA(dpns->plan, MergeAppend)) - context->appendparents = bms_union(context->appendparents, - ((MergeAppend *) dpns->plan)->apprelids); - - push_child_plan(dpns, dpns->outer_plan, &save_dpns); - resolve_special_varno((Node *) tle->expr, context, - callback, callback_arg); - pop_child_plan(dpns, &save_dpns); - context->appendparents = save_appendparents; - return; - } - else if (var->varno == INNER_VAR && dpns->inner_tlist) - { - TargetEntry *tle; - deparse_namespace save_dpns; - - tle = get_tle_by_resno(dpns->inner_tlist, var->varattno); - if (!tle) - elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno); - - push_child_plan(dpns, dpns->inner_plan, &save_dpns); - resolve_special_varno((Node *) tle->expr, context, callback, callback_arg); - pop_child_plan(dpns, &save_dpns); - return; - } - else if (var->varno == INDEX_VAR && dpns->index_tlist) - { - TargetEntry *tle; - - tle = get_tle_by_resno(dpns->index_tlist, var->varattno); - if (!tle) - elog(ERROR, "bogus varattno for INDEX_VAR var: %d", var->varattno); - - resolve_special_varno((Node *) tle->expr, context, callback, callback_arg); - return; - } - else if (var->varno < 1 || var->varno > list_length(dpns->rtable)) - elog(ERROR, "bogus varno: %d", var->varno); - - /* Not special. Just invoke the callback. */ - (*callback) (node, context, callback_arg); -} - -/* - * Get the name of a field of an expression of composite type. The - * expression is usually a Var, but we handle other cases too. - * - * levelsup is an extra offset to interpret the Var's varlevelsup correctly. - * - * This is fairly straightforward when the expression has a named composite - * type; we need only look up the type in the catalogs. However, the type - * could also be RECORD. Since no actual table or view column is allowed to - * have type RECORD, a Var of type RECORD must refer to a JOIN or FUNCTION RTE - * or to a subquery output. We drill down to find the ultimate defining - * expression and attempt to infer the field name from it. We ereport if we - * can't determine the name. - * - * Similarly, a PARAM of type RECORD has to refer to some expression of - * a determinable composite type. - */ -static const char * -get_name_for_var_field(Var *var, int fieldno, - int levelsup, deparse_context *context) -{ - RangeTblEntry *rte; - AttrNumber attnum; - int netlevelsup; - deparse_namespace *dpns; - Index varno; - AttrNumber varattno; - TupleDesc tupleDesc; - Node *expr; - - /* - * If it's a RowExpr that was expanded from a whole-row Var, use the - * column names attached to it. - */ - if (IsA(var, RowExpr)) - { - RowExpr *r = (RowExpr *) var; - - if (fieldno > 0 && fieldno <= list_length(r->colnames)) - return strVal(list_nth(r->colnames, fieldno - 1)); - } - - /* - * If it's a Param of type RECORD, try to find what the Param refers to. - */ - if (IsA(var, Param)) - { - Param *param = (Param *) var; - ListCell *ancestor_cell; - - expr = find_param_referent(param, context, &dpns, &ancestor_cell); - if (expr) - { - /* Found a match, so recurse to decipher the field name */ - deparse_namespace save_dpns; - const char *result; - - push_ancestor_plan(dpns, ancestor_cell, &save_dpns); - result = get_name_for_var_field((Var *) expr, fieldno, - 0, context); - pop_ancestor_plan(dpns, &save_dpns); - return result; - } - } - - /* - * If it's a Var of type RECORD, we have to find what the Var refers to; - * if not, we can use get_expr_result_tupdesc(). - */ - if (!IsA(var, Var) || - var->vartype != RECORDOID) - { - tupleDesc = get_expr_result_tupdesc((Node *) var, false); - /* Got the tupdesc, so we can extract the field name */ - Assert(fieldno >= 1 && fieldno <= tupleDesc->natts); - return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname); - } - - /* Find appropriate nesting depth */ - netlevelsup = var->varlevelsup + levelsup; - if (netlevelsup >= list_length(context->namespaces)) - elog(ERROR, "bogus varlevelsup: %d offset %d", - var->varlevelsup, levelsup); - dpns = (deparse_namespace *) list_nth(context->namespaces, - netlevelsup); - - varno = var->varno; - varattno = var->varattno; - - if (var->varnosyn > 0 && var->varnosyn <= list_length(dpns->rtable) && dpns->plan == NULL) { - rte = rt_fetch(var->varnosyn, dpns->rtable); - - /* - * if the rte var->varnosyn points to is not a regular table and it is a join - * then the correct relname will be found with var->varnosyn and var->varattnosyn - */ - if (rte->rtekind == RTE_JOIN && rte->relid == 0 && var->varnosyn != var->varno) { - varno = var->varnosyn; - varattno = var->varattnosyn; - } - } - - /* - * Try to find the relevant RTE in this rtable. In a plan tree, it's - * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig - * down into the subplans, or INDEX_VAR, which is resolved similarly. - */ - if (varno >= 1 && varno <= list_length(dpns->rtable)) - { - rte = rt_fetch(varno, dpns->rtable); - attnum = varattno; - } - else if (varno == OUTER_VAR && dpns->outer_tlist) - { - TargetEntry *tle; - deparse_namespace save_dpns; - const char *result; - - tle = get_tle_by_resno(dpns->outer_tlist, varattno); - if (!tle) - elog(ERROR, "bogus varattno for OUTER_VAR var: %d", varattno); - - Assert(netlevelsup == 0); - push_child_plan(dpns, dpns->outer_plan, &save_dpns); - - result = get_name_for_var_field((Var *) tle->expr, fieldno, - levelsup, context); - - pop_child_plan(dpns, &save_dpns); - return result; - } - else if (varno == INNER_VAR && dpns->inner_tlist) - { - TargetEntry *tle; - deparse_namespace save_dpns; - const char *result; - - tle = get_tle_by_resno(dpns->inner_tlist, varattno); - if (!tle) - elog(ERROR, "bogus varattno for INNER_VAR var: %d", varattno); - - Assert(netlevelsup == 0); - push_child_plan(dpns, dpns->inner_plan, &save_dpns); - - result = get_name_for_var_field((Var *) tle->expr, fieldno, - levelsup, context); - - pop_child_plan(dpns, &save_dpns); - return result; - } - else if (varno == INDEX_VAR && dpns->index_tlist) - { - TargetEntry *tle; - const char *result; - - tle = get_tle_by_resno(dpns->index_tlist, varattno); - if (!tle) - elog(ERROR, "bogus varattno for INDEX_VAR var: %d", varattno); - - Assert(netlevelsup == 0); - - result = get_name_for_var_field((Var *) tle->expr, fieldno, - levelsup, context); - - return result; - } - else - { - elog(ERROR, "bogus varno: %d", varno); - return NULL; /* keep compiler quiet */ - } - - if (attnum == InvalidAttrNumber) - { - /* Var is whole-row reference to RTE, so select the right field */ - return get_rte_attribute_name(rte, fieldno); - } - - /* - * This part has essentially the same logic as the parser's - * expandRecordVariable() function, but we are dealing with a different - * representation of the input context, and we only need one field name - * not a TupleDesc. Also, we need special cases for finding subquery and - * CTE subplans when deparsing Plan trees. - */ - expr = (Node *) var; /* default if we can't drill down */ - - switch (rte->rtekind) - { - case RTE_RELATION: - case RTE_VALUES: - case RTE_NAMEDTUPLESTORE: - case RTE_RESULT: - - /* - * This case should not occur: a column of a table or values list - * shouldn't have type RECORD. Fall through and fail (most - * likely) at the bottom. - */ - break; - case RTE_SUBQUERY: - /* Subselect-in-FROM: examine sub-select's output expr */ - { - if (rte->subquery) - { - TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList, - attnum); - - if (ste == NULL || ste->resjunk) - elog(ERROR, "subquery %s does not have attribute %d", - rte->eref->aliasname, attnum); - expr = (Node *) ste->expr; - if (IsA(expr, Var)) - { - /* - * Recurse into the sub-select to see what its Var - * refers to. We have to build an additional level of - * namespace to keep in step with varlevelsup in the - * subselect. - */ - deparse_namespace mydpns; - const char *result; - - set_deparse_for_query(&mydpns, rte->subquery, - context->namespaces); - - context->namespaces = lcons(&mydpns, - context->namespaces); - - result = get_name_for_var_field((Var *) expr, fieldno, - 0, context); - - context->namespaces = - list_delete_first(context->namespaces); - - return result; - } - /* else fall through to inspect the expression */ - } - else - { - /* - * We're deparsing a Plan tree so we don't have complete - * RTE entries (in particular, rte->subquery is NULL). But - * the only place we'd see a Var directly referencing a - * SUBQUERY RTE is in a SubqueryScan plan node, and we can - * look into the child plan's tlist instead. - */ - TargetEntry *tle; - deparse_namespace save_dpns; - const char *result; - - if (!dpns->inner_plan) - elog(ERROR, "failed to find plan for subquery %s", - rte->eref->aliasname); - tle = get_tle_by_resno(dpns->inner_tlist, attnum); - if (!tle) - elog(ERROR, "bogus varattno for subquery var: %d", - attnum); - Assert(netlevelsup == 0); - push_child_plan(dpns, dpns->inner_plan, &save_dpns); - - result = get_name_for_var_field((Var *) tle->expr, fieldno, - levelsup, context); - - pop_child_plan(dpns, &save_dpns); - return result; - } - } - break; - case RTE_JOIN: - /* Join RTE --- recursively inspect the alias variable */ - if (rte->joinaliasvars == NIL) - elog(ERROR, "cannot decompile join alias var in plan tree"); - Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars)); - expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1); - Assert(expr != NULL); - /* we intentionally don't strip implicit coercions here */ - if (IsA(expr, Var)) - return get_name_for_var_field((Var *) expr, fieldno, - var->varlevelsup + levelsup, - context); - /* else fall through to inspect the expression */ - break; - case RTE_FUNCTION: - case RTE_TABLEFUNC: - - /* - * We couldn't get here unless a function is declared with one of - * its result columns as RECORD, which is not allowed. - */ - break; - case RTE_CTE: - /* CTE reference: examine subquery's output expr */ - { - CommonTableExpr *cte = NULL; - Index ctelevelsup; - ListCell *lc; - - /* - * Try to find the referenced CTE using the namespace stack. - */ - ctelevelsup = rte->ctelevelsup + netlevelsup; - if (ctelevelsup >= list_length(context->namespaces)) - lc = NULL; - else - { - deparse_namespace *ctedpns; - - ctedpns = (deparse_namespace *) - list_nth(context->namespaces, ctelevelsup); - foreach(lc, ctedpns->ctes) - { - cte = (CommonTableExpr *) lfirst(lc); - if (strcmp(cte->ctename, rte->ctename) == 0) - break; - } - } - if (lc != NULL) - { - Query *ctequery = (Query *) cte->ctequery; - TargetEntry *ste = get_tle_by_resno(GetCTETargetList(cte), - attnum); - - if (ste == NULL || ste->resjunk) - elog(ERROR, "subquery %s does not have attribute %d", - rte->eref->aliasname, attnum); - expr = (Node *) ste->expr; - if (IsA(expr, Var)) - { - /* - * Recurse into the CTE to see what its Var refers to. - * We have to build an additional level of namespace - * to keep in step with varlevelsup in the CTE. - * Furthermore it could be an outer CTE, so we may - * have to delete some levels of namespace. - */ - List *save_nslist = context->namespaces; - List *new_nslist; - deparse_namespace mydpns; - const char *result; - - set_deparse_for_query(&mydpns, ctequery, - context->namespaces); - - new_nslist = list_copy_tail(context->namespaces, - ctelevelsup); - context->namespaces = lcons(&mydpns, new_nslist); - - result = get_name_for_var_field((Var *) expr, fieldno, - 0, context); - - context->namespaces = save_nslist; - - return result; - } - /* else fall through to inspect the expression */ - } - else - { - /* - * We're deparsing a Plan tree so we don't have a CTE - * list. But the only place we'd see a Var directly - * referencing a CTE RTE is in a CteScan plan node, and we - * can look into the subplan's tlist instead. - */ - TargetEntry *tle; - deparse_namespace save_dpns; - const char *result; - - if (!dpns->inner_plan) - elog(ERROR, "failed to find plan for CTE %s", - rte->eref->aliasname); - tle = get_tle_by_resno(dpns->inner_tlist, attnum); - if (!tle) - elog(ERROR, "bogus varattno for subquery var: %d", - attnum); - Assert(netlevelsup == 0); - push_child_plan(dpns, dpns->inner_plan, &save_dpns); - - result = get_name_for_var_field((Var *) tle->expr, fieldno, - levelsup, context); - - pop_child_plan(dpns, &save_dpns); - return result; - } - } - break; - } - - /* - * We now have an expression we can't expand any more, so see if - * get_expr_result_tupdesc() can do anything with it. - */ - tupleDesc = get_expr_result_tupdesc(expr, false); - /* Got the tupdesc, so we can extract the field name */ - Assert(fieldno >= 1 && fieldno <= tupleDesc->natts); - return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname); -} - -/* - * Try to find the referenced expression for a PARAM_EXEC Param that might - * reference a parameter supplied by an upper NestLoop or SubPlan plan node. - * - * If successful, return the expression and set *dpns_p and *ancestor_cell_p - * appropriately for calling push_ancestor_plan(). If no referent can be - * found, return NULL. - */ -static Node * -find_param_referent(Param *param, deparse_context *context, - deparse_namespace **dpns_p, ListCell **ancestor_cell_p) -{ - /* Initialize output parameters to prevent compiler warnings */ - *dpns_p = NULL; - *ancestor_cell_p = NULL; - - /* - * If it's a PARAM_EXEC parameter, look for a matching NestLoopParam or - * SubPlan argument. This will necessarily be in some ancestor of the - * current expression's Plan. - */ - if (param->paramkind == PARAM_EXEC) - { - deparse_namespace *dpns; - Plan *child_plan; - bool in_same_plan_level; - ListCell *lc; - - dpns = (deparse_namespace *) linitial(context->namespaces); - child_plan = dpns->plan; - in_same_plan_level = true; - - foreach(lc, dpns->ancestors) - { - Node *ancestor = (Node *) lfirst(lc); - ListCell *lc2; - - /* - * NestLoops transmit params to their inner child only; also, once - * we've crawled up out of a subplan, this couldn't possibly be - * the right match. - */ - if (IsA(ancestor, NestLoop) && - child_plan == innerPlan(ancestor) && - in_same_plan_level) - { - NestLoop *nl = (NestLoop *) ancestor; - - foreach(lc2, nl->nestParams) - { - NestLoopParam *nlp = (NestLoopParam *) lfirst(lc2); - - if (nlp->paramno == param->paramid) - { - /* Found a match, so return it */ - *dpns_p = dpns; - *ancestor_cell_p = lc; - return (Node *) nlp->paramval; - } - } - } - - /* - * Check to see if we're crawling up from a subplan. - */ - if(IsA(ancestor, SubPlan)) - { - SubPlan *subplan = (SubPlan *) ancestor; - ListCell *lc3; - ListCell *lc4; - - /* Matched subplan, so check its arguments */ - forboth(lc3, subplan->parParam, lc4, subplan->args) - { - int paramid = lfirst_int(lc3); - Node *arg = (Node *) lfirst(lc4); - - if (paramid == param->paramid) - { - /* - * Found a match, so return it. But, since Vars in - * the arg are to be evaluated in the surrounding - * context, we have to point to the next ancestor item - * that is *not* a SubPlan. - */ - ListCell *rest; - - for_each_cell(rest, dpns->ancestors, - lnext(dpns->ancestors, lc)) - { - Node *ancestor2 = (Node *) lfirst(rest); - - if (!IsA(ancestor2, SubPlan)) - { - *dpns_p = dpns; - *ancestor_cell_p = rest; - return arg; - } - } - elog(ERROR, "SubPlan cannot be outermost ancestor"); - } - } - - /* We have emerged from a subplan. */ - in_same_plan_level = false; - - /* SubPlan isn't a kind of Plan, so skip the rest */ - continue; - } - - /* - * Check to see if we're emerging from an initplan of the current - * ancestor plan. Initplans never have any parParams, so no need - * to search that list, but we need to know if we should reset - * in_same_plan_level. - */ - foreach(lc2, ((Plan *) ancestor)->initPlan) - { - SubPlan *subplan = lfirst_node(SubPlan, lc2); - - if (child_plan != (Plan *) list_nth(dpns->subplans, - subplan->plan_id - 1)) - continue; - - /* No parameters to be had here. */ - Assert(subplan->parParam == NIL); - - /* We have emerged from an initplan. */ - in_same_plan_level = false; - break; - } - - /* No luck, crawl up to next ancestor */ - child_plan = (Plan *) ancestor; - } - } - - /* No referent found */ - return NULL; -} - -/* - * Display a Param appropriately. - */ -static void -get_parameter(Param *param, deparse_context *context) -{ - Node *expr; - deparse_namespace *dpns; - ListCell *ancestor_cell; - - /* - * If it's a PARAM_EXEC parameter, try to locate the expression from which - * the parameter was computed. Note that failing to find a referent isn't - * an error, since the Param might well be a subplan output rather than an - * input. - */ - expr = find_param_referent(param, context, &dpns, &ancestor_cell); - if (expr) - { - /* Found a match, so print it */ - deparse_namespace save_dpns; - bool save_varprefix; - bool need_paren; - - /* Switch attention to the ancestor plan node */ - push_ancestor_plan(dpns, ancestor_cell, &save_dpns); - - /* - * Force prefixing of Vars, since they won't belong to the relation - * being scanned in the original plan node. - */ - save_varprefix = context->varprefix; - context->varprefix = true; - - /* - * A Param's expansion is typically a Var, Aggref, or upper-level - * Param, which wouldn't need extra parentheses. Otherwise, insert - * parens to ensure the expression looks atomic. - */ - need_paren = !(IsA(expr, Var) || - IsA(expr, Aggref) || - IsA(expr, Param)); - if (need_paren) - appendStringInfoChar(context->buf, '('); - - get_rule_expr(expr, context, false); - - if (need_paren) - appendStringInfoChar(context->buf, ')'); - - context->varprefix = save_varprefix; - - pop_ancestor_plan(dpns, &save_dpns); - - return; - } - - /* - * If it's an external parameter, see if the outermost namespace provides - * function argument names. - */ - if (param->paramkind == PARAM_EXTERN) - { - dpns = lfirst(list_tail(context->namespaces)); - if (dpns->argnames) - { - char *argname = dpns->argnames[param->paramid - 1]; - - if (argname) - { - bool should_qualify = false; - ListCell *lc; - - /* - * Qualify the parameter name if there are any other deparse - * namespaces with range tables. This avoids qualifying in - * trivial cases like "RETURN a + b", but makes it safe in all - * other cases. - */ - foreach(lc, context->namespaces) - { - deparse_namespace *dp_ns = lfirst(lc); - - if (list_length(dp_ns->rtable_names) > 0) - { - should_qualify = true; - break; - } - } - if (should_qualify) - { - appendStringInfoString(context->buf, quote_identifier(dpns->funcname)); - appendStringInfoChar(context->buf, '.'); - } - - appendStringInfoString(context->buf, quote_identifier(argname)); - return; - } - } - } - - /* - * Not PARAM_EXEC, or couldn't find referent: for base types just print $N. - * For composite types, add cast to the parameter to ease remote node detect - * the type. - */ - if (param->paramtype >= FirstNormalObjectId) - { - char *typeName = format_type_with_typemod(param->paramtype, param->paramtypmod); - - appendStringInfo(context->buf, "$%d::%s", param->paramid, typeName); - } - else - { - appendStringInfo(context->buf, "$%d", param->paramid); - } -} - -/* - * get_simple_binary_op_name - * - * helper function for isSimpleNode - * will return single char binary operator name, or NULL if it's not - */ -static const char * -get_simple_binary_op_name(OpExpr *expr) -{ - List *args = expr->args; - - if (list_length(args) == 2) - { - /* binary operator */ - Node *arg1 = (Node *) linitial(args); - Node *arg2 = (Node *) lsecond(args); - const char *op; - - op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2)); - if (strlen(op) == 1) - return op; - } - return NULL; -} - - -/* - * isSimpleNode - check if given node is simple (doesn't need parenthesizing) - * - * true : simple in the context of parent node's type - * false : not simple - */ -static bool -isSimpleNode(Node *node, Node *parentNode, int prettyFlags) -{ - if (!node) - return false; - - switch (nodeTag(node)) - { - case T_Var: - case T_Const: - case T_Param: - case T_CoerceToDomainValue: - case T_SetToDefault: - case T_CurrentOfExpr: - /* single words: always simple */ - return true; - - case T_SubscriptingRef: - case T_ArrayExpr: - case T_RowExpr: - case T_CoalesceExpr: - case T_MinMaxExpr: - case T_SQLValueFunction: - case T_XmlExpr: - case T_NextValueExpr: - case T_NullIfExpr: - case T_Aggref: - case T_WindowFunc: - case T_FuncExpr: - /* function-like: name(..) or name[..] */ - return true; - - /* CASE keywords act as parentheses */ - case T_CaseExpr: - return true; - - case T_FieldSelect: - - /* - * appears simple since . has top precedence, unless parent is - * T_FieldSelect itself! - */ - return (IsA(parentNode, FieldSelect) ? false : true); - - case T_FieldStore: - - /* - * treat like FieldSelect (probably doesn't matter) - */ - return (IsA(parentNode, FieldStore) ? false : true); - - case T_CoerceToDomain: - /* maybe simple, check args */ - return isSimpleNode((Node *) ((CoerceToDomain *) node)->arg, - node, prettyFlags); - case T_RelabelType: - return isSimpleNode((Node *) ((RelabelType *) node)->arg, - node, prettyFlags); - case T_CoerceViaIO: - return isSimpleNode((Node *) ((CoerceViaIO *) node)->arg, - node, prettyFlags); - case T_ArrayCoerceExpr: - return isSimpleNode((Node *) ((ArrayCoerceExpr *) node)->arg, - node, prettyFlags); - case T_ConvertRowtypeExpr: - return isSimpleNode((Node *) ((ConvertRowtypeExpr *) node)->arg, - node, prettyFlags); - - case T_OpExpr: - { - /* depends on parent node type; needs further checking */ - if (prettyFlags & PRETTYFLAG_PAREN && IsA(parentNode, OpExpr)) - { - const char *op; - const char *parentOp; - bool is_lopriop; - bool is_hipriop; - bool is_lopriparent; - bool is_hipriparent; - - op = get_simple_binary_op_name((OpExpr *) node); - if (!op) - return false; - - /* We know only the basic operators + - and * / % */ - is_lopriop = (strchr("+-", *op) != NULL); - is_hipriop = (strchr("*/%", *op) != NULL); - if (!(is_lopriop || is_hipriop)) - return false; - - parentOp = get_simple_binary_op_name((OpExpr *) parentNode); - if (!parentOp) - return false; - - is_lopriparent = (strchr("+-", *parentOp) != NULL); - is_hipriparent = (strchr("*/%", *parentOp) != NULL); - if (!(is_lopriparent || is_hipriparent)) - return false; - - if (is_hipriop && is_lopriparent) - return true; /* op binds tighter than parent */ - - if (is_lopriop && is_hipriparent) - return false; - - /* - * Operators are same priority --- can skip parens only if - * we have (a - b) - c, not a - (b - c). - */ - if (node == (Node *) linitial(((OpExpr *) parentNode)->args)) - return true; - - return false; - } - /* else do the same stuff as for T_SubLink et al. */ - } - /* FALLTHROUGH */ - - case T_SubLink: - case T_NullTest: - case T_BooleanTest: - case T_DistinctExpr: - switch (nodeTag(parentNode)) - { - case T_FuncExpr: - { - /* special handling for casts */ - CoercionForm type = ((FuncExpr *) parentNode)->funcformat; - - if (type == COERCE_EXPLICIT_CAST || - type == COERCE_IMPLICIT_CAST) - return false; - return true; /* own parentheses */ - } - case T_BoolExpr: /* lower precedence */ - case T_SubscriptingRef: /* other separators */ - case T_ArrayExpr: /* other separators */ - case T_RowExpr: /* other separators */ - case T_CoalesceExpr: /* own parentheses */ - case T_MinMaxExpr: /* own parentheses */ - case T_XmlExpr: /* own parentheses */ - case T_NullIfExpr: /* other separators */ - case T_Aggref: /* own parentheses */ - case T_WindowFunc: /* own parentheses */ - case T_CaseExpr: /* other separators */ - return true; - default: - return false; - } - - case T_BoolExpr: - switch (nodeTag(parentNode)) - { - case T_BoolExpr: - if (prettyFlags & PRETTYFLAG_PAREN) - { - BoolExprType type; - BoolExprType parentType; - - type = ((BoolExpr *) node)->boolop; - parentType = ((BoolExpr *) parentNode)->boolop; - switch (type) - { - case NOT_EXPR: - case AND_EXPR: - if (parentType == AND_EXPR || parentType == OR_EXPR) - return true; - break; - case OR_EXPR: - if (parentType == OR_EXPR) - return true; - break; - } - } - return false; - case T_FuncExpr: - { - /* special handling for casts */ - CoercionForm type = ((FuncExpr *) parentNode)->funcformat; - - if (type == COERCE_EXPLICIT_CAST || - type == COERCE_IMPLICIT_CAST) - return false; - return true; /* own parentheses */ - } - case T_SubscriptingRef: /* other separators */ - case T_ArrayExpr: /* other separators */ - case T_RowExpr: /* other separators */ - case T_CoalesceExpr: /* own parentheses */ - case T_MinMaxExpr: /* own parentheses */ - case T_XmlExpr: /* own parentheses */ - case T_NullIfExpr: /* other separators */ - case T_Aggref: /* own parentheses */ - case T_WindowFunc: /* own parentheses */ - case T_CaseExpr: /* other separators */ - return true; - default: - return false; - } - - default: - break; - } - /* those we don't know: in dubio complexo */ - return false; -} - - -/* - * appendContextKeyword - append a keyword to buffer - * - * If prettyPrint is enabled, perform a line break, and adjust indentation. - * Otherwise, just append the keyword. - */ -static void -appendContextKeyword(deparse_context *context, const char *str, - int indentBefore, int indentAfter, int indentPlus) -{ - StringInfo buf = context->buf; - - if (PRETTY_INDENT(context)) - { - int indentAmount; - - context->indentLevel += indentBefore; - - /* remove any trailing spaces currently in the buffer ... */ - removeStringInfoSpaces(buf); - /* ... then add a newline and some spaces */ - appendStringInfoChar(buf, '\n'); - - if (context->indentLevel < PRETTYINDENT_LIMIT) - indentAmount = Max(context->indentLevel, 0) + indentPlus; - else - { - /* - * If we're indented more than PRETTYINDENT_LIMIT characters, try - * to conserve horizontal space by reducing the per-level - * indentation. For best results the scale factor here should - * divide all the indent amounts that get added to indentLevel - * (PRETTYINDENT_STD, etc). It's important that the indentation - * not grow unboundedly, else deeply-nested trees use O(N^2) - * whitespace; so we also wrap modulo PRETTYINDENT_LIMIT. - */ - indentAmount = PRETTYINDENT_LIMIT + - (context->indentLevel - PRETTYINDENT_LIMIT) / - (PRETTYINDENT_STD / 2); - indentAmount %= PRETTYINDENT_LIMIT; - /* scale/wrap logic affects indentLevel, but not indentPlus */ - indentAmount += indentPlus; - } - appendStringInfoSpaces(buf, indentAmount); - - appendStringInfoString(buf, str); - - context->indentLevel += indentAfter; - if (context->indentLevel < 0) - context->indentLevel = 0; - } - else - appendStringInfoString(buf, str); -} - -/* - * removeStringInfoSpaces - delete trailing spaces from a buffer. - * - * Possibly this should move to stringinfo.c at some point. - */ -static void -removeStringInfoSpaces(StringInfo str) -{ - while (str->len > 0 && str->data[str->len - 1] == ' ') - str->data[--(str->len)] = '\0'; -} - - -/* - * get_rule_expr_paren - deparse expr using get_rule_expr, - * embracing the string with parentheses if necessary for prettyPrint. - * - * Never embrace if prettyFlags=0, because it's done in the calling node. - * - * Any node that does *not* embrace its argument node by sql syntax (with - * parentheses, non-operator keywords like CASE/WHEN/ON, or comma etc) should - * use get_rule_expr_paren instead of get_rule_expr so parentheses can be - * added. - */ -static void -get_rule_expr_paren(Node *node, deparse_context *context, - bool showimplicit, Node *parentNode) -{ - bool need_paren; - - need_paren = PRETTY_PAREN(context) && - !isSimpleNode(node, parentNode, context->prettyFlags); - - if (need_paren) - appendStringInfoChar(context->buf, '('); - - get_rule_expr(node, context, showimplicit); - - if (need_paren) - appendStringInfoChar(context->buf, ')'); -} - - -/* ---------- - * get_rule_expr - Parse back an expression - * - * Note: showimplicit determines whether we display any implicit cast that - * is present at the top of the expression tree. It is a passed argument, - * not a field of the context struct, because we change the value as we - * recurse down into the expression. In general we suppress implicit casts - * when the result type is known with certainty (eg, the arguments of an - * OR must be boolean). We display implicit casts for arguments of functions - * and operators, since this is needed to be certain that the same function - * or operator will be chosen when the expression is re-parsed. - * ---------- - */ -static void -get_rule_expr(Node *node, deparse_context *context, - bool showimplicit) -{ - StringInfo buf = context->buf; - - if (node == NULL) - return; - - /* Guard against excessively long or deeply-nested queries */ - CHECK_FOR_INTERRUPTS(); - check_stack_depth(); - - /* - * Each level of get_rule_expr must emit an indivisible term - * (parenthesized if necessary) to ensure result is reparsed into the same - * expression tree. The only exception is that when the input is a List, - * we emit the component items comma-separated with no surrounding - * decoration; this is convenient for most callers. - */ - switch (nodeTag(node)) - { - case T_Var: - (void) get_variable((Var *) node, 0, false, context); - break; - - case T_Const: - get_const_expr((Const *) node, context, 0); - break; - - case T_Param: - get_parameter((Param *) node, context); - break; - - case T_Aggref: - get_agg_expr((Aggref *) node, context, (Aggref *) node); - break; - - case T_GroupingFunc: - { - GroupingFunc *gexpr = (GroupingFunc *) node; - - appendStringInfoString(buf, "GROUPING("); - get_rule_expr((Node *) gexpr->args, context, true); - appendStringInfoChar(buf, ')'); - } - break; - - case T_WindowFunc: - get_windowfunc_expr((WindowFunc *) node, context); - break; - - case T_SubscriptingRef: - { - SubscriptingRef *sbsref = (SubscriptingRef *) node; - bool need_parens; - - /* - * If the argument is a CaseTestExpr, we must be inside a - * FieldStore, ie, we are assigning to an element of an array - * within a composite column. Since we already punted on - * displaying the FieldStore's target information, just punt - * here too, and display only the assignment source - * expression. - */ - if (IsA(sbsref->refexpr, CaseTestExpr)) - { - Assert(sbsref->refassgnexpr); - get_rule_expr((Node *) sbsref->refassgnexpr, - context, showimplicit); - break; - } - - /* - * Parenthesize the argument unless it's a simple Var or a - * FieldSelect. (In particular, if it's another - * SubscriptingRef, we *must* parenthesize to avoid - * confusion.) - */ - need_parens = !IsA(sbsref->refexpr, Var) && - !IsA(sbsref->refexpr, FieldSelect); - if (need_parens) - appendStringInfoChar(buf, '('); - get_rule_expr((Node *) sbsref->refexpr, context, showimplicit); - if (need_parens) - appendStringInfoChar(buf, ')'); - - /* - * If there's a refassgnexpr, we want to print the node in the - * format "container[subscripts] := refassgnexpr". This is - * not legal SQL, so decompilation of INSERT or UPDATE - * statements should always use processIndirection as part of - * the statement-level syntax. We should only see this when - * EXPLAIN tries to print the targetlist of a plan resulting - * from such a statement. - */ - if (sbsref->refassgnexpr) - { - Node *refassgnexpr; - - /* - * Use processIndirection to print this node's subscripts - * as well as any additional field selections or - * subscripting in immediate descendants. It returns the - * RHS expr that is actually being "assigned". - */ - refassgnexpr = processIndirection(node, context); - appendStringInfoString(buf, " := "); - get_rule_expr(refassgnexpr, context, showimplicit); - } - else - { - /* Just an ordinary container fetch, so print subscripts */ - printSubscripts(sbsref, context); - } - } - break; - - case T_FuncExpr: - get_func_expr((FuncExpr *) node, context, showimplicit); - break; - - case T_NamedArgExpr: - { - NamedArgExpr *na = (NamedArgExpr *) node; - - appendStringInfo(buf, "%s => ", quote_identifier(na->name)); - get_rule_expr((Node *) na->arg, context, showimplicit); - } - break; - - case T_OpExpr: - get_oper_expr((OpExpr *) node, context); - break; - - case T_DistinctExpr: - { - DistinctExpr *expr = (DistinctExpr *) node; - List *args = expr->args; - Node *arg1 = (Node *) linitial(args); - Node *arg2 = (Node *) lsecond(args); - - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, '('); - get_rule_expr_paren(arg1, context, true, node); - appendStringInfoString(buf, " IS DISTINCT FROM "); - get_rule_expr_paren(arg2, context, true, node); - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, ')'); - } - break; - - case T_NullIfExpr: - { - NullIfExpr *nullifexpr = (NullIfExpr *) node; - - appendStringInfoString(buf, "NULLIF("); - get_rule_expr((Node *) nullifexpr->args, context, true); - appendStringInfoChar(buf, ')'); - } - break; - - case T_ScalarArrayOpExpr: - { - ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node; - List *args = expr->args; - Node *arg1 = (Node *) linitial(args); - Node *arg2 = (Node *) lsecond(args); - - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, '('); - get_rule_expr_paren(arg1, context, true, node); - appendStringInfo(buf, " %s %s (", - generate_operator_name(expr->opno, - exprType(arg1), - get_base_element_type(exprType(arg2))), - expr->useOr ? "ANY" : "ALL"); - get_rule_expr_paren(arg2, context, true, node); - - /* - * There's inherent ambiguity in "x op ANY/ALL (y)" when y is - * a bare sub-SELECT. Since we're here, the sub-SELECT must - * be meant as a scalar sub-SELECT yielding an array value to - * be used in ScalarArrayOpExpr; but the grammar will - * preferentially interpret such a construct as an ANY/ALL - * SubLink. To prevent misparsing the output that way, insert - * a dummy coercion (which will be stripped by parse analysis, - * so no inefficiency is added in dump and reload). This is - * indeed most likely what the user wrote to get the construct - * accepted in the first place. - */ - if (IsA(arg2, SubLink) && - ((SubLink *) arg2)->subLinkType == EXPR_SUBLINK) - appendStringInfo(buf, "::%s", - format_type_with_typemod(exprType(arg2), - exprTypmod(arg2))); - appendStringInfoChar(buf, ')'); - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, ')'); - } - break; - - case T_BoolExpr: - { - BoolExpr *expr = (BoolExpr *) node; - Node *first_arg = linitial(expr->args); - ListCell *arg; - - switch (expr->boolop) - { - case AND_EXPR: - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, '('); - get_rule_expr_paren(first_arg, context, - false, node); - for_each_from(arg, expr->args, 1) - { - appendStringInfoString(buf, " AND "); - get_rule_expr_paren((Node *) lfirst(arg), context, - false, node); - } - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, ')'); - break; - - case OR_EXPR: - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, '('); - get_rule_expr_paren(first_arg, context, - false, node); - for_each_from(arg, expr->args, 1) - { - appendStringInfoString(buf, " OR "); - get_rule_expr_paren((Node *) lfirst(arg), context, - false, node); - } - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, ')'); - break; - - case NOT_EXPR: - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, '('); - appendStringInfoString(buf, "NOT "); - get_rule_expr_paren(first_arg, context, - false, node); - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, ')'); - break; - - default: - elog(ERROR, "unrecognized boolop: %d", - (int) expr->boolop); - } - } - break; - - case T_SubLink: - get_sublink_expr((SubLink *) node, context); - break; - - case T_SubPlan: - { - SubPlan *subplan = (SubPlan *) node; - - /* - * We cannot see an already-planned subplan in rule deparsing, - * only while EXPLAINing a query plan. We don't try to - * reconstruct the original SQL, just reference the subplan - * that appears elsewhere in EXPLAIN's result. - */ - if (subplan->useHashTable) - appendStringInfo(buf, "(hashed %s)", subplan->plan_name); - else - appendStringInfo(buf, "(%s)", subplan->plan_name); - } - break; - - case T_AlternativeSubPlan: - { - AlternativeSubPlan *asplan = (AlternativeSubPlan *) node; - ListCell *lc; - - /* - * This case cannot be reached in normal usage, since no - * AlternativeSubPlan can appear either in parsetrees or - * finished plan trees. We keep it just in case somebody - * wants to use this code to print planner data structures. - */ - appendStringInfoString(buf, "(alternatives: "); - foreach(lc, asplan->subplans) - { - SubPlan *splan = lfirst_node(SubPlan, lc); - - if (splan->useHashTable) - appendStringInfo(buf, "hashed %s", splan->plan_name); - else - appendStringInfoString(buf, splan->plan_name); - if (lnext(asplan->subplans, lc)) - appendStringInfoString(buf, " or "); - } - appendStringInfoChar(buf, ')'); - } - break; - - case T_FieldSelect: - { - FieldSelect *fselect = (FieldSelect *) node; - Node *arg = (Node *) fselect->arg; - int fno = fselect->fieldnum; - const char *fieldname; - bool need_parens; - - /* - * Parenthesize the argument unless it's an SubscriptingRef or - * another FieldSelect. Note in particular that it would be - * WRONG to not parenthesize a Var argument; simplicity is not - * the issue here, having the right number of names is. - */ - need_parens = !IsA(arg, SubscriptingRef) && - !IsA(arg, FieldSelect); - if (need_parens) - appendStringInfoChar(buf, '('); - get_rule_expr(arg, context, true); - if (need_parens) - appendStringInfoChar(buf, ')'); - - /* - * Get and print the field name. - */ - fieldname = get_name_for_var_field((Var *) arg, fno, - 0, context); - appendStringInfo(buf, ".%s", quote_identifier(fieldname)); - } - break; - - case T_FieldStore: - { - FieldStore *fstore = (FieldStore *) node; - bool need_parens; - - /* - * There is no good way to represent a FieldStore as real SQL, - * so decompilation of INSERT or UPDATE statements should - * always use processIndirection as part of the - * statement-level syntax. We should only get here when - * EXPLAIN tries to print the targetlist of a plan resulting - * from such a statement. The plan case is even harder than - * ordinary rules would be, because the planner tries to - * collapse multiple assignments to the same field or subfield - * into one FieldStore; so we can see a list of target fields - * not just one, and the arguments could be FieldStores - * themselves. We don't bother to try to print the target - * field names; we just print the source arguments, with a - * ROW() around them if there's more than one. This isn't - * terribly complete, but it's probably good enough for - * EXPLAIN's purposes; especially since anything more would be - * either hopelessly confusing or an even poorer - * representation of what the plan is actually doing. - */ - need_parens = (list_length(fstore->newvals) != 1); - if (need_parens) - appendStringInfoString(buf, "ROW("); - get_rule_expr((Node *) fstore->newvals, context, showimplicit); - if (need_parens) - appendStringInfoChar(buf, ')'); - } - break; - - case T_RelabelType: - { - RelabelType *relabel = (RelabelType *) node; - Node *arg = (Node *) relabel->arg; - - if (relabel->relabelformat == COERCE_IMPLICIT_CAST && - !showimplicit) - { - /* don't show the implicit cast */ - get_rule_expr_paren(arg, context, false, node); - } - else - { - get_coercion_expr(arg, context, - relabel->resulttype, - relabel->resulttypmod, - node); - } - } - break; - - case T_CoerceViaIO: - { - CoerceViaIO *iocoerce = (CoerceViaIO *) node; - Node *arg = (Node *) iocoerce->arg; - - if (iocoerce->coerceformat == COERCE_IMPLICIT_CAST && - !showimplicit) - { - /* don't show the implicit cast */ - get_rule_expr_paren(arg, context, false, node); - } - else - { - get_coercion_expr(arg, context, - iocoerce->resulttype, - -1, - node); - } - } - break; - - case T_ArrayCoerceExpr: - { - ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; - Node *arg = (Node *) acoerce->arg; - - if (acoerce->coerceformat == COERCE_IMPLICIT_CAST && - !showimplicit) - { - /* don't show the implicit cast */ - get_rule_expr_paren(arg, context, false, node); - } - else - { - get_coercion_expr(arg, context, - acoerce->resulttype, - acoerce->resulttypmod, - node); - } - } - break; - - case T_ConvertRowtypeExpr: - { - ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node; - Node *arg = (Node *) convert->arg; - - if (convert->convertformat == COERCE_IMPLICIT_CAST && - !showimplicit) - { - /* don't show the implicit cast */ - get_rule_expr_paren(arg, context, false, node); - } - else - { - get_coercion_expr(arg, context, - convert->resulttype, -1, - node); - } - } - break; - - case T_CollateExpr: - { - CollateExpr *collate = (CollateExpr *) node; - Node *arg = (Node *) collate->arg; - - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, '('); - get_rule_expr_paren(arg, context, showimplicit, node); - appendStringInfo(buf, " COLLATE %s", - generate_collation_name(collate->collOid)); - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, ')'); - } - break; - - case T_CaseExpr: - { - CaseExpr *caseexpr = (CaseExpr *) node; - ListCell *temp; - - appendContextKeyword(context, "CASE", - 0, PRETTYINDENT_VAR, 0); - if (caseexpr->arg) - { - appendStringInfoChar(buf, ' '); - get_rule_expr((Node *) caseexpr->arg, context, true); - } - foreach(temp, caseexpr->args) - { - CaseWhen *when = (CaseWhen *) lfirst(temp); - Node *w = (Node *) when->expr; - - if (caseexpr->arg) - { - /* - * The parser should have produced WHEN clauses of the - * form "CaseTestExpr = RHS", possibly with an - * implicit coercion inserted above the CaseTestExpr. - * For accurate decompilation of rules it's essential - * that we show just the RHS. However in an - * expression that's been through the optimizer, the - * WHEN clause could be almost anything (since the - * equality operator could have been expanded into an - * inline function). If we don't recognize the form - * of the WHEN clause, just punt and display it as-is. - */ - if (IsA(w, OpExpr)) - { - List *args = ((OpExpr *) w)->args; - - if (list_length(args) == 2 && - IsA(strip_implicit_coercions(linitial(args)), - CaseTestExpr)) - w = (Node *) lsecond(args); - } - } - - if (!PRETTY_INDENT(context)) - appendStringInfoChar(buf, ' '); - appendContextKeyword(context, "WHEN ", - 0, 0, 0); - get_rule_expr(w, context, false); - appendStringInfoString(buf, " THEN "); - get_rule_expr((Node *) when->result, context, true); - } - if (!PRETTY_INDENT(context)) - appendStringInfoChar(buf, ' '); - appendContextKeyword(context, "ELSE ", - 0, 0, 0); - get_rule_expr((Node *) caseexpr->defresult, context, true); - if (!PRETTY_INDENT(context)) - appendStringInfoChar(buf, ' '); - appendContextKeyword(context, "END", - -PRETTYINDENT_VAR, 0, 0); - } - break; - - case T_CaseTestExpr: - { - /* - * Normally we should never get here, since for expressions - * that can contain this node type we attempt to avoid - * recursing to it. But in an optimized expression we might - * be unable to avoid that (see comments for CaseExpr). If we - * do see one, print it as CASE_TEST_EXPR. - */ - appendStringInfoString(buf, "CASE_TEST_EXPR"); - } - break; - - case T_ArrayExpr: - { - ArrayExpr *arrayexpr = (ArrayExpr *) node; - - appendStringInfoString(buf, "ARRAY["); - get_rule_expr((Node *) arrayexpr->elements, context, true); - appendStringInfoChar(buf, ']'); - - /* - * If the array isn't empty, we assume its elements are - * coerced to the desired type. If it's empty, though, we - * need an explicit coercion to the array type. - */ - if (arrayexpr->elements == NIL) - appendStringInfo(buf, "::%s", - format_type_with_typemod(arrayexpr->array_typeid, -1)); - } - break; - - case T_RowExpr: - { - RowExpr *rowexpr = (RowExpr *) node; - TupleDesc tupdesc = NULL; - ListCell *arg; - int i; - char *sep; - - /* - * If it's a named type and not RECORD, we may have to skip - * dropped columns and/or claim there are NULLs for added - * columns. - */ - if (rowexpr->row_typeid != RECORDOID) - { - tupdesc = lookup_rowtype_tupdesc(rowexpr->row_typeid, -1); - Assert(list_length(rowexpr->args) <= tupdesc->natts); - } - - /* - * SQL99 allows "ROW" to be omitted when there is more than - * one column, but for simplicity we always print it. - */ - appendStringInfoString(buf, "ROW("); - sep = ""; - i = 0; - foreach(arg, rowexpr->args) - { - Node *e = (Node *) lfirst(arg); - - if (tupdesc == NULL || - !TupleDescAttr(tupdesc, i)->attisdropped) - { - appendStringInfoString(buf, sep); - /* Whole-row Vars need special treatment here */ - get_rule_expr_toplevel(e, context, true); - sep = ", "; - } - i++; - } - if (tupdesc != NULL) - { - while (i < tupdesc->natts) - { - if (!TupleDescAttr(tupdesc, i)->attisdropped) - { - appendStringInfoString(buf, sep); - appendStringInfoString(buf, "NULL"); - sep = ", "; - } - i++; - } - - ReleaseTupleDesc(tupdesc); - } - appendStringInfoChar(buf, ')'); - if (rowexpr->row_format == COERCE_EXPLICIT_CAST) - appendStringInfo(buf, "::%s", - format_type_with_typemod(rowexpr->row_typeid, -1)); - } - break; - - case T_RowCompareExpr: - { - RowCompareExpr *rcexpr = (RowCompareExpr *) node; - ListCell *arg; - char *sep; - - /* - * SQL99 allows "ROW" to be omitted when there is more than - * one column, but for simplicity we always print it. - */ - appendStringInfoString(buf, "(ROW("); - sep = ""; - foreach(arg, rcexpr->largs) - { - Node *e = (Node *) lfirst(arg); - - appendStringInfoString(buf, sep); - get_rule_expr(e, context, true); - sep = ", "; - } - - /* - * We assume that the name of the first-column operator will - * do for all the rest too. This is definitely open to - * failure, eg if some but not all operators were renamed - * since the construct was parsed, but there seems no way to - * be perfect. - */ - appendStringInfo(buf, ") %s ROW(", - generate_operator_name(linitial_oid(rcexpr->opnos), - exprType(linitial(rcexpr->largs)), - exprType(linitial(rcexpr->rargs)))); - sep = ""; - foreach(arg, rcexpr->rargs) - { - Node *e = (Node *) lfirst(arg); - - appendStringInfoString(buf, sep); - get_rule_expr(e, context, true); - sep = ", "; - } - appendStringInfoString(buf, "))"); - } - break; - - case T_CoalesceExpr: - { - CoalesceExpr *coalesceexpr = (CoalesceExpr *) node; - - appendStringInfoString(buf, "COALESCE("); - get_rule_expr((Node *) coalesceexpr->args, context, true); - appendStringInfoChar(buf, ')'); - } - break; - - case T_MinMaxExpr: - { - MinMaxExpr *minmaxexpr = (MinMaxExpr *) node; - - switch (minmaxexpr->op) - { - case IS_GREATEST: - appendStringInfoString(buf, "GREATEST("); - break; - case IS_LEAST: - appendStringInfoString(buf, "LEAST("); - break; - } - get_rule_expr((Node *) minmaxexpr->args, context, true); - appendStringInfoChar(buf, ')'); - } - break; - - case T_SQLValueFunction: - { - SQLValueFunction *svf = (SQLValueFunction *) node; - - /* - * Note: this code knows that typmod for time, timestamp, and - * timestamptz just prints as integer. - */ - switch (svf->op) - { - case SVFOP_CURRENT_DATE: - appendStringInfoString(buf, "CURRENT_DATE"); - break; - case SVFOP_CURRENT_TIME: - appendStringInfoString(buf, "CURRENT_TIME"); - break; - case SVFOP_CURRENT_TIME_N: - appendStringInfo(buf, "CURRENT_TIME(%d)", svf->typmod); - break; - case SVFOP_CURRENT_TIMESTAMP: - appendStringInfoString(buf, "CURRENT_TIMESTAMP"); - break; - case SVFOP_CURRENT_TIMESTAMP_N: - appendStringInfo(buf, "CURRENT_TIMESTAMP(%d)", - svf->typmod); - break; - case SVFOP_LOCALTIME: - appendStringInfoString(buf, "LOCALTIME"); - break; - case SVFOP_LOCALTIME_N: - appendStringInfo(buf, "LOCALTIME(%d)", svf->typmod); - break; - case SVFOP_LOCALTIMESTAMP: - appendStringInfoString(buf, "LOCALTIMESTAMP"); - break; - case SVFOP_LOCALTIMESTAMP_N: - appendStringInfo(buf, "LOCALTIMESTAMP(%d)", - svf->typmod); - break; - case SVFOP_CURRENT_ROLE: - appendStringInfoString(buf, "CURRENT_ROLE"); - break; - case SVFOP_CURRENT_USER: - appendStringInfoString(buf, "CURRENT_USER"); - break; - case SVFOP_USER: - appendStringInfoString(buf, "USER"); - break; - case SVFOP_SESSION_USER: - appendStringInfoString(buf, "SESSION_USER"); - break; - case SVFOP_CURRENT_CATALOG: - appendStringInfoString(buf, "CURRENT_CATALOG"); - break; - case SVFOP_CURRENT_SCHEMA: - appendStringInfoString(buf, "CURRENT_SCHEMA"); - break; - } - } - break; - - case T_XmlExpr: - { - XmlExpr *xexpr = (XmlExpr *) node; - bool needcomma = false; - ListCell *arg; - ListCell *narg; - Const *con; - - switch (xexpr->op) - { - case IS_XMLCONCAT: - appendStringInfoString(buf, "XMLCONCAT("); - break; - case IS_XMLELEMENT: - appendStringInfoString(buf, "XMLELEMENT("); - break; - case IS_XMLFOREST: - appendStringInfoString(buf, "XMLFOREST("); - break; - case IS_XMLPARSE: - appendStringInfoString(buf, "XMLPARSE("); - break; - case IS_XMLPI: - appendStringInfoString(buf, "XMLPI("); - break; - case IS_XMLROOT: - appendStringInfoString(buf, "XMLROOT("); - break; - case IS_XMLSERIALIZE: - appendStringInfoString(buf, "XMLSERIALIZE("); - break; - case IS_DOCUMENT: - break; - } - if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE) - { - if (xexpr->xmloption == XMLOPTION_DOCUMENT) - appendStringInfoString(buf, "DOCUMENT "); - else - appendStringInfoString(buf, "CONTENT "); - } - if (xexpr->name) - { - appendStringInfo(buf, "NAME %s", - quote_identifier(map_xml_name_to_sql_identifier(xexpr->name))); - needcomma = true; - } - if (xexpr->named_args) - { - if (xexpr->op != IS_XMLFOREST) - { - if (needcomma) - appendStringInfoString(buf, ", "); - appendStringInfoString(buf, "XMLATTRIBUTES("); - needcomma = false; - } - forboth(arg, xexpr->named_args, narg, xexpr->arg_names) - { - Node *e = (Node *) lfirst(arg); - char *argname = strVal(lfirst(narg)); - - if (needcomma) - appendStringInfoString(buf, ", "); - get_rule_expr((Node *) e, context, true); - appendStringInfo(buf, " AS %s", - quote_identifier(map_xml_name_to_sql_identifier(argname))); - needcomma = true; - } - if (xexpr->op != IS_XMLFOREST) - appendStringInfoChar(buf, ')'); - } - if (xexpr->args) - { - if (needcomma) - appendStringInfoString(buf, ", "); - switch (xexpr->op) - { - case IS_XMLCONCAT: - case IS_XMLELEMENT: - case IS_XMLFOREST: - case IS_XMLPI: - case IS_XMLSERIALIZE: - /* no extra decoration needed */ - get_rule_expr((Node *) xexpr->args, context, true); - break; - case IS_XMLPARSE: - Assert(list_length(xexpr->args) == 2); - - get_rule_expr((Node *) linitial(xexpr->args), - context, true); - - con = lsecond_node(Const, xexpr->args); - Assert(!con->constisnull); - if (DatumGetBool(con->constvalue)) - appendStringInfoString(buf, - " PRESERVE WHITESPACE"); - else - appendStringInfoString(buf, - " STRIP WHITESPACE"); - break; - case IS_XMLROOT: - Assert(list_length(xexpr->args) == 3); - - get_rule_expr((Node *) linitial(xexpr->args), - context, true); - - appendStringInfoString(buf, ", VERSION "); - con = (Const *) lsecond(xexpr->args); - if (IsA(con, Const) && - con->constisnull) - appendStringInfoString(buf, "NO VALUE"); - else - get_rule_expr((Node *) con, context, false); - - con = lthird_node(Const, xexpr->args); - if (con->constisnull) - /* suppress STANDALONE NO VALUE */ ; - else - { - switch (DatumGetInt32(con->constvalue)) - { - case XML_STANDALONE_YES: - appendStringInfoString(buf, - ", STANDALONE YES"); - break; - case XML_STANDALONE_NO: - appendStringInfoString(buf, - ", STANDALONE NO"); - break; - case XML_STANDALONE_NO_VALUE: - appendStringInfoString(buf, - ", STANDALONE NO VALUE"); - break; - default: - break; - } - } - break; - case IS_DOCUMENT: - get_rule_expr_paren((Node *) xexpr->args, context, false, node); - break; - } - - } - if (xexpr->op == IS_XMLSERIALIZE) - appendStringInfo(buf, " AS %s", - format_type_with_typemod(xexpr->type, - xexpr->typmod)); - if (xexpr->op == IS_DOCUMENT) - appendStringInfoString(buf, " IS DOCUMENT"); - else - appendStringInfoChar(buf, ')'); - } - break; - - case T_NullTest: - { - NullTest *ntest = (NullTest *) node; - - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, '('); - get_rule_expr_paren((Node *) ntest->arg, context, true, node); - - /* - * For scalar inputs, we prefer to print as IS [NOT] NULL, - * which is shorter and traditional. If it's a rowtype input - * but we're applying a scalar test, must print IS [NOT] - * DISTINCT FROM NULL to be semantically correct. - */ - if (ntest->argisrow || - !type_is_rowtype(exprType((Node *) ntest->arg))) - { - switch (ntest->nulltesttype) - { - case IS_NULL: - appendStringInfoString(buf, " IS NULL"); - break; - case IS_NOT_NULL: - appendStringInfoString(buf, " IS NOT NULL"); - break; - default: - elog(ERROR, "unrecognized nulltesttype: %d", - (int) ntest->nulltesttype); - } - } - else - { - switch (ntest->nulltesttype) - { - case IS_NULL: - appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL"); - break; - case IS_NOT_NULL: - appendStringInfoString(buf, " IS DISTINCT FROM NULL"); - break; - default: - elog(ERROR, "unrecognized nulltesttype: %d", - (int) ntest->nulltesttype); - } - } - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, ')'); - } - break; - - case T_BooleanTest: - { - BooleanTest *btest = (BooleanTest *) node; - - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, '('); - get_rule_expr_paren((Node *) btest->arg, context, false, node); - switch (btest->booltesttype) - { - case IS_TRUE: - appendStringInfoString(buf, " IS TRUE"); - break; - case IS_NOT_TRUE: - appendStringInfoString(buf, " IS NOT TRUE"); - break; - case IS_FALSE: - appendStringInfoString(buf, " IS FALSE"); - break; - case IS_NOT_FALSE: - appendStringInfoString(buf, " IS NOT FALSE"); - break; - case IS_UNKNOWN: - appendStringInfoString(buf, " IS UNKNOWN"); - break; - case IS_NOT_UNKNOWN: - appendStringInfoString(buf, " IS NOT UNKNOWN"); - break; - default: - elog(ERROR, "unrecognized booltesttype: %d", - (int) btest->booltesttype); - } - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, ')'); - } - break; - - case T_CoerceToDomain: - { - CoerceToDomain *ctest = (CoerceToDomain *) node; - Node *arg = (Node *) ctest->arg; - - if (ctest->coercionformat == COERCE_IMPLICIT_CAST && - !showimplicit) - { - /* don't show the implicit cast */ - get_rule_expr(arg, context, false); - } - else - { - get_coercion_expr(arg, context, - ctest->resulttype, - ctest->resulttypmod, - node); - } - } - break; - - case T_CoerceToDomainValue: - appendStringInfoString(buf, "VALUE"); - break; - - case T_SetToDefault: - appendStringInfoString(buf, "DEFAULT"); - break; - - case T_CurrentOfExpr: - { - CurrentOfExpr *cexpr = (CurrentOfExpr *) node; - - if (cexpr->cursor_name) - appendStringInfo(buf, "CURRENT OF %s", - quote_identifier(cexpr->cursor_name)); - else - appendStringInfo(buf, "CURRENT OF $%d", - cexpr->cursor_param); - } - break; - - case T_NextValueExpr: - { - NextValueExpr *nvexpr = (NextValueExpr *) node; - - /* - * This isn't exactly nextval(), but that seems close enough - * for EXPLAIN's purposes. - */ - appendStringInfoString(buf, "nextval("); - simple_quote_literal(buf, - generate_relation_name(nvexpr->seqid, - NIL)); - appendStringInfoChar(buf, ')'); - } - break; - - case T_InferenceElem: - { - InferenceElem *iexpr = (InferenceElem *) node; - bool save_varprefix; - bool need_parens; - - /* - * InferenceElem can only refer to target relation, so a - * prefix is not useful, and indeed would cause parse errors. - */ - save_varprefix = context->varprefix; - context->varprefix = false; - - /* - * Parenthesize the element unless it's a simple Var or a bare - * function call. Follows pg_get_indexdef_worker(). - */ - need_parens = !IsA(iexpr->expr, Var); - if (IsA(iexpr->expr, FuncExpr) && - ((FuncExpr *) iexpr->expr)->funcformat == - COERCE_EXPLICIT_CALL) - need_parens = false; - - if (need_parens) - appendStringInfoChar(buf, '('); - get_rule_expr((Node *) iexpr->expr, - context, false); - if (need_parens) - appendStringInfoChar(buf, ')'); - - context->varprefix = save_varprefix; - - if (iexpr->infercollid) - appendStringInfo(buf, " COLLATE %s", - generate_collation_name(iexpr->infercollid)); - - /* Add the operator class name, if not default */ - if (iexpr->inferopclass) - { - Oid inferopclass = iexpr->inferopclass; - Oid inferopcinputtype = get_opclass_input_type(iexpr->inferopclass); - - get_opclass_name(inferopclass, inferopcinputtype, buf); - } - } - break; - - case T_PartitionBoundSpec: - { - PartitionBoundSpec *spec = (PartitionBoundSpec *) node; - ListCell *cell; - char *sep; - - if (spec->is_default) - { - appendStringInfoString(buf, "DEFAULT"); - break; - } - - switch (spec->strategy) - { - case PARTITION_STRATEGY_HASH: - Assert(spec->modulus > 0 && spec->remainder >= 0); - Assert(spec->modulus > spec->remainder); - - appendStringInfoString(buf, "FOR VALUES"); - appendStringInfo(buf, " WITH (modulus %d, remainder %d)", - spec->modulus, spec->remainder); - break; - - case PARTITION_STRATEGY_LIST: - Assert(spec->listdatums != NIL); - - appendStringInfoString(buf, "FOR VALUES IN ("); - sep = ""; - foreach(cell, spec->listdatums) - { - Const *val = lfirst_node(Const, cell); - - appendStringInfoString(buf, sep); - get_const_expr(val, context, -1); - sep = ", "; - } - - appendStringInfoChar(buf, ')'); - break; - - case PARTITION_STRATEGY_RANGE: - Assert(spec->lowerdatums != NIL && - spec->upperdatums != NIL && - list_length(spec->lowerdatums) == - list_length(spec->upperdatums)); - - appendStringInfo(buf, "FOR VALUES FROM %s TO %s", - get_range_partbound_string(spec->lowerdatums), - get_range_partbound_string(spec->upperdatums)); - break; - - default: - elog(ERROR, "unrecognized partition strategy: %d", - (int) spec->strategy); - break; - } - } - break; - - case T_List: - { - char *sep; - ListCell *l; - - sep = ""; - foreach(l, (List *) node) - { - appendStringInfoString(buf, sep); - get_rule_expr((Node *) lfirst(l), context, showimplicit); - sep = ", "; - } - } - break; - - case T_TableFunc: - get_tablefunc((TableFunc *) node, context, showimplicit); - break; - - case T_CallStmt: - get_proc_expr((CallStmt *) node, context, showimplicit); - break; - - default: - elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node)); - break; - } -} - -/* - * get_rule_expr_toplevel - Parse back a toplevel expression - * - * Same as get_rule_expr(), except that if the expr is just a Var, we pass - * istoplevel = true not false to get_variable(). This causes whole-row Vars - * to get printed with decoration that will prevent expansion of "*". - * We need to use this in contexts such as ROW() and VALUES(), where the - * parser would expand "foo.*" appearing at top level. (In principle we'd - * use this in get_target_list() too, but that has additional worries about - * whether to print AS, so it needs to invoke get_variable() directly anyway.) - */ -static void -get_rule_expr_toplevel(Node *node, deparse_context *context, - bool showimplicit) -{ - if (node && IsA(node, Var)) - (void) get_variable((Var *) node, 0, true, context); - else - get_rule_expr(node, context, showimplicit); -} - -/* - * get_rule_expr_funccall - Parse back a function-call expression - * - * Same as get_rule_expr(), except that we guarantee that the output will - * look like a function call, or like one of the things the grammar treats as - * equivalent to a function call (see the func_expr_windowless production). - * This is needed in places where the grammar uses func_expr_windowless and - * you can't substitute a parenthesized a_expr. If what we have isn't going - * to look like a function call, wrap it in a dummy CAST() expression, which - * will satisfy the grammar --- and, indeed, is likely what the user wrote to - * produce such a thing. - */ -static void -get_rule_expr_funccall(Node *node, deparse_context *context, - bool showimplicit) -{ - if (looks_like_function(node)) - get_rule_expr(node, context, showimplicit); - else - { - StringInfo buf = context->buf; - - appendStringInfoString(buf, "CAST("); - /* no point in showing any top-level implicit cast */ - get_rule_expr(node, context, false); - appendStringInfo(buf, " AS %s)", - format_type_with_typemod(exprType(node), - exprTypmod(node))); - } -} - -/* - * Helper function to identify node types that satisfy func_expr_windowless. - * If in doubt, "false" is always a safe answer. - */ -static bool -looks_like_function(Node *node) -{ - if (node == NULL) - return false; /* probably shouldn't happen */ - switch (nodeTag(node)) - { - case T_FuncExpr: - /* OK, unless it's going to deparse as a cast */ - return (((FuncExpr *) node)->funcformat == COERCE_EXPLICIT_CALL || - ((FuncExpr *) node)->funcformat == COERCE_SQL_SYNTAX); - case T_NullIfExpr: - case T_CoalesceExpr: - case T_MinMaxExpr: - case T_SQLValueFunction: - case T_XmlExpr: - /* these are all accepted by func_expr_common_subexpr */ - return true; - default: - break; - } - return false; -} - - -/* - * get_oper_expr - Parse back an OpExpr node - */ -static void -get_oper_expr(OpExpr *expr, deparse_context *context) -{ - StringInfo buf = context->buf; - Oid opno = expr->opno; - List *args = expr->args; - - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, '('); - if (list_length(args) == 2) - { - /* binary operator */ - Node *arg1 = (Node *) linitial(args); - Node *arg2 = (Node *) lsecond(args); - - get_rule_expr_paren(arg1, context, true, (Node *) expr); - appendStringInfo(buf, " %s ", - generate_operator_name(opno, - exprType(arg1), - exprType(arg2))); - get_rule_expr_paren(arg2, context, true, (Node *) expr); - } - else - { - /* prefix operator */ - Node *arg = (Node *) linitial(args); - - appendStringInfo(buf, "%s ", - generate_operator_name(opno, - InvalidOid, - exprType(arg))); - get_rule_expr_paren(arg, context, true, (Node *) expr); - } - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, ')'); -} - -/* - * get_func_expr - Parse back a FuncExpr node - */ -static void -get_func_expr(FuncExpr *expr, deparse_context *context, - bool showimplicit) -{ - StringInfo buf = context->buf; - Oid funcoid = expr->funcid; - Oid argtypes[FUNC_MAX_ARGS]; - int nargs; - List *argnames; - bool use_variadic; - ListCell *l; - - /* - * If the function call came from an implicit coercion, then just show the - * first argument --- unless caller wants to see implicit coercions. - */ - if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit) - { - get_rule_expr_paren((Node *) linitial(expr->args), context, - false, (Node *) expr); - return; - } - - /* - * If the function call came from a cast, then show the first argument - * plus an explicit cast operation. - */ - if (expr->funcformat == COERCE_EXPLICIT_CAST || - expr->funcformat == COERCE_IMPLICIT_CAST) - { - Node *arg = linitial(expr->args); - Oid rettype = expr->funcresulttype; - int32 coercedTypmod; - - /* Get the typmod if this is a length-coercion function */ - (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod); - - get_coercion_expr(arg, context, - rettype, coercedTypmod, - (Node *) expr); - - return; - } - - /* - * If the function was called using one of the SQL spec's random special - * syntaxes, try to reproduce that. If we don't recognize the function, - * fall through. - */ - if (expr->funcformat == COERCE_SQL_SYNTAX) - { - if (get_func_sql_syntax(expr, context)) - return; - } - - - /* - * Normal function: display as proname(args). First we need to extract - * the argument datatypes. - */ - if (list_length(expr->args) > FUNC_MAX_ARGS) - ereport(ERROR, - (errcode(ERRCODE_TOO_MANY_ARGUMENTS), - errmsg("too many arguments"))); - nargs = 0; - argnames = NIL; - foreach(l, expr->args) - { - Node *arg = (Node *) lfirst(l); - - if (IsA(arg, NamedArgExpr)) - argnames = lappend(argnames, ((NamedArgExpr *) arg)->name); - argtypes[nargs] = exprType(arg); - nargs++; - } - - appendStringInfo(buf, "%s(", - generate_function_name(funcoid, nargs, - argnames, argtypes, - expr->funcvariadic, - &use_variadic, - context->special_exprkind)); - nargs = 0; - foreach(l, expr->args) - { - if (nargs++ > 0) - appendStringInfoString(buf, ", "); - if (use_variadic && lnext(expr->args, l) == NULL) - appendStringInfoString(buf, "VARIADIC "); - get_rule_expr((Node *) lfirst(l), context, true); - } - - appendStringInfoChar(buf, ')'); -} - - -/* - * get_proc_expr - Parse back a CallStmt node - */ -static void -get_proc_expr(CallStmt *stmt, deparse_context *context, - bool showimplicit) -{ - StringInfo buf = context->buf; - Oid functionOid = stmt->funcexpr->funcid; - bool use_variadic; - Oid *argumentTypes; - List *finalArgumentList = NIL; - ListCell *argumentCell; - List *namedArgList = NIL; - int numberOfArgs = -1; - - if (!get_merged_argument_list(stmt, &namedArgList, &argumentTypes, - &finalArgumentList, &numberOfArgs)) - { - /* Nothing merged i.e. no OUT arguments */ - get_func_expr((FuncExpr *) stmt->funcexpr, context, showimplicit); - return; - } - - appendStringInfo(buf, "%s(", - generate_function_name(functionOid, numberOfArgs, - namedArgList, argumentTypes, - stmt->funcexpr->funcvariadic, - &use_variadic, - context->special_exprkind)); - int argNumber = 0; - foreach(argumentCell, finalArgumentList) - { - if (argNumber++ > 0) - appendStringInfoString(buf, ", "); - if (use_variadic && lnext(finalArgumentList, argumentCell) == NULL) - appendStringInfoString(buf, "VARIADIC "); - get_rule_expr((Node *) lfirst(argumentCell), context, true); - argNumber++; - } - - appendStringInfoChar(buf, ')'); -} - -/* - * get_agg_expr - Parse back an Aggref node - */ -static void -get_agg_expr(Aggref *aggref, deparse_context *context, - Aggref *original_aggref) -{ - StringInfo buf = context->buf; - Oid argtypes[FUNC_MAX_ARGS]; - int nargs; - bool use_variadic; - - /* - * For a combining aggregate, we look up and deparse the corresponding - * partial aggregate instead. This is necessary because our input - * argument list has been replaced; the new argument list always has just - * one element, which will point to a partial Aggref that supplies us with - * transition states to combine. - */ - if (DO_AGGSPLIT_COMBINE(aggref->aggsplit)) - { - TargetEntry *tle; - - - Assert(list_length(aggref->args) == 1); - tle = linitial_node(TargetEntry, aggref->args); - resolve_special_varno((Node *) tle->expr, context, - get_agg_combine_expr, original_aggref); - return; - } - - /* - * Mark as PARTIAL, if appropriate. We look to the original aggref so as - * to avoid printing this when recursing from the code just above. - */ - if (DO_AGGSPLIT_SKIPFINAL(original_aggref->aggsplit)) - appendStringInfoString(buf, "PARTIAL "); - - /* Extract the argument types as seen by the parser */ - nargs = get_aggregate_argtypes(aggref, argtypes); - - /* Print the aggregate name, schema-qualified if needed */ - appendStringInfo(buf, "%s(%s", - generate_function_name(aggref->aggfnoid, nargs, - NIL, argtypes, - aggref->aggvariadic, - &use_variadic, - context->special_exprkind), - (aggref->aggdistinct != NIL) ? "DISTINCT " : ""); - - if (AGGKIND_IS_ORDERED_SET(aggref->aggkind)) - { - /* - * Ordered-set aggregates do not use "*" syntax. Also, we needn't - * worry about inserting VARIADIC. So we can just dump the direct - * args as-is. - */ - Assert(!aggref->aggvariadic); - get_rule_expr((Node *) aggref->aggdirectargs, context, true); - Assert(aggref->aggorder != NIL); - appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY "); - get_rule_orderby(aggref->aggorder, aggref->args, false, context); - } - else - { - /* aggstar can be set only in zero-argument aggregates */ - if (aggref->aggstar) - appendStringInfoChar(buf, '*'); - else - { - ListCell *l; - int i; - - i = 0; - foreach(l, aggref->args) - { - TargetEntry *tle = (TargetEntry *) lfirst(l); - Node *arg = (Node *) tle->expr; - - Assert(!IsA(arg, NamedArgExpr)); - if (tle->resjunk) - continue; - if (i++ > 0) - appendStringInfoString(buf, ", "); - if (use_variadic && i == nargs) - appendStringInfoString(buf, "VARIADIC "); - get_rule_expr(arg, context, true); - } - } - - if (aggref->aggorder != NIL) - { - appendStringInfoString(buf, " ORDER BY "); - get_rule_orderby(aggref->aggorder, aggref->args, false, context); - } - } - - if (aggref->aggfilter != NULL) - { - appendStringInfoString(buf, ") FILTER (WHERE "); - get_rule_expr((Node *) aggref->aggfilter, context, false); - } - - appendStringInfoChar(buf, ')'); -} - -/* - * This is a helper function for get_agg_expr(). It's used when we deparse - * a combining Aggref; resolve_special_varno locates the corresponding partial - * Aggref and then calls this. - */ -static void -get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg) -{ - Aggref *aggref; - Aggref *original_aggref = callback_arg; - - if (!IsA(node, Aggref)) - elog(ERROR, "combining Aggref does not point to an Aggref"); - - aggref = (Aggref *) node; - get_agg_expr(aggref, context, original_aggref); -} - -/* - * get_windowfunc_expr - Parse back a WindowFunc node - */ -static void -get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context) -{ - StringInfo buf = context->buf; - Oid argtypes[FUNC_MAX_ARGS]; - int nargs; - List *argnames; - ListCell *l; - - if (list_length(wfunc->args) > FUNC_MAX_ARGS) - ereport(ERROR, - (errcode(ERRCODE_TOO_MANY_ARGUMENTS), - errmsg("too many arguments"))); - nargs = 0; - argnames = NIL; - foreach(l, wfunc->args) - { - Node *arg = (Node *) lfirst(l); - - if (IsA(arg, NamedArgExpr)) - argnames = lappend(argnames, ((NamedArgExpr *) arg)->name); - argtypes[nargs] = exprType(arg); - nargs++; - } - - appendStringInfo(buf, "%s(", - generate_function_name(wfunc->winfnoid, nargs, - argnames, argtypes, - false, NULL, - context->special_exprkind)); - /* winstar can be set only in zero-argument aggregates */ - if (wfunc->winstar) - appendStringInfoChar(buf, '*'); - else - get_rule_expr((Node *) wfunc->args, context, true); - - if (wfunc->aggfilter != NULL) - { - appendStringInfoString(buf, ") FILTER (WHERE "); - get_rule_expr((Node *) wfunc->aggfilter, context, false); - } - - appendStringInfoString(buf, ") OVER "); - - foreach(l, context->windowClause) - { - WindowClause *wc = (WindowClause *) lfirst(l); - - if (wc->winref == wfunc->winref) - { - if (wc->name) - appendStringInfoString(buf, quote_identifier(wc->name)); - else - get_rule_windowspec(wc, context->windowTList, context); - break; - } - } - if (l == NULL) - { - if (context->windowClause) - elog(ERROR, "could not find window clause for winref %u", - wfunc->winref); - - /* - * In EXPLAIN, we don't have window context information available, so - * we have to settle for this: - */ - appendStringInfoString(buf, "(?)"); - } -} - - -/* - * get_func_sql_syntax - Parse back a SQL-syntax function call - * - * Returns true if we successfully deparsed, false if we did not - * recognize the function. - */ -static bool -get_func_sql_syntax(FuncExpr *expr, deparse_context *context) -{ - StringInfo buf = context->buf; - Oid funcoid = expr->funcid; - - switch (funcoid) - { - case F_TIMEZONE_INTERVAL_TIMESTAMP: - case F_TIMEZONE_INTERVAL_TIMESTAMPTZ: - case F_TIMEZONE_INTERVAL_TIMETZ: - case F_TIMEZONE_TEXT_TIMESTAMP: - case F_TIMEZONE_TEXT_TIMESTAMPTZ: - case F_TIMEZONE_TEXT_TIMETZ: - /* AT TIME ZONE ... note reversed argument order */ - appendStringInfoChar(buf, '('); - get_rule_expr((Node *) lsecond(expr->args), context, false); - appendStringInfoString(buf, " AT TIME ZONE "); - get_rule_expr((Node *) linitial(expr->args), context, false); - appendStringInfoChar(buf, ')'); - return true; - - case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_INTERVAL: - case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_TIMESTAMPTZ: - case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_INTERVAL: - case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ: - case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_INTERVAL: - case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_TIMESTAMP: - case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_INTERVAL: - case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_TIMESTAMP: - case F_OVERLAPS_TIMETZ_TIMETZ_TIMETZ_TIMETZ: - case F_OVERLAPS_TIME_INTERVAL_TIME_INTERVAL: - case F_OVERLAPS_TIME_INTERVAL_TIME_TIME: - case F_OVERLAPS_TIME_TIME_TIME_INTERVAL: - case F_OVERLAPS_TIME_TIME_TIME_TIME: - /* (x1, x2) OVERLAPS (y1, y2) */ - appendStringInfoString(buf, "(("); - get_rule_expr((Node *) linitial(expr->args), context, false); - appendStringInfoString(buf, ", "); - get_rule_expr((Node *) lsecond(expr->args), context, false); - appendStringInfoString(buf, ") OVERLAPS ("); - get_rule_expr((Node *) lthird(expr->args), context, false); - appendStringInfoString(buf, ", "); - get_rule_expr((Node *) lfourth(expr->args), context, false); - appendStringInfoString(buf, "))"); - return true; - - case F_EXTRACT_TEXT_DATE: - case F_EXTRACT_TEXT_TIME: - case F_EXTRACT_TEXT_TIMETZ: - case F_EXTRACT_TEXT_TIMESTAMP: - case F_EXTRACT_TEXT_TIMESTAMPTZ: - case F_EXTRACT_TEXT_INTERVAL: - /* EXTRACT (x FROM y) */ - appendStringInfoString(buf, "EXTRACT("); - { - Const *con = (Const *) linitial(expr->args); - - Assert(IsA(con, Const) && - con->consttype == TEXTOID && - !con->constisnull); - appendStringInfoString(buf, TextDatumGetCString(con->constvalue)); - } - appendStringInfoString(buf, " FROM "); - get_rule_expr((Node *) lsecond(expr->args), context, false); - appendStringInfoChar(buf, ')'); - return true; - - case F_IS_NORMALIZED: - /* IS xxx NORMALIZED */ - appendStringInfoString(buf, "(("); - get_rule_expr((Node *) linitial(expr->args), context, false); - appendStringInfoString(buf, ") IS"); - if (list_length(expr->args) == 2) - { - Const *con = (Const *) lsecond(expr->args); - - Assert(IsA(con, Const) && - con->consttype == TEXTOID && - !con->constisnull); - appendStringInfo(buf, " %s", - TextDatumGetCString(con->constvalue)); - } - appendStringInfoString(buf, " NORMALIZED)"); - return true; - - case F_PG_COLLATION_FOR: - /* COLLATION FOR */ - appendStringInfoString(buf, "COLLATION FOR ("); - get_rule_expr((Node *) linitial(expr->args), context, false); - appendStringInfoChar(buf, ')'); - return true; - - /* - * XXX EXTRACT, a/k/a date_part(), is intentionally not covered - * yet. Add it after we change the return type to numeric. - */ - - case F_NORMALIZE: - /* NORMALIZE() */ - appendStringInfoString(buf, "NORMALIZE("); - get_rule_expr((Node *) linitial(expr->args), context, false); - if (list_length(expr->args) == 2) - { - Const *con = (Const *) lsecond(expr->args); - - Assert(IsA(con, Const) && - con->consttype == TEXTOID && - !con->constisnull); - appendStringInfo(buf, ", %s", - TextDatumGetCString(con->constvalue)); - } - appendStringInfoChar(buf, ')'); - return true; - - case F_OVERLAY_BIT_BIT_INT4: - case F_OVERLAY_BIT_BIT_INT4_INT4: - case F_OVERLAY_BYTEA_BYTEA_INT4: - case F_OVERLAY_BYTEA_BYTEA_INT4_INT4: - case F_OVERLAY_TEXT_TEXT_INT4: - case F_OVERLAY_TEXT_TEXT_INT4_INT4: - /* OVERLAY() */ - appendStringInfoString(buf, "OVERLAY("); - get_rule_expr((Node *) linitial(expr->args), context, false); - appendStringInfoString(buf, " PLACING "); - get_rule_expr((Node *) lsecond(expr->args), context, false); - appendStringInfoString(buf, " FROM "); - get_rule_expr((Node *) lthird(expr->args), context, false); - if (list_length(expr->args) == 4) - { - appendStringInfoString(buf, " FOR "); - get_rule_expr((Node *) lfourth(expr->args), context, false); - } - appendStringInfoChar(buf, ')'); - return true; - - case F_POSITION_BIT_BIT: - case F_POSITION_BYTEA_BYTEA: - case F_POSITION_TEXT_TEXT: - /* POSITION() ... extra parens since args are b_expr not a_expr */ - appendStringInfoString(buf, "POSITION(("); - get_rule_expr((Node *) lsecond(expr->args), context, false); - appendStringInfoString(buf, ") IN ("); - get_rule_expr((Node *) linitial(expr->args), context, false); - appendStringInfoString(buf, "))"); - return true; - - case F_SUBSTRING_BIT_INT4: - case F_SUBSTRING_BIT_INT4_INT4: - case F_SUBSTRING_BYTEA_INT4: - case F_SUBSTRING_BYTEA_INT4_INT4: - case F_SUBSTRING_TEXT_INT4: - case F_SUBSTRING_TEXT_INT4_INT4: - /* SUBSTRING FROM/FOR (i.e., integer-position variants) */ - appendStringInfoString(buf, "SUBSTRING("); - get_rule_expr((Node *) linitial(expr->args), context, false); - appendStringInfoString(buf, " FROM "); - get_rule_expr((Node *) lsecond(expr->args), context, false); - if (list_length(expr->args) == 3) - { - appendStringInfoString(buf, " FOR "); - get_rule_expr((Node *) lthird(expr->args), context, false); - } - appendStringInfoChar(buf, ')'); - return true; - - case F_SUBSTRING_TEXT_TEXT_TEXT: - /* SUBSTRING SIMILAR/ESCAPE */ - appendStringInfoString(buf, "SUBSTRING("); - get_rule_expr((Node *) linitial(expr->args), context, false); - appendStringInfoString(buf, " SIMILAR "); - get_rule_expr((Node *) lsecond(expr->args), context, false); - appendStringInfoString(buf, " ESCAPE "); - get_rule_expr((Node *) lthird(expr->args), context, false); - appendStringInfoChar(buf, ')'); - return true; - - case F_BTRIM_BYTEA_BYTEA: - case F_BTRIM_TEXT: - case F_BTRIM_TEXT_TEXT: - /* TRIM() */ - appendStringInfoString(buf, "TRIM(BOTH"); - if (list_length(expr->args) == 2) - { - appendStringInfoChar(buf, ' '); - get_rule_expr((Node *) lsecond(expr->args), context, false); - } - appendStringInfoString(buf, " FROM "); - get_rule_expr((Node *) linitial(expr->args), context, false); - appendStringInfoChar(buf, ')'); - return true; - - case F_LTRIM_BYTEA_BYTEA: - case F_LTRIM_TEXT: - case F_LTRIM_TEXT_TEXT: - /* TRIM() */ - appendStringInfoString(buf, "TRIM(LEADING"); - if (list_length(expr->args) == 2) - { - appendStringInfoChar(buf, ' '); - get_rule_expr((Node *) lsecond(expr->args), context, false); - } - appendStringInfoString(buf, " FROM "); - get_rule_expr((Node *) linitial(expr->args), context, false); - appendStringInfoChar(buf, ')'); - return true; - - case F_RTRIM_BYTEA_BYTEA: - case F_RTRIM_TEXT: - case F_RTRIM_TEXT_TEXT: - /* TRIM() */ - appendStringInfoString(buf, "TRIM(TRAILING"); - if (list_length(expr->args) == 2) - { - appendStringInfoChar(buf, ' '); - get_rule_expr((Node *) lsecond(expr->args), context, false); - } - appendStringInfoString(buf, " FROM "); - get_rule_expr((Node *) linitial(expr->args), context, false); - appendStringInfoChar(buf, ')'); - return true; - - case F_XMLEXISTS: - /* XMLEXISTS ... extra parens because args are c_expr */ - appendStringInfoString(buf, "XMLEXISTS(("); - get_rule_expr((Node *) linitial(expr->args), context, false); - appendStringInfoString(buf, ") PASSING ("); - get_rule_expr((Node *) lsecond(expr->args), context, false); - appendStringInfoString(buf, "))"); - return true; - } - return false; -} - - -/* ---------- - * get_coercion_expr - * - * Make a string representation of a value coerced to a specific type - * ---------- - */ -static void -get_coercion_expr(Node *arg, deparse_context *context, - Oid resulttype, int32 resulttypmod, - Node *parentNode) -{ - StringInfo buf = context->buf; - - /* - * Since parse_coerce.c doesn't immediately collapse application of - * length-coercion functions to constants, what we'll typically see in - * such cases is a Const with typmod -1 and a length-coercion function - * right above it. Avoid generating redundant output. However, beware of - * suppressing casts when the user actually wrote something like - * 'foo'::text::char(3). - * - * Note: it might seem that we are missing the possibility of needing to - * print a COLLATE clause for such a Const. However, a Const could only - * have nondefault collation in a post-constant-folding tree, in which the - * length coercion would have been folded too. See also the special - * handling of CollateExpr in coerce_to_target_type(): any collation - * marking will be above the coercion node, not below it. - */ - if (arg && IsA(arg, Const) && - ((Const *) arg)->consttype == resulttype && - ((Const *) arg)->consttypmod == -1) - { - /* Show the constant without normal ::typename decoration */ - get_const_expr((Const *) arg, context, -1); - } - else - { - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, '('); - get_rule_expr_paren(arg, context, false, parentNode); - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, ')'); - } - appendStringInfo(buf, "::%s", - format_type_with_typemod(resulttype, resulttypmod)); -} - -/* ---------- - * get_const_expr - * - * Make a string representation of a Const - * - * showtype can be -1 to never show "::typename" decoration, or +1 to always - * show it, or 0 to show it only if the constant wouldn't be assumed to be - * the right type by default. - * - * If the Const's collation isn't default for its type, show that too. - * We mustn't do this when showtype is -1 (since that means the caller will - * print "::typename", and we can't put a COLLATE clause in between). It's - * caller's responsibility that collation isn't missed in such cases. - * ---------- - */ -static void -get_const_expr(Const *constval, deparse_context *context, int showtype) -{ - StringInfo buf = context->buf; - Oid typoutput; - bool typIsVarlena; - char *extval; - bool needlabel = false; - - if (constval->constisnull) - { - /* - * Always label the type of a NULL constant to prevent misdecisions - * about type when reparsing. - */ - appendStringInfoString(buf, "NULL"); - if (showtype >= 0) - { - appendStringInfo(buf, "::%s", - format_type_with_typemod(constval->consttype, - constval->consttypmod)); - get_const_collation(constval, context); - } - return; - } - - getTypeOutputInfo(constval->consttype, - &typoutput, &typIsVarlena); - - extval = OidOutputFunctionCall(typoutput, constval->constvalue); - - switch (constval->consttype) - { - case INT4OID: - - /* - * INT4 can be printed without any decoration, unless it is - * negative; in that case print it as '-nnn'::integer to ensure - * that the output will re-parse as a constant, not as a constant - * plus operator. In most cases we could get away with printing - * (-nnn) instead, because of the way that gram.y handles negative - * literals; but that doesn't work for INT_MIN, and it doesn't - * seem that much prettier anyway. - */ - if (extval[0] != '-') - appendStringInfoString(buf, extval); - else - { - appendStringInfo(buf, "'%s'", extval); - needlabel = true; /* we must attach a cast */ - } - break; - - case NUMERICOID: - - /* - * NUMERIC can be printed without quotes if it looks like a float - * constant (not an integer, and not Infinity or NaN) and doesn't - * have a leading sign (for the same reason as for INT4). - */ - if (isdigit((unsigned char) extval[0]) && - strcspn(extval, "eE.") != strlen(extval)) - { - appendStringInfoString(buf, extval); - } - else - { - appendStringInfo(buf, "'%s'", extval); - needlabel = true; /* we must attach a cast */ - } - break; - - case BITOID: - case VARBITOID: - appendStringInfo(buf, "B'%s'", extval); - break; - - case BOOLOID: - if (strcmp(extval, "t") == 0) - appendStringInfoString(buf, "true"); - else - appendStringInfoString(buf, "false"); - break; - - default: - simple_quote_literal(buf, extval); - break; - } - - pfree(extval); - - if (showtype < 0) - return; - - /* - * For showtype == 0, append ::typename unless the constant will be - * implicitly typed as the right type when it is read in. - * - * XXX this code has to be kept in sync with the behavior of the parser, - * especially make_const. - */ - switch (constval->consttype) - { - case BOOLOID: - case UNKNOWNOID: - /* These types can be left unlabeled */ - needlabel = false; - break; - case INT4OID: - /* We determined above whether a label is needed */ - break; - case NUMERICOID: - - /* - * Float-looking constants will be typed as numeric, which we - * checked above; but if there's a nondefault typmod we need to - * show it. - */ - needlabel |= (constval->consttypmod >= 0); - break; - default: - needlabel = true; - break; - } - if (needlabel || showtype > 0) - appendStringInfo(buf, "::%s", - format_type_with_typemod(constval->consttype, - constval->consttypmod)); - - get_const_collation(constval, context); -} - -/* - * helper for get_const_expr: append COLLATE if needed - */ -static void -get_const_collation(Const *constval, deparse_context *context) -{ - StringInfo buf = context->buf; - - if (OidIsValid(constval->constcollid)) - { - Oid typcollation = get_typcollation(constval->consttype); - - if (constval->constcollid != typcollation) - { - appendStringInfo(buf, " COLLATE %s", - generate_collation_name(constval->constcollid)); - } - } -} - -/* - * simple_quote_literal - Format a string as a SQL literal, append to buf - */ -static void -simple_quote_literal(StringInfo buf, const char *val) -{ - const char *valptr; - - /* - * We form the string literal according to the prevailing setting of - * standard_conforming_strings; we never use E''. User is responsible for - * making sure result is used correctly. - */ - appendStringInfoChar(buf, '\''); - for (valptr = val; *valptr; valptr++) - { - char ch = *valptr; - - if (SQL_STR_DOUBLE(ch, !standard_conforming_strings)) - appendStringInfoChar(buf, ch); - appendStringInfoChar(buf, ch); - } - appendStringInfoChar(buf, '\''); -} - - -/* ---------- - * get_sublink_expr - Parse back a sublink - * ---------- - */ -static void -get_sublink_expr(SubLink *sublink, deparse_context *context) -{ - StringInfo buf = context->buf; - Query *query = (Query *) (sublink->subselect); - char *opname = NULL; - bool need_paren; - - if (sublink->subLinkType == ARRAY_SUBLINK) - appendStringInfoString(buf, "ARRAY("); - else - appendStringInfoChar(buf, '('); - - /* - * Note that we print the name of only the first operator, when there are - * multiple combining operators. This is an approximation that could go - * wrong in various scenarios (operators in different schemas, renamed - * operators, etc) but there is not a whole lot we can do about it, since - * the syntax allows only one operator to be shown. - */ - if (sublink->testexpr) - { - if (IsA(sublink->testexpr, OpExpr)) - { - /* single combining operator */ - OpExpr *opexpr = (OpExpr *) sublink->testexpr; - - get_rule_expr(linitial(opexpr->args), context, true); - opname = generate_operator_name(opexpr->opno, - exprType(linitial(opexpr->args)), - exprType(lsecond(opexpr->args))); - } - else if (IsA(sublink->testexpr, BoolExpr)) - { - /* multiple combining operators, = or <> cases */ - char *sep; - ListCell *l; - - appendStringInfoChar(buf, '('); - sep = ""; - foreach(l, ((BoolExpr *) sublink->testexpr)->args) - { - OpExpr *opexpr = lfirst_node(OpExpr, l); - - appendStringInfoString(buf, sep); - get_rule_expr(linitial(opexpr->args), context, true); - if (!opname) - opname = generate_operator_name(opexpr->opno, - exprType(linitial(opexpr->args)), - exprType(lsecond(opexpr->args))); - sep = ", "; - } - appendStringInfoChar(buf, ')'); - } - else if (IsA(sublink->testexpr, RowCompareExpr)) - { - /* multiple combining operators, < <= > >= cases */ - RowCompareExpr *rcexpr = (RowCompareExpr *) sublink->testexpr; - - appendStringInfoChar(buf, '('); - get_rule_expr((Node *) rcexpr->largs, context, true); - opname = generate_operator_name(linitial_oid(rcexpr->opnos), - exprType(linitial(rcexpr->largs)), - exprType(linitial(rcexpr->rargs))); - appendStringInfoChar(buf, ')'); - } - else - elog(ERROR, "unrecognized testexpr type: %d", - (int) nodeTag(sublink->testexpr)); - } - - need_paren = true; - - switch (sublink->subLinkType) - { - case EXISTS_SUBLINK: - appendStringInfoString(buf, "EXISTS "); - break; - - case ANY_SUBLINK: - if (strcmp(opname, "=") == 0) /* Represent = ANY as IN */ - appendStringInfoString(buf, " IN "); - else - appendStringInfo(buf, " %s ANY ", opname); - break; - - case ALL_SUBLINK: - appendStringInfo(buf, " %s ALL ", opname); - break; - - case ROWCOMPARE_SUBLINK: - appendStringInfo(buf, " %s ", opname); - break; - - case EXPR_SUBLINK: - case MULTIEXPR_SUBLINK: - case ARRAY_SUBLINK: - need_paren = false; - break; - - case CTE_SUBLINK: /* shouldn't occur in a SubLink */ - default: - elog(ERROR, "unrecognized sublink type: %d", - (int) sublink->subLinkType); - break; - } - - if (need_paren) - appendStringInfoChar(buf, '('); - - get_query_def(query, buf, context->namespaces, NULL, - context->prettyFlags, context->wrapColumn, - context->indentLevel); - - if (need_paren) - appendStringInfoString(buf, "))"); - else - appendStringInfoChar(buf, ')'); -} - - -/* ---------- - * get_tablefunc - Parse back a table function - * ---------- - */ -static void -get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit) -{ - StringInfo buf = context->buf; - - /* XMLTABLE is the only existing implementation. */ - - appendStringInfoString(buf, "XMLTABLE("); - - if (tf->ns_uris != NIL) - { - ListCell *lc1, - *lc2; - bool first = true; - - appendStringInfoString(buf, "XMLNAMESPACES ("); - forboth(lc1, tf->ns_uris, lc2, tf->ns_names) - { - Node *expr = (Node *) lfirst(lc1); - char *name = strVal(lfirst(lc2)); - - if (!first) - appendStringInfoString(buf, ", "); - else - first = false; - - if (name != NULL) - { - get_rule_expr(expr, context, showimplicit); - appendStringInfo(buf, " AS %s", name); - } - else - { - appendStringInfoString(buf, "DEFAULT "); - get_rule_expr(expr, context, showimplicit); - } - } - appendStringInfoString(buf, "), "); - } - - appendStringInfoChar(buf, '('); - get_rule_expr((Node *) tf->rowexpr, context, showimplicit); - appendStringInfoString(buf, ") PASSING ("); - get_rule_expr((Node *) tf->docexpr, context, showimplicit); - appendStringInfoChar(buf, ')'); - - if (tf->colexprs != NIL) - { - ListCell *l1; - ListCell *l2; - ListCell *l3; - ListCell *l4; - ListCell *l5; - int colnum = 0; - - appendStringInfoString(buf, " COLUMNS "); - forfive(l1, tf->colnames, l2, tf->coltypes, l3, tf->coltypmods, - l4, tf->colexprs, l5, tf->coldefexprs) - { - char *colname = strVal(lfirst(l1)); - Oid typid = lfirst_oid(l2); - int32 typmod = lfirst_int(l3); - Node *colexpr = (Node *) lfirst(l4); - Node *coldefexpr = (Node *) lfirst(l5); - bool ordinality = (tf->ordinalitycol == colnum); - bool notnull = bms_is_member(colnum, tf->notnulls); - - if (colnum > 0) - appendStringInfoString(buf, ", "); - colnum++; - - appendStringInfo(buf, "%s %s", quote_identifier(colname), - ordinality ? "FOR ORDINALITY" : - format_type_with_typemod(typid, typmod)); - if (ordinality) - continue; - - if (coldefexpr != NULL) - { - appendStringInfoString(buf, " DEFAULT ("); - get_rule_expr((Node *) coldefexpr, context, showimplicit); - appendStringInfoChar(buf, ')'); - } - if (colexpr != NULL) - { - appendStringInfoString(buf, " PATH ("); - get_rule_expr((Node *) colexpr, context, showimplicit); - appendStringInfoChar(buf, ')'); - } - if (notnull) - appendStringInfoString(buf, " NOT NULL"); - } - } - - appendStringInfoChar(buf, ')'); -} - -/* ---------- - * get_from_clause - Parse back a FROM clause - * - * "prefix" is the keyword that denotes the start of the list of FROM - * elements. It is FROM when used to parse back SELECT and UPDATE, but - * is USING when parsing back DELETE. - * ---------- - */ -static void -get_from_clause(Query *query, const char *prefix, deparse_context *context) -{ - StringInfo buf = context->buf; - bool first = true; - ListCell *l; - - /* - * We use the query's jointree as a guide to what to print. However, we - * must ignore auto-added RTEs that are marked not inFromCl. (These can - * only appear at the top level of the jointree, so it's sufficient to - * check here.) This check also ensures we ignore the rule pseudo-RTEs - * for NEW and OLD. - */ - foreach(l, query->jointree->fromlist) - { - Node *jtnode = (Node *) lfirst(l); - - if (IsA(jtnode, RangeTblRef)) - { - int varno = ((RangeTblRef *) jtnode)->rtindex; - RangeTblEntry *rte = rt_fetch(varno, query->rtable); - - if (!rte->inFromCl) - continue; - } - - if (first) - { - appendContextKeyword(context, prefix, - -PRETTYINDENT_STD, PRETTYINDENT_STD, 2); - first = false; - - get_from_clause_item(jtnode, query, context); - } - else - { - StringInfoData itembuf; - - appendStringInfoString(buf, ", "); - - /* - * Put the new FROM item's text into itembuf so we can decide - * after we've got it whether or not it needs to go on a new line. - */ - initStringInfo(&itembuf); - context->buf = &itembuf; - - get_from_clause_item(jtnode, query, context); - - /* Restore context's output buffer */ - context->buf = buf; - - /* Consider line-wrapping if enabled */ - if (PRETTY_INDENT(context) && context->wrapColumn >= 0) - { - /* Does the new item start with a new line? */ - if (itembuf.len > 0 && itembuf.data[0] == '\n') - { - /* If so, we shouldn't add anything */ - /* instead, remove any trailing spaces currently in buf */ - removeStringInfoSpaces(buf); - } - else - { - char *trailing_nl; - - /* Locate the start of the current line in the buffer */ - trailing_nl = strrchr(buf->data, '\n'); - if (trailing_nl == NULL) - trailing_nl = buf->data; - else - trailing_nl++; - - /* - * Add a newline, plus some indentation, if the new item - * would cause an overflow. - */ - if (strlen(trailing_nl) + itembuf.len > context->wrapColumn) - appendContextKeyword(context, "", -PRETTYINDENT_STD, - PRETTYINDENT_STD, - PRETTYINDENT_VAR); - } - } - - /* Add the new item */ - appendStringInfoString(buf, itembuf.data); - - /* clean up */ - pfree(itembuf.data); - } - } -} - -static void -get_from_clause_item(Node *jtnode, Query *query, deparse_context *context) -{ - StringInfo buf = context->buf; - deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces); - - if (IsA(jtnode, RangeTblRef)) - { - int varno = ((RangeTblRef *) jtnode)->rtindex; - RangeTblEntry *rte = rt_fetch(varno, query->rtable); - char *refname = get_rtable_name(varno, context); - deparse_columns *colinfo = deparse_columns_fetch(varno, dpns); - RangeTblFunction *rtfunc1 = NULL; - bool printalias; - CitusRTEKind rteKind = GetRangeTblKind(rte); - - if (rte->lateral) - appendStringInfoString(buf, "LATERAL "); - - /* Print the FROM item proper */ - switch (rte->rtekind) - { - case RTE_RELATION: - /* Normal relation RTE */ - appendStringInfo(buf, "%s%s", - only_marker(rte), - generate_relation_or_shard_name(rte->relid, - context->distrelid, - context->shardid, - context->namespaces)); - break; - case RTE_SUBQUERY: - /* Subquery RTE */ - appendStringInfoChar(buf, '('); - get_query_def(rte->subquery, buf, context->namespaces, NULL, - context->prettyFlags, context->wrapColumn, - context->indentLevel); - appendStringInfoChar(buf, ')'); - break; - case RTE_FUNCTION: - /* if it's a shard, do differently */ - if (GetRangeTblKind(rte) == CITUS_RTE_SHARD) - { - char *fragmentSchemaName = NULL; - char *fragmentTableName = NULL; - - ExtractRangeTblExtraData(rte, NULL, &fragmentSchemaName, &fragmentTableName, NULL); - - /* use schema and table name from the remote alias */ - appendStringInfo(buf, "%s%s", - only_marker(rte), - generate_fragment_name(fragmentSchemaName, - fragmentTableName)); - break; - } - - /* Function RTE */ - rtfunc1 = (RangeTblFunction *) linitial(rte->functions); - - /* - * Omit ROWS FROM() syntax for just one function, unless it - * has both a coldeflist and WITH ORDINALITY. If it has both, - * we must use ROWS FROM() syntax to avoid ambiguity about - * whether the coldeflist includes the ordinality column. - */ - if (list_length(rte->functions) == 1 && - (rtfunc1->funccolnames == NIL || !rte->funcordinality)) - { - get_rule_expr_funccall(rtfunc1->funcexpr, context, true); - /* we'll print the coldeflist below, if it has one */ - } - else - { - bool all_unnest; - ListCell *lc; - - /* - * If all the function calls in the list are to unnest, - * and none need a coldeflist, then collapse the list back - * down to UNNEST(args). (If we had more than one - * built-in unnest function, this would get more - * difficult.) - * - * XXX This is pretty ugly, since it makes not-terribly- - * future-proof assumptions about what the parser would do - * with the output; but the alternative is to emit our - * nonstandard ROWS FROM() notation for what might have - * been a perfectly spec-compliant multi-argument - * UNNEST(). - */ - all_unnest = true; - foreach(lc, rte->functions) - { - RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc); - - if (!IsA(rtfunc->funcexpr, FuncExpr) || - ((FuncExpr *) rtfunc->funcexpr)->funcid != F_UNNEST_ANYARRAY || - rtfunc->funccolnames != NIL) - { - all_unnest = false; - break; - } - } - - if (all_unnest) - { - List *allargs = NIL; - - foreach(lc, rte->functions) - { - RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc); - List *args = ((FuncExpr *) rtfunc->funcexpr)->args; - - allargs = list_concat(allargs, args); - } - - appendStringInfoString(buf, "UNNEST("); - get_rule_expr((Node *) allargs, context, true); - appendStringInfoChar(buf, ')'); - } - else - { - int funcno = 0; - - appendStringInfoString(buf, "ROWS FROM("); - foreach(lc, rte->functions) - { - RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc); - - if (funcno > 0) - appendStringInfoString(buf, ", "); - get_rule_expr_funccall(rtfunc->funcexpr, context, true); - if (rtfunc->funccolnames != NIL) - { - /* Reconstruct the column definition list */ - appendStringInfoString(buf, " AS "); - get_from_clause_coldeflist(rtfunc, - NULL, - context); - } - funcno++; - } - appendStringInfoChar(buf, ')'); - } - /* prevent printing duplicate coldeflist below */ - rtfunc1 = NULL; - } - if (rte->funcordinality) - appendStringInfoString(buf, " WITH ORDINALITY"); - break; - case RTE_TABLEFUNC: - get_tablefunc(rte->tablefunc, context, true); - break; - case RTE_VALUES: - /* Values list RTE */ - appendStringInfoChar(buf, '('); - get_values_def(rte->values_lists, context); - appendStringInfoChar(buf, ')'); - break; - case RTE_CTE: - appendStringInfoString(buf, quote_identifier(rte->ctename)); - break; - default: - elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind); - break; - } - - /* Print the relation alias, if needed */ - printalias = false; - if (rte->alias != NULL) - { - /* Always print alias if user provided one */ - printalias = true; - } - else if (colinfo->printaliases) - { - /* Always print alias if we need to print column aliases */ - printalias = true; - } - else if (rte->rtekind == RTE_RELATION) - { - /* - * No need to print alias if it's same as relation name (this - * would normally be the case, but not if set_rtable_names had to - * resolve a conflict). - */ - if (strcmp(refname, get_relation_name(rte->relid)) != 0) - printalias = true; - } - else if (rte->rtekind == RTE_FUNCTION) - { - /* - * For a function RTE, always print alias. This covers possible - * renaming of the function and/or instability of the - * FigureColname rules for things that aren't simple functions. - * Note we'd need to force it anyway for the columndef list case. - */ - printalias = true; - } - else if (rte->rtekind == RTE_VALUES) - { - /* Alias is syntactically required for VALUES */ - printalias = true; - } - else if (rte->rtekind == RTE_CTE) - { - /* - * No need to print alias if it's same as CTE name (this would - * normally be the case, but not if set_rtable_names had to - * resolve a conflict). - */ - if (strcmp(refname, rte->ctename) != 0) - printalias = true; - } - else if (rte->rtekind == RTE_SUBQUERY) - { - /* subquery requires alias too */ - printalias = true; - } - if (printalias) - appendStringInfo(buf, " %s", quote_identifier(refname)); - - /* Print the column definitions or aliases, if needed */ - if (rtfunc1 && rtfunc1->funccolnames != NIL) - { - /* Reconstruct the columndef list, which is also the aliases */ - get_from_clause_coldeflist(rtfunc1, colinfo, context); - } - else if (GetRangeTblKind(rte) != CITUS_RTE_SHARD || - (rte->alias != NULL && rte->alias->colnames != NIL)) - { - /* Else print column aliases as needed */ - get_column_alias_list(colinfo, context); - } - /* check if column's are given aliases in distributed tables */ - else if (colinfo->parentUsing != NIL) - { - Assert(colinfo->printaliases); - get_column_alias_list(colinfo, context); - } - - /* Tablesample clause must go after any alias */ - if ((rteKind == CITUS_RTE_RELATION || rteKind == CITUS_RTE_SHARD) && - rte->tablesample) - { - get_tablesample_def(rte->tablesample, context); - } - } - else if (IsA(jtnode, JoinExpr)) - { - JoinExpr *j = (JoinExpr *) jtnode; - deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns); - bool need_paren_on_right; - - need_paren_on_right = PRETTY_PAREN(context) && - !IsA(j->rarg, RangeTblRef) && - !(IsA(j->rarg, JoinExpr) && ((JoinExpr *) j->rarg)->alias != NULL); - - if (!PRETTY_PAREN(context) || j->alias != NULL) - appendStringInfoChar(buf, '('); - - get_from_clause_item(j->larg, query, context); - - switch (j->jointype) - { - case JOIN_INNER: - if (j->quals) - appendContextKeyword(context, " JOIN ", - -PRETTYINDENT_STD, - PRETTYINDENT_STD, - PRETTYINDENT_JOIN); - else - appendContextKeyword(context, " CROSS JOIN ", - -PRETTYINDENT_STD, - PRETTYINDENT_STD, - PRETTYINDENT_JOIN); - break; - case JOIN_LEFT: - appendContextKeyword(context, " LEFT JOIN ", - -PRETTYINDENT_STD, - PRETTYINDENT_STD, - PRETTYINDENT_JOIN); - break; - case JOIN_FULL: - appendContextKeyword(context, " FULL JOIN ", - -PRETTYINDENT_STD, - PRETTYINDENT_STD, - PRETTYINDENT_JOIN); - break; - case JOIN_RIGHT: - appendContextKeyword(context, " RIGHT JOIN ", - -PRETTYINDENT_STD, - PRETTYINDENT_STD, - PRETTYINDENT_JOIN); - break; - default: - elog(ERROR, "unrecognized join type: %d", - (int) j->jointype); - } - - if (need_paren_on_right) - appendStringInfoChar(buf, '('); - get_from_clause_item(j->rarg, query, context); - if (need_paren_on_right) - appendStringInfoChar(buf, ')'); - - if (j->usingClause) - { - ListCell *lc; - bool first = true; - - appendStringInfoString(buf, " USING ("); - /* Use the assigned names, not what's in usingClause */ - foreach(lc, colinfo->usingNames) - { - char *colname = (char *) lfirst(lc); - - if (first) - first = false; - else - appendStringInfoString(buf, ", "); - appendStringInfoString(buf, quote_identifier(colname)); - } - appendStringInfoChar(buf, ')'); - - if (j->join_using_alias) - appendStringInfo(buf, " AS %s", - quote_identifier(j->join_using_alias->aliasname)); - } - else if (j->quals) - { - appendStringInfoString(buf, " ON "); - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, '('); - get_rule_expr(j->quals, context, false); - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, ')'); - } - else if (j->jointype != JOIN_INNER) - { - /* If we didn't say CROSS JOIN above, we must provide an ON */ - appendStringInfoString(buf, " ON TRUE"); - } - - if (!PRETTY_PAREN(context) || j->alias != NULL) - appendStringInfoChar(buf, ')'); - - /* Yes, it's correct to put alias after the right paren ... */ - if (j->alias != NULL) - { - /* - * Note that it's correct to emit an alias clause if and only if - * there was one originally. Otherwise we'd be converting a named - * join to unnamed or vice versa, which creates semantic - * subtleties we don't want. However, we might print a different - * alias name than was there originally. - */ - appendStringInfo(buf, " %s", - quote_identifier(get_rtable_name(j->rtindex, - context))); - get_column_alias_list(colinfo, context); - } - } - else - elog(ERROR, "unrecognized node type: %d", - (int) nodeTag(jtnode)); -} - -/* - * get_column_alias_list - print column alias list for an RTE - * - * Caller must already have printed the relation's alias name. - */ -static void -get_column_alias_list(deparse_columns *colinfo, deparse_context *context) -{ - StringInfo buf = context->buf; - int i; - bool first = true; - - /* Don't print aliases if not needed */ - if (!colinfo->printaliases) - return; - - for (i = 0; i < colinfo->num_new_cols; i++) - { - char *colname = colinfo->new_colnames[i]; - - if (first) - { - appendStringInfoChar(buf, '('); - first = false; - } - else - appendStringInfoString(buf, ", "); - appendStringInfoString(buf, quote_identifier(colname)); - } - if (!first) - appendStringInfoChar(buf, ')'); -} - -/* - * get_from_clause_coldeflist - reproduce FROM clause coldeflist - * - * When printing a top-level coldeflist (which is syntactically also the - * relation's column alias list), use column names from colinfo. But when - * printing a coldeflist embedded inside ROWS FROM(), we prefer to use the - * original coldeflist's names, which are available in rtfunc->funccolnames. - * Pass NULL for colinfo to select the latter behavior. - * - * The coldeflist is appended immediately (no space) to buf. Caller is - * responsible for ensuring that an alias or AS is present before it. - */ -static void -get_from_clause_coldeflist(RangeTblFunction *rtfunc, - deparse_columns *colinfo, - deparse_context *context) -{ - StringInfo buf = context->buf; - ListCell *l1; - ListCell *l2; - ListCell *l3; - ListCell *l4; - int i; - - appendStringInfoChar(buf, '('); - - i = 0; - forfour(l1, rtfunc->funccoltypes, - l2, rtfunc->funccoltypmods, - l3, rtfunc->funccolcollations, - l4, rtfunc->funccolnames) - { - Oid atttypid = lfirst_oid(l1); - int32 atttypmod = lfirst_int(l2); - Oid attcollation = lfirst_oid(l3); - char *attname; - - if (colinfo) - attname = colinfo->colnames[i]; - else - attname = strVal(lfirst(l4)); - - Assert(attname); /* shouldn't be any dropped columns here */ - - if (i > 0) - appendStringInfoString(buf, ", "); - appendStringInfo(buf, "%s %s", - quote_identifier(attname), - format_type_with_typemod(atttypid, atttypmod)); - if (OidIsValid(attcollation) && - attcollation != get_typcollation(atttypid)) - appendStringInfo(buf, " COLLATE %s", - generate_collation_name(attcollation)); - - i++; - } - - appendStringInfoChar(buf, ')'); -} - -/* - * get_tablesample_def - print a TableSampleClause - */ -static void -get_tablesample_def(TableSampleClause *tablesample, deparse_context *context) -{ - StringInfo buf = context->buf; - Oid argtypes[1]; - int nargs; - ListCell *l; - - /* - * We should qualify the handler's function name if it wouldn't be - * resolved by lookup in the current search path. - */ - argtypes[0] = INTERNALOID; - appendStringInfo(buf, " TABLESAMPLE %s (", - generate_function_name(tablesample->tsmhandler, 1, - NIL, argtypes, - false, NULL, EXPR_KIND_NONE)); - - nargs = 0; - foreach(l, tablesample->args) - { - if (nargs++ > 0) - appendStringInfoString(buf, ", "); - get_rule_expr((Node *) lfirst(l), context, false); - } - appendStringInfoChar(buf, ')'); - - if (tablesample->repeatable != NULL) - { - appendStringInfoString(buf, " REPEATABLE ("); - get_rule_expr((Node *) tablesample->repeatable, context, false); - appendStringInfoChar(buf, ')'); - } -} - - -/* - * get_opclass_name - fetch name of an index operator class - * - * The opclass name is appended (after a space) to buf. - * - * Output is suppressed if the opclass is the default for the given - * actual_datatype. (If you don't want this behavior, just pass - * InvalidOid for actual_datatype.) - */ -static void -get_opclass_name(Oid opclass, Oid actual_datatype, - StringInfo buf) -{ - HeapTuple ht_opc; - Form_pg_opclass opcrec; - char *opcname; - char *nspname; - - ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass)); - if (!HeapTupleIsValid(ht_opc)) - elog(ERROR, "cache lookup failed for opclass %u", opclass); - opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc); - - if (!OidIsValid(actual_datatype) || - GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass) - { - /* Okay, we need the opclass name. Do we need to qualify it? */ - opcname = NameStr(opcrec->opcname); - if (OpclassIsVisible(opclass)) - appendStringInfo(buf, " %s", quote_identifier(opcname)); - else - { - nspname = get_namespace_name(opcrec->opcnamespace); - appendStringInfo(buf, " %s.%s", - quote_identifier(nspname), - quote_identifier(opcname)); - } - } - ReleaseSysCache(ht_opc); -} - -/* - * processIndirection - take care of array and subfield assignment - * - * We strip any top-level FieldStore or assignment SubscriptingRef nodes that - * appear in the input, printing them as decoration for the base column - * name (which we assume the caller just printed). We might also need to - * strip CoerceToDomain nodes, but only ones that appear above assignment - * nodes. - * - * Returns the subexpression that's to be assigned. - */ -static Node * -processIndirection(Node *node, deparse_context *context) -{ - StringInfo buf = context->buf; - CoerceToDomain *cdomain = NULL; - - for (;;) - { - if (node == NULL) - break; - if (IsA(node, FieldStore)) - { - FieldStore *fstore = (FieldStore *) node; - Oid typrelid; - char *fieldname; - - /* lookup tuple type */ - typrelid = get_typ_typrelid(fstore->resulttype); - if (!OidIsValid(typrelid)) - elog(ERROR, "argument type %s of FieldStore is not a tuple type", - format_type_be(fstore->resulttype)); - - /* - * Print the field name. There should only be one target field in - * stored rules. There could be more than that in executable - * target lists, but this function cannot be used for that case. - */ - Assert(list_length(fstore->fieldnums) == 1); - fieldname = get_attname(typrelid, - linitial_int(fstore->fieldnums), false); - appendStringInfo(buf, ".%s", quote_identifier(fieldname)); - - /* - * We ignore arg since it should be an uninteresting reference to - * the target column or subcolumn. - */ - node = (Node *) linitial(fstore->newvals); - } - else if (IsA(node, SubscriptingRef)) - { - SubscriptingRef *sbsref = (SubscriptingRef *) node; - - if (sbsref->refassgnexpr == NULL) - break; - printSubscripts(sbsref, context); - - /* - * We ignore refexpr since it should be an uninteresting reference - * to the target column or subcolumn. - */ - node = (Node *) sbsref->refassgnexpr; - } - else if (IsA(node, CoerceToDomain)) - { - cdomain = (CoerceToDomain *) node; - /* If it's an explicit domain coercion, we're done */ - if (cdomain->coercionformat != COERCE_IMPLICIT_CAST) - break; - /* Tentatively descend past the CoerceToDomain */ - node = (Node *) cdomain->arg; - } - else - break; - } - - /* - * If we descended past a CoerceToDomain whose argument turned out not to - * be a FieldStore or array assignment, back up to the CoerceToDomain. - * (This is not enough to be fully correct if there are nested implicit - * CoerceToDomains, but such cases shouldn't ever occur.) - */ - if (cdomain && node == (Node *) cdomain->arg) - node = (Node *) cdomain; - - return node; -} - -static void -printSubscripts(SubscriptingRef *sbsref, deparse_context *context) -{ - StringInfo buf = context->buf; - ListCell *lowlist_item; - ListCell *uplist_item; - - lowlist_item = list_head(sbsref->reflowerindexpr); /* could be NULL */ - foreach(uplist_item, sbsref->refupperindexpr) - { - appendStringInfoChar(buf, '['); - if (lowlist_item) - { - /* If subexpression is NULL, get_rule_expr prints nothing */ - get_rule_expr((Node *) lfirst(lowlist_item), context, false); - appendStringInfoChar(buf, ':'); - lowlist_item = lnext(sbsref->reflowerindexpr, lowlist_item); - } - /* If subexpression is NULL, get_rule_expr prints nothing */ - get_rule_expr((Node *) lfirst(uplist_item), context, false); - appendStringInfoChar(buf, ']'); - } -} - -/* - * get_relation_name - * Get the unqualified name of a relation specified by OID - * - * This differs from the underlying get_rel_name() function in that it will - * throw error instead of silently returning NULL if the OID is bad. - */ -static char * -get_relation_name(Oid relid) -{ - char *relname = get_rel_name(relid); - - if (!relname) - elog(ERROR, "cache lookup failed for relation %u", relid); - return relname; -} - -/* - * generate_relation_or_shard_name - * Compute the name to display for a relation or shard - * - * If the provided relid is equal to the provided distrelid, this function - * returns a shard-extended relation name; otherwise, it falls through to a - * simple generate_relation_name call. - */ -static char * -generate_relation_or_shard_name(Oid relid, Oid distrelid, int64 shardid, - List *namespaces) -{ - char *relname = NULL; - - if (relid == distrelid) - { - relname = get_relation_name(relid); - - if (shardid > 0) - { - Oid schemaOid = get_rel_namespace(relid); - char *schemaName = get_namespace_name(schemaOid); - - AppendShardIdToName(&relname, shardid); - - relname = quote_qualified_identifier(schemaName, relname); - } - } - else - { - relname = generate_relation_name(relid, namespaces); - } - - return relname; -} - -/* - * generate_relation_name - * Compute the name to display for a relation specified by OID - * - * The result includes all necessary quoting and schema-prefixing. - * - * If namespaces isn't NIL, it must be a list of deparse_namespace nodes. - * We will forcibly qualify the relation name if it equals any CTE name - * visible in the namespace list. - */ -char * -generate_relation_name(Oid relid, List *namespaces) -{ - HeapTuple tp; - Form_pg_class reltup; - bool need_qual; - ListCell *nslist; - char *relname; - char *nspname; - char *result; - - tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid)); - if (!HeapTupleIsValid(tp)) - elog(ERROR, "cache lookup failed for relation %u", relid); - reltup = (Form_pg_class) GETSTRUCT(tp); - relname = NameStr(reltup->relname); - - /* Check for conflicting CTE name */ - need_qual = false; - foreach(nslist, namespaces) - { - deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist); - ListCell *ctlist; - - foreach(ctlist, dpns->ctes) - { - CommonTableExpr *cte = (CommonTableExpr *) lfirst(ctlist); - - if (strcmp(cte->ctename, relname) == 0) - { - need_qual = true; - break; - } - } - if (need_qual) - break; - } - - /* Otherwise, qualify the name if not visible in search path */ - if (!need_qual) - need_qual = !RelationIsVisible(relid); - - if (need_qual) - nspname = get_namespace_name(reltup->relnamespace); - else - nspname = NULL; - - result = quote_qualified_identifier(nspname, relname); - - ReleaseSysCache(tp); - - return result; -} - - -/* - * generate_rte_shard_name returns the qualified name of the shard given a - * CITUS_RTE_SHARD range table entry. - */ -static char * -generate_rte_shard_name(RangeTblEntry *rangeTableEntry) -{ - char *shardSchemaName = NULL; - char *shardTableName = NULL; - - Assert(GetRangeTblKind(rangeTableEntry) == CITUS_RTE_SHARD); - - ExtractRangeTblExtraData(rangeTableEntry, NULL, &shardSchemaName, &shardTableName, - NULL); - - return generate_fragment_name(shardSchemaName, shardTableName); -} - - -/* - * generate_fragment_name - * Compute the name to display for a shard or merged table - * - * The result includes all necessary quoting and schema-prefixing. The schema - * name can be NULL for regular shards. For merged tables, they are always - * declared within a job-specific schema, and therefore can't have null schema - * names. - */ -static char * -generate_fragment_name(char *schemaName, char *tableName) -{ - StringInfo fragmentNameString = makeStringInfo(); - - if (schemaName != NULL) - { - appendStringInfo(fragmentNameString, "%s.%s", quote_identifier(schemaName), - quote_identifier(tableName)); - } - else - { - appendStringInfoString(fragmentNameString, quote_identifier(tableName)); - } - - return fragmentNameString->data; -} - -/* - * generate_function_name - * Compute the name to display for a function specified by OID, - * given that it is being called with the specified actual arg names and - * types. (Those matter because of ambiguous-function resolution rules.) - * - * If we're dealing with a potentially variadic function (in practice, this - * means a FuncExpr or Aggref, not some other way of calling a function), then - * has_variadic must specify whether variadic arguments have been merged, - * and *use_variadic_p will be set to indicate whether to print VARIADIC in - * the output. For non-FuncExpr cases, has_variadic should be false and - * use_variadic_p can be NULL. - * - * The result includes all necessary quoting and schema-prefixing. - */ -static char * -generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes, - bool has_variadic, bool *use_variadic_p, - ParseExprKind special_exprkind) -{ - char *result; - HeapTuple proctup; - Form_pg_proc procform; - char *proname; - bool use_variadic; - char *nspname; - FuncDetailCode p_result; - Oid p_funcid; - Oid p_rettype; - bool p_retset; - int p_nvargs; - Oid p_vatype; - Oid *p_true_typeids; - bool force_qualify = false; - - proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); - if (!HeapTupleIsValid(proctup)) - elog(ERROR, "cache lookup failed for function %u", funcid); - procform = (Form_pg_proc) GETSTRUCT(proctup); - proname = NameStr(procform->proname); - - /* - * Due to parser hacks to avoid needing to reserve CUBE, we need to force - * qualification in some special cases. - */ - if (special_exprkind == EXPR_KIND_GROUP_BY) - { - if (strcmp(proname, "cube") == 0 || strcmp(proname, "rollup") == 0) - force_qualify = true; - } - - /* - * Determine whether VARIADIC should be printed. We must do this first - * since it affects the lookup rules in func_get_detail(). - * - * Currently, we always print VARIADIC if the function has a merged - * variadic-array argument. Note that this is always the case for - * functions taking a VARIADIC argument type other than VARIADIC ANY. - * - * In principle, if VARIADIC wasn't originally specified and the array - * actual argument is deconstructable, we could print the array elements - * separately and not print VARIADIC, thus more nearly reproducing the - * original input. For the moment that seems like too much complication - * for the benefit, and anyway we do not know whether VARIADIC was - * originally specified if it's a non-ANY type. - */ - if (use_variadic_p) - { - /* Parser should not have set funcvariadic unless fn is variadic */ - Assert(!has_variadic || OidIsValid(procform->provariadic)); - use_variadic = has_variadic; - *use_variadic_p = use_variadic; - } - else - { - Assert(!has_variadic); - use_variadic = false; - } - - /* - * The idea here is to schema-qualify only if the parser would fail to - * resolve the correct function given the unqualified func name with the - * specified argtypes and VARIADIC flag. But if we already decided to - * force qualification, then we can skip the lookup and pretend we didn't - * find it. - */ - if (!force_qualify) - p_result = func_get_detail(list_make1(makeString(proname)), - NIL, argnames, nargs, argtypes, - !use_variadic, true, false, - &p_funcid, &p_rettype, - &p_retset, &p_nvargs, &p_vatype, - &p_true_typeids, NULL); - else - { - p_result = FUNCDETAIL_NOTFOUND; - p_funcid = InvalidOid; - } - - if ((p_result == FUNCDETAIL_NORMAL || - p_result == FUNCDETAIL_AGGREGATE || - p_result == FUNCDETAIL_WINDOWFUNC) && - p_funcid == funcid) - nspname = NULL; - else - nspname = get_namespace_name(procform->pronamespace); - - result = quote_qualified_identifier(nspname, proname); - - ReleaseSysCache(proctup); - - return result; -} - -/* - * generate_operator_name - * Compute the name to display for an operator specified by OID, - * given that it is being called with the specified actual arg types. - * (Arg types matter because of ambiguous-operator resolution rules. - * Pass InvalidOid for unused arg of a unary operator.) - * - * The result includes all necessary quoting and schema-prefixing, - * plus the OPERATOR() decoration needed to use a qualified operator name - * in an expression. - */ -char * -generate_operator_name(Oid operid, Oid arg1, Oid arg2) -{ - StringInfoData buf; - HeapTuple opertup; - Form_pg_operator operform; - char *oprname; - char *nspname; - - initStringInfo(&buf); - - opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operid)); - if (!HeapTupleIsValid(opertup)) - elog(ERROR, "cache lookup failed for operator %u", operid); - operform = (Form_pg_operator) GETSTRUCT(opertup); - oprname = NameStr(operform->oprname); - - /* - * Unlike generate_operator_name() in postgres/src/backend/utils/adt/ruleutils.c, - * we don't check if the operator is in current namespace or not. This is - * because this check is costly when the operator is not in current namespace. - */ - nspname = get_namespace_name(operform->oprnamespace); - Assert(nspname != NULL); - appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname)); - appendStringInfoString(&buf, oprname); - appendStringInfoChar(&buf, ')'); - - ReleaseSysCache(opertup); - - return buf.data; -} - -/* - * get_one_range_partition_bound_string - * A C string representation of one range partition bound - */ -char * -get_range_partbound_string(List *bound_datums) -{ - deparse_context context; - StringInfo buf = makeStringInfo(); - ListCell *cell; - char *sep; - - memset(&context, 0, sizeof(deparse_context)); - context.buf = buf; - - appendStringInfoChar(buf, '('); - sep = ""; - foreach(cell, bound_datums) - { - PartitionRangeDatum *datum = - lfirst_node(PartitionRangeDatum, cell); - - appendStringInfoString(buf, sep); - if (datum->kind == PARTITION_RANGE_DATUM_MINVALUE) - appendStringInfoString(buf, "MINVALUE"); - else if (datum->kind == PARTITION_RANGE_DATUM_MAXVALUE) - appendStringInfoString(buf, "MAXVALUE"); - else - { - Const *val = castNode(Const, datum->value); - - get_const_expr(val, &context, -1); - } - sep = ", "; - } - appendStringInfoChar(buf, ')'); - - return buf->data; -} - -/* - * Collect a list of OIDs of all sequences owned by the specified relation, - * and column if specified. If deptype is not zero, then only find sequences - * with the specified dependency type. - */ -List * -getOwnedSequences_internal(Oid relid, AttrNumber attnum, char deptype) -{ - List *result = NIL; - Relation depRel; - ScanKeyData key[3]; - SysScanDesc scan; - HeapTuple tup; - - depRel = table_open(DependRelationId, AccessShareLock); - - ScanKeyInit(&key[0], - Anum_pg_depend_refclassid, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(RelationRelationId)); - ScanKeyInit(&key[1], - Anum_pg_depend_refobjid, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(relid)); - if (attnum) - ScanKeyInit(&key[2], - Anum_pg_depend_refobjsubid, - BTEqualStrategyNumber, F_INT4EQ, - Int32GetDatum(attnum)); - - scan = systable_beginscan(depRel, DependReferenceIndexId, true, - NULL, attnum ? 3 : 2, key); - - while (HeapTupleIsValid(tup = systable_getnext(scan))) - { - Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup); - - /* - * We assume any auto or internal dependency of a sequence on a column - * must be what we are looking for. (We need the relkind test because - * indexes can also have auto dependencies on columns.) - */ - if (deprec->classid == RelationRelationId && - deprec->objsubid == 0 && - deprec->refobjsubid != 0 && - (deprec->deptype == DEPENDENCY_AUTO || deprec->deptype == DEPENDENCY_INTERNAL) && - get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE) - { - if (!deptype || deprec->deptype == deptype) - result = lappend_oid(result, deprec->objid); - } - } - - systable_endscan(scan); - - table_close(depRel, AccessShareLock); - - return result; -} - -#endif /* (PG_VERSION_NUM >= PG_VERSION_14) && (PG_VERSION_NUM < PG_VERSION_15) */ diff --git a/src/backend/distributed/executor/adaptive_executor.c b/src/backend/distributed/executor/adaptive_executor.c index 9f98ad9cf..f276b3df1 100644 --- a/src/backend/distributed/executor/adaptive_executor.c +++ b/src/backend/distributed/executor/adaptive_executor.c @@ -718,10 +718,8 @@ static void RebuildWaitEventSetForSessions(DistributedExecution *execution); static void AddLatchWaitEventToExecution(DistributedExecution *execution); static void ProcessWaitEvents(DistributedExecution *execution, WaitEvent *events, int eventCount, bool *cancellationReceived); -#if PG_VERSION_NUM >= PG_VERSION_15 static void RemoteSocketClosedForAnySession(DistributedExecution *execution); static void ProcessWaitEventsForSocketClosed(WaitEvent *events, int eventCount); -#endif static long MillisecondsBetweenTimestamps(instr_time startTime, instr_time endTime); static uint64 MicrosecondsBetweenTimestamps(instr_time startTime, instr_time endTime); static int WorkerPoolCompare(const void *lhsKey, const void *rhsKey); @@ -1784,11 +1782,8 @@ FindOrCreateWorkerSession(WorkerPool *workerPool, MultiConnection *connection) session->commandsSent = 0; session->waitEventSetIndex = WAIT_EVENT_SET_INDEX_NOT_INITIALIZED; -#if PG_VERSION_NUM >= PG_VERSION_15 - /* always detect closed sockets */ UpdateConnectionWaitFlags(session, WL_SOCKET_CLOSED); -#endif dlist_init(&session->pendingTaskQueue); dlist_init(&session->readyTaskQueue); @@ -1832,7 +1827,6 @@ FindOrCreateWorkerSession(WorkerPool *workerPool, MultiConnection *connection) * the events, even ignores cancellation events. Future callers of this * function should consider its limitations. */ -#if PG_VERSION_NUM >= PG_VERSION_15 static void RemoteSocketClosedForAnySession(DistributedExecution *execution) { @@ -1850,9 +1844,6 @@ RemoteSocketClosedForAnySession(DistributedExecution *execution) } -#endif - - /* * SequentialRunDistributedExecution gets a distributed execution and * executes each individual task in the execution sequentially, one @@ -2188,8 +2179,6 @@ ProcessWaitEvents(DistributedExecution *execution, WaitEvent *events, int eventC } -#if PG_VERSION_NUM >= PG_VERSION_15 - /* * ProcessWaitEventsForSocketClosed mainly checks for WL_SOCKET_CLOSED event. * If WL_SOCKET_CLOSED is found, the function sets the underlying connection's @@ -2222,9 +2211,6 @@ ProcessWaitEventsForSocketClosed(WaitEvent *events, int eventCount) } -#endif - - /* * ManageWorkerPool ensures the worker pool has the appropriate number of connections * based on the number of pending tasks. @@ -2719,7 +2705,6 @@ OpenNewConnections(WorkerPool *workerPool, int newConnectionCount, * Instead, we prefer this slight difference, which in effect has almost no * difference, but doing things in different points in time. */ -#if PG_VERSION_NUM >= PG_VERSION_15 /* we added new connections, rebuild the waitEventSet */ RebuildWaitEventSetForSessions(execution); @@ -2739,9 +2724,6 @@ OpenNewConnections(WorkerPool *workerPool, int newConnectionCount, * of the execution. */ AddLatchWaitEventToExecution(execution); -#else - execution->rebuildWaitEventSet = true; -#endif WorkerSession *session = NULL; foreach_declared_ptr(session, newSessionsList) @@ -3678,13 +3660,8 @@ UpdateConnectionWaitFlags(WorkerSession *session, int waitFlags) return; } -#if PG_VERSION_NUM >= PG_VERSION_15 - /* always detect closed sockets */ connection->waitFlags = waitFlags | WL_SOCKET_CLOSED; -#else - connection->waitFlags = waitFlags; -#endif /* without signalling the execution, the flag changes won't be reflected */ execution->waitFlagsChanged = true; @@ -3709,13 +3686,11 @@ CheckConnectionReady(WorkerSession *session) return false; } -#if PG_VERSION_NUM >= PG_VERSION_15 if ((session->latestUnconsumedWaitEvents & WL_SOCKET_CLOSED) != 0) { connection->connectionState = MULTI_CONNECTION_LOST; return false; } -#endif /* try to send all pending data */ int sendStatus = PQflush(connection->pgConn); diff --git a/src/backend/distributed/executor/query_stats.c b/src/backend/distributed/executor/query_stats.c index ce6179b96..319041b56 100644 --- a/src/backend/distributed/executor/query_stats.c +++ b/src/backend/distributed/executor/query_stats.c @@ -140,19 +140,6 @@ static void CitusQueryStatsRemoveExpiredEntries(HTAB *existingQueryIdHash); void InitializeCitusQueryStats(void) { -/* on PG 15, we use shmem_request_hook_type */ -#if PG_VERSION_NUM < PG_VERSION_15 - - /* allocate shared memory */ - if (!IsUnderPostmaster) - { - RequestAddinShmemSpace(CitusQueryStatsSharedMemSize()); - - elog(LOG, "requesting named LWLockTranch for %s", STATS_SHARED_MEM_NAME); - RequestNamedLWLockTranche(STATS_SHARED_MEM_NAME, 1); - } -#endif - /* Install hook */ prev_shmem_startup_hook = shmem_startup_hook; shmem_startup_hook = CitusQueryStatsShmemStartup; diff --git a/src/backend/distributed/metadata/dependency.c b/src/backend/distributed/metadata/dependency.c index 2569b58fc..36db39bab 100644 --- a/src/backend/distributed/metadata/dependency.c +++ b/src/backend/distributed/metadata/dependency.c @@ -1716,13 +1716,11 @@ ExpandCitusSupportedTypes(ObjectAddressCollector *collector, ObjectAddress targe /* * As of PostgreSQL 15, the same applies to schemas. */ -#if PG_VERSION_NUM >= PG_VERSION_15 List *schemaIdList = GetPublicationSchemas(publicationId); List *schemaDependencyList = CreateObjectAddressDependencyDefList(NamespaceRelationId, schemaIdList); result = list_concat(result, schemaDependencyList); -#endif break; } diff --git a/src/backend/distributed/metadata/metadata_sync.c b/src/backend/distributed/metadata/metadata_sync.c index e4d901d39..f73856169 100644 --- a/src/backend/distributed/metadata/metadata_sync.c +++ b/src/backend/distributed/metadata/metadata_sync.c @@ -1750,48 +1750,6 @@ GetSequencesFromAttrDef(Oid attrdefOid) } -#if PG_VERSION_NUM < PG_VERSION_15 - -/* - * Given a pg_attrdef OID, return the relation OID and column number of - * the owning column (represented as an ObjectAddress for convenience). - * - * Returns InvalidObjectAddress if there is no such pg_attrdef entry. - */ -ObjectAddress -GetAttrDefaultColumnAddress(Oid attrdefoid) -{ - ObjectAddress result = InvalidObjectAddress; - ScanKeyData skey[1]; - HeapTuple tup; - - Relation attrdef = table_open(AttrDefaultRelationId, AccessShareLock); - ScanKeyInit(&skey[0], - Anum_pg_attrdef_oid, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(attrdefoid)); - SysScanDesc scan = systable_beginscan(attrdef, AttrDefaultOidIndexId, true, - NULL, 1, skey); - - if (HeapTupleIsValid(tup = systable_getnext(scan))) - { - Form_pg_attrdef atdform = (Form_pg_attrdef) GETSTRUCT(tup); - - result.classId = RelationRelationId; - result.objectId = atdform->adrelid; - result.objectSubId = atdform->adnum; - } - - systable_endscan(scan); - table_close(attrdef, AccessShareLock); - - return result; -} - - -#endif - - /* * GetAttrDefsFromSequence returns a list of attrdef OIDs that have * a dependency on the given sequence @@ -3113,7 +3071,6 @@ SyncNodeMetadataToNodesMain(Datum main_arg) PopActiveSnapshot(); CommitTransactionCommand(); - ProcessCompletedNotifies(); if (syncedAllNodes) { diff --git a/src/backend/distributed/metadata/pg_get_object_address_13_14_15.c b/src/backend/distributed/metadata/pg_get_object_address_13_14_15.c index abe378cdb..bd9b84e81 100644 --- a/src/backend/distributed/metadata/pg_get_object_address_13_14_15.c +++ b/src/backend/distributed/metadata/pg_get_object_address_13_14_15.c @@ -283,9 +283,7 @@ PgGetObjectAddress(char *ttype, ArrayType *namearr, ArrayType *argsarr) case OBJECT_FDW: case OBJECT_FOREIGN_SERVER: case OBJECT_LANGUAGE: -#if PG_VERSION_NUM >= PG_VERSION_15 case OBJECT_PARAMETER_ACL: -#endif case OBJECT_PUBLICATION: case OBJECT_ROLE: case OBJECT_SCHEMA: @@ -323,9 +321,7 @@ PgGetObjectAddress(char *ttype, ArrayType *namearr, ArrayType *argsarr) break; } -#if PG_VERSION_NUM >= PG_VERSION_15 case OBJECT_PUBLICATION_NAMESPACE: -#endif case OBJECT_USER_MAPPING: { objnode = (Node *) list_make2(linitial(name), linitial(args)); diff --git a/src/backend/distributed/planner/combine_query_planner.c b/src/backend/distributed/planner/combine_query_planner.c index f81ade91c..c8ab2a4b3 100644 --- a/src/backend/distributed/planner/combine_query_planner.c +++ b/src/backend/distributed/planner/combine_query_planner.c @@ -136,11 +136,8 @@ CreateCitusCustomScanPath(PlannerInfo *root, RelOptInfo *relOptInfo, path->custom_path.path.pathtarget = relOptInfo->reltarget; path->custom_path.path.parent = relOptInfo; -#if (PG_VERSION_NUM >= PG_VERSION_15) - /* necessary to avoid extra Result node in PG15 */ path->custom_path.flags = CUSTOMPATH_SUPPORT_PROJECTION; -#endif /* * The 100k rows we put on the cost of the path is kind of arbitrary and could be diff --git a/src/backend/distributed/planner/distributed_planner.c b/src/backend/distributed/planner/distributed_planner.c index 06f556c88..c0e6de877 100644 --- a/src/backend/distributed/planner/distributed_planner.c +++ b/src/backend/distributed/planner/distributed_planner.c @@ -1443,13 +1443,8 @@ FinalizePlan(PlannedStmt *localPlan, DistributedPlan *distributedPlan) customScan->custom_private = list_make1(distributedPlanData); -#if (PG_VERSION_NUM >= PG_VERSION_15) - /* necessary to avoid extra Result node in PG15 */ customScan->flags = CUSTOMPATH_SUPPORT_BACKWARD_SCAN | CUSTOMPATH_SUPPORT_PROJECTION; -#else - customScan->flags = CUSTOMPATH_SUPPORT_BACKWARD_SCAN; -#endif /* * Fast path queries cannot have any subplans by definition, so skip diff --git a/src/backend/distributed/planner/merge_planner.c b/src/backend/distributed/planner/merge_planner.c index 9c0ba3cd3..e1d917ca0 100644 --- a/src/backend/distributed/planner/merge_planner.c +++ b/src/backend/distributed/planner/merge_planner.c @@ -38,8 +38,6 @@ #include "distributed/shard_pruning.h" #include "distributed/shared_library_init.h" -#if PG_VERSION_NUM >= PG_VERSION_15 - static int SourceResultPartitionColumnIndex(Query *mergeQuery, List *sourceTargetList, CitusTableCacheEntry *targetRelation); @@ -100,8 +98,6 @@ static char * MergeCommandResultIdPrefix(uint64 planId); static void ErrorIfMergeHasReturningList(Query *query); static Node * GetMergeJoinCondition(Query *mergeQuery); -#endif - /* * CreateMergePlan @@ -118,13 +114,6 @@ CreateMergePlan(uint64 planId, Query *originalQuery, Query *query, PlannerRestrictionContext *plannerRestrictionContext, ParamListInfo boundParams) { - /* function is void for pre-15 versions of Postgres */ - #if PG_VERSION_NUM < PG_VERSION_15 - - ereport(ERROR, (errmsg("MERGE is not supported in pre-15 Postgres versions"))); - - #else - Oid targetRelationId = ModifyQueryResultRelationId(originalQuery); /* @@ -153,8 +142,6 @@ CreateMergePlan(uint64 planId, Query *originalQuery, Query *query, } return distributedPlan; - - #endif } @@ -184,9 +171,6 @@ GetMergeJoinTree(Query *mergeQuery) } -#if PG_VERSION_NUM >= PG_VERSION_15 - - /* * GetMergeJoinCondition returns the quals of the ON condition */ @@ -1443,9 +1427,6 @@ SourceResultPartitionColumnIndex(Query *mergeQuery, List *sourceTargetList, } -#endif - - /* * ExtractMergeSourceRangeTableEntry returns the range table entry of source * table or source query in USING clause. @@ -1453,13 +1434,6 @@ SourceResultPartitionColumnIndex(Query *mergeQuery, List *sourceTargetList, RangeTblEntry * ExtractMergeSourceRangeTableEntry(Query *query, bool joinSourceOk) { - /* function is void for pre-15 versions of Postgres */ - #if PG_VERSION_NUM < PG_VERSION_15 - - ereport(ERROR, (errmsg("MERGE is not supported in pre-15 Postgres versions"))); - - #else - Assert(IsMergeQuery(query)); List *fromList = query->jointree->fromlist; @@ -1498,8 +1472,6 @@ ExtractMergeSourceRangeTableEntry(Query *query, bool joinSourceOk) RangeTblEntry *subqueryRte = rt_fetch(reference->rtindex, query->rtable); return subqueryRte; - - #endif } @@ -1516,13 +1488,6 @@ ExtractMergeSourceRangeTableEntry(Query *query, bool joinSourceOk) Var * FetchAndValidateInsertVarIfExists(Oid targetRelationId, Query *query) { - /* function is void for pre-15 versions of Postgres */ - #if PG_VERSION_NUM < PG_VERSION_15 - - ereport(ERROR, (errmsg("MERGE is not supported in pre-15 Postgres versions"))); - - #else - Assert(IsMergeQuery(query)); if (!IsCitusTableType(targetRelationId, DISTRIBUTED_TABLE)) @@ -1593,8 +1558,6 @@ FetchAndValidateInsertVarIfExists(Oid targetRelationId, Query *query) } return NULL; - - #endif } diff --git a/src/backend/distributed/planner/multi_explain.c b/src/backend/distributed/planner/multi_explain.c index 8b57b5a12..370e487b4 100644 --- a/src/backend/distributed/planner/multi_explain.c +++ b/src/backend/distributed/planner/multi_explain.c @@ -1287,8 +1287,8 @@ worker_save_query_explain_analyze(PG_FUNCTION_ARGS) } /* resolve OIDs of unknown (user-defined) types */ - Query *analyzedQuery = parse_analyze_varparams_compat(parseTree, queryString, - ¶mTypes, &numParams, NULL); + Query *analyzedQuery = parse_analyze_varparams(parseTree, queryString, + ¶mTypes, &numParams, NULL); /* pg_rewrite_query is a wrapper around QueryRewrite with some debugging logic */ List *queryList = pg_rewrite_query(analyzedQuery); diff --git a/src/backend/distributed/shardsplit/shardsplit_decoder.c b/src/backend/distributed/shardsplit/shardsplit_decoder.c index 20dd01b0c..837009530 100644 --- a/src/backend/distributed/shardsplit/shardsplit_decoder.c +++ b/src/backend/distributed/shardsplit/shardsplit_decoder.c @@ -122,11 +122,7 @@ update_replication_progress(LogicalDecodingContext *ctx, bool skipped_xact) */ if (ctx->end_xact || ++changes_count >= CHANGES_THRESHOLD) { -#if (PG_VERSION_NUM >= PG_VERSION_15) OutputPluginUpdateProgress(ctx, skipped_xact); -#else - OutputPluginUpdateProgress(ctx); -#endif changes_count = 0; } } diff --git a/src/backend/distributed/shared_library_init.c b/src/backend/distributed/shared_library_init.c index 7672c08ba..a4146062e 100644 --- a/src/backend/distributed/shared_library_init.c +++ b/src/backend/distributed/shared_library_init.c @@ -175,15 +175,11 @@ static bool FinishedStartupCitusBackend = false; static object_access_hook_type PrevObjectAccessHook = NULL; -#if PG_VERSION_NUM >= PG_VERSION_15 static shmem_request_hook_type prev_shmem_request_hook = NULL; -#endif void _PG_init(void); -#if PG_VERSION_NUM >= PG_VERSION_15 static void citus_shmem_request(void); -#endif static void CitusObjectAccessHook(ObjectAccessType access, Oid classId, Oid objectId, int subId, void *arg); static void DoInitialCleanup(void); @@ -476,10 +472,8 @@ _PG_init(void) original_client_auth_hook = ClientAuthentication_hook; ClientAuthentication_hook = CitusAuthHook; -#if PG_VERSION_NUM >= PG_VERSION_15 prev_shmem_request_hook = shmem_request_hook; shmem_request_hook = citus_shmem_request; -#endif InitializeMaintenanceDaemon(); InitializeMaintenanceDaemonForMainDb(); @@ -604,8 +598,6 @@ AdjustDynamicLibraryPathForCdcDecoders(void) } -#if PG_VERSION_NUM >= PG_VERSION_15 - /* * Requests any additional shared memory required for citus. */ @@ -626,9 +618,6 @@ citus_shmem_request(void) } -#endif - - /* * DoInitialCleanup does cleanup at start time. * Currently it: diff --git a/src/backend/distributed/test/fake_am.c b/src/backend/distributed/test/fake_am.c index 928051942..8829d0d8b 100644 --- a/src/backend/distributed/test/fake_am.c +++ b/src/backend/distributed/test/fake_am.c @@ -310,7 +310,7 @@ fake_relation_set_new_filenode(Relation rel, */ *minmulti = GetOldestMultiXactId(); - SMgrRelation srel = RelationCreateStorage_compat(*newrnode, persistence, true); + SMgrRelation srel = RelationCreateStorage(*newrnode, persistence, true); /* * If required, set up an init fork for an unlogged table so that it can diff --git a/src/backend/distributed/test/shared_connection_counters.c b/src/backend/distributed/test/shared_connection_counters.c index c59602887..e5c685e65 100644 --- a/src/backend/distributed/test/shared_connection_counters.c +++ b/src/backend/distributed/test/shared_connection_counters.c @@ -49,13 +49,8 @@ makeIntConst(int val, int location) { A_Const *n = makeNode(A_Const); -#if PG_VERSION_NUM >= PG_VERSION_15 n->val.ival.type = T_Integer; n->val.ival.ival = val; -#else - n->val.type = T_Integer; - n->val.val.ival = val; -#endif n->location = location; return (Node *) n; diff --git a/src/backend/distributed/transaction/backend_data.c b/src/backend/distributed/transaction/backend_data.c index 866b18fd2..19b03978e 100644 --- a/src/backend/distributed/transaction/backend_data.c +++ b/src/backend/distributed/transaction/backend_data.c @@ -519,15 +519,6 @@ UserHasPermissionToViewStatsOf(Oid currentUserId, Oid backendOwnedId) void InitializeBackendManagement(void) { -/* on PG 15, we use shmem_request_hook_type */ -#if PG_VERSION_NUM < PG_VERSION_15 - - /* allocate shared memory */ - if (!IsUnderPostmaster) - { - RequestAddinShmemSpace(BackendManagementShmemSize()); - } -#endif prev_shmem_startup_hook = shmem_startup_hook; shmem_startup_hook = BackendManagementShmemInit; } diff --git a/src/backend/distributed/utils/background_jobs.c b/src/backend/distributed/utils/background_jobs.c index a729776c7..911880dc7 100644 --- a/src/backend/distributed/utils/background_jobs.c +++ b/src/backend/distributed/utils/background_jobs.c @@ -1397,87 +1397,6 @@ CalculateBackoffDelay(int retryCount) } -#if PG_VERSION_NUM < PG_VERSION_15 -static const char * -error_severity(int elevel) -{ - const char *prefix; - - switch (elevel) - { - case DEBUG1: - case DEBUG2: - case DEBUG3: - case DEBUG4: - case DEBUG5: - { - prefix = gettext_noop("DEBUG"); - break; - } - - case LOG: - case LOG_SERVER_ONLY: - { - prefix = gettext_noop("LOG"); - break; - } - - case INFO: - { - prefix = gettext_noop("INFO"); - break; - } - - case NOTICE: - { - prefix = gettext_noop("NOTICE"); - break; - } - - case WARNING: - { - prefix = gettext_noop("WARNING"); - break; - } - - case WARNING_CLIENT_ONLY: - { - prefix = gettext_noop("WARNING"); - break; - } - - case ERROR: - { - prefix = gettext_noop("ERROR"); - break; - } - - case FATAL: - { - prefix = gettext_noop("FATAL"); - break; - } - - case PANIC: - { - prefix = gettext_noop("PANIC"); - break; - } - - default: - { - prefix = "???"; - break; - } - } - - return prefix; -} - - -#endif - - /* * bgw_generate_returned_message - * generates the message to be inserted into the job_run_details table diff --git a/src/backend/distributed/utils/citus_stat_tenants.c b/src/backend/distributed/utils/citus_stat_tenants.c index 6af5c0d58..1ca4fc6f1 100644 --- a/src/backend/distributed/utils/citus_stat_tenants.c +++ b/src/backend/distributed/utils/citus_stat_tenants.c @@ -15,6 +15,7 @@ #include "unistd.h" #include "access/hash.h" +#include "common/pg_prng.h" #include "executor/execdesc.h" #include "storage/ipc.h" #include "storage/lwlock.h" @@ -38,10 +39,6 @@ #include "distributed/tuplestore.h" #include "distributed/utils/citus_stat_tenants.h" -#if (PG_VERSION_NUM >= PG_VERSION_15) - #include "common/pg_prng.h" -#endif - static void AttributeMetricsIfApplicable(void); ExecutorEnd_hook_type prev_ExecutorEnd = NULL; @@ -298,13 +295,7 @@ AttributeTask(char *tenantId, int colocationId, CmdType commandType) /* If the tenant is not found in the hash table, we will track the query with a probability of StatTenantsSampleRateForNewTenants. */ if (!found) { -#if (PG_VERSION_NUM >= PG_VERSION_15) double randomValue = pg_prng_double(&pg_global_prng_state); -#else - - /* Generate a random double between 0 and 1 */ - double randomValue = (double) random() / MAX_RANDOM_VALUE; -#endif bool shouldTrackQuery = randomValue <= StatTenantsSampleRateForNewTenants; if (!shouldTrackQuery) { diff --git a/src/include/columnar/columnar_version_compat.h b/src/include/columnar/columnar_version_compat.h index d9b29cdb0..d6908aced 100644 --- a/src/include/columnar/columnar_version_compat.h +++ b/src/include/columnar/columnar_version_compat.h @@ -14,14 +14,6 @@ #include "pg_version_constants.h" -#if PG_VERSION_NUM >= PG_VERSION_15 -#define ExecARDeleteTriggers_compat(a, b, c, d, e, f) \ - ExecARDeleteTriggers(a, b, c, d, e, f) -#else -#define ExecARDeleteTriggers_compat(a, b, c, d, e, f) \ - ExecARDeleteTriggers(a, b, c, d, e) -#endif - #define ACLCHECK_OBJECT_TABLE OBJECT_TABLE #define ExplainPropertyLong(qlabel, value, es) \ diff --git a/src/include/distributed/commands.h b/src/include/distributed/commands.h index 7c18b2bab..a6e6bf6ec 100644 --- a/src/include/distributed/commands.h +++ b/src/include/distributed/commands.h @@ -560,13 +560,11 @@ extern List * PostprocessAlterSequenceSchemaStmt(Node *node, const char *querySt extern List * PreprocessAlterSequenceOwnerStmt(Node *node, const char *queryString, ProcessUtilityContext processUtilityContext); extern List * PostprocessAlterSequenceOwnerStmt(Node *node, const char *queryString); -#if (PG_VERSION_NUM >= PG_VERSION_15) extern List * PreprocessAlterSequencePersistenceStmt(Node *node, const char *queryString, ProcessUtilityContext processUtilityContext); extern List * PreprocessSequenceAlterTableStmt(Node *node, const char *queryString, ProcessUtilityContext processUtilityContext); -#endif extern List * PreprocessDropSequenceStmt(Node *node, const char *queryString, ProcessUtilityContext processUtilityContext); extern List * SequenceDropStmtObjectAddress(Node *stmt, bool missing_ok, bool @@ -582,10 +580,8 @@ extern List * AlterSequenceSchemaStmtObjectAddress(Node *node, bool missing_ok, isPostprocess); extern List * AlterSequenceOwnerStmtObjectAddress(Node *node, bool missing_ok, bool isPostprocess); -#if (PG_VERSION_NUM >= PG_VERSION_15) extern List * AlterSequencePersistenceStmtObjectAddress(Node *node, bool missing_ok, bool isPostprocess); -#endif extern List * RenameSequenceStmtObjectAddress(Node *node, bool missing_ok, bool isPostprocess); extern void ErrorIfUnsupportedSeqStmt(CreateSeqStmt *createSeqStmt); @@ -784,8 +780,6 @@ extern List * CreateTriggerStmtObjectAddress(Node *node, bool missingOk, bool isPostprocess); extern void CreateTriggerEventExtendNames(CreateTrigStmt *createTriggerStmt, char *schemaName, uint64 shardId); -extern List * PreprocessAlterTriggerRenameStmt(Node *node, const char *queryString, - ProcessUtilityContext processUtilityContext); extern List * PostprocessAlterTriggerRenameStmt(Node *node, const char *queryString); extern void AlterTriggerRenameEventExtendNames(RenameStmt *renameTriggerStmt, char *schemaName, uint64 shardId); diff --git a/src/include/distributed/deparser.h b/src/include/distributed/deparser.h index 4d4005c19..66c697f03 100644 --- a/src/include/distributed/deparser.h +++ b/src/include/distributed/deparser.h @@ -299,9 +299,7 @@ extern char * DeparseDropSequenceStmt(Node *node); extern char * DeparseRenameSequenceStmt(Node *node); extern char * DeparseAlterSequenceSchemaStmt(Node *node); extern char * DeparseAlterSequenceOwnerStmt(Node *node); -#if (PG_VERSION_NUM >= PG_VERSION_15) extern char * DeparseAlterSequencePersistenceStmt(Node *node); -#endif extern char * DeparseGrantOnSequenceStmt(Node *node); /* forward declarations for qualify_sequence_stmt.c */ @@ -309,9 +307,7 @@ extern void QualifyRenameSequenceStmt(Node *node); extern void QualifyDropSequenceStmt(Node *node); extern void QualifyAlterSequenceSchemaStmt(Node *node); extern void QualifyAlterSequenceOwnerStmt(Node *node); -#if (PG_VERSION_NUM >= PG_VERSION_15) extern void QualifyAlterSequencePersistenceStmt(Node *node); -#endif extern void QualifyGrantOnSequenceStmt(Node *node); #endif /* CITUS_DEPARSER_H */ diff --git a/src/include/distributed/distributed_planner.h b/src/include/distributed/distributed_planner.h index 23540f6f6..33a9c2fa8 100644 --- a/src/include/distributed/distributed_planner.h +++ b/src/include/distributed/distributed_planner.h @@ -28,11 +28,6 @@ #define CURSOR_OPT_FORCE_DISTRIBUTED 0x080000 -/* Hack to compile Citus on pre-MERGE Postgres versions */ -#if PG_VERSION_NUM < PG_VERSION_15 -#define CMD_MERGE CMD_UNKNOWN -#endif - /* level of planner calls */ extern int PlannerLevel; diff --git a/src/include/distributed/metadata_sync.h b/src/include/distributed/metadata_sync.h index 617eed705..29583f01f 100644 --- a/src/include/distributed/metadata_sync.h +++ b/src/include/distributed/metadata_sync.h @@ -130,9 +130,6 @@ extern List * IdentitySequenceDependencyCommandList(Oid targetRelationId); extern List * DDLCommandsForSequence(Oid sequenceOid, char *ownerName); extern List * GetSequencesFromAttrDef(Oid attrdefOid); -#if PG_VERSION_NUM < PG_VERSION_15 -ObjectAddress GetAttrDefaultColumnAddress(Oid attrdefoid); -#endif extern List * GetAttrDefsFromSequence(Oid seqOid); extern void GetDependentSequencesWithRelation(Oid relationId, List **seqInfoList, AttrNumber attnum, char depType); diff --git a/src/include/distributed/resource_lock.h b/src/include/distributed/resource_lock.h index 576d2bf15..b6f9fcfbe 100644 --- a/src/include/distributed/resource_lock.h +++ b/src/include/distributed/resource_lock.h @@ -177,9 +177,7 @@ IsNodeWideObjectClass(ObjectClass objectClass) case OCLASS_ROLE: case OCLASS_DATABASE: case OCLASS_TBLSPACE: -#if PG_VERSION_NUM >= PG_VERSION_15 case OCLASS_PARAMETER_ACL: -#endif #if PG_VERSION_NUM >= PG_VERSION_16 case OCLASS_ROLE_MEMBERSHIP: #endif diff --git a/src/include/pg_version_compat.h b/src/include/pg_version_compat.h index 9343cc310..a62d829ce 100644 --- a/src/include/pg_version_compat.h +++ b/src/include/pg_version_compat.h @@ -320,76 +320,6 @@ typedef RangeTblEntry RTEPermissionInfo; #endif -#if PG_VERSION_NUM >= PG_VERSION_15 -#define ProcessCompletedNotifies() -#define RelationCreateStorage_compat(a, b, c) RelationCreateStorage(a, b, c) -#define parse_analyze_varparams_compat(a, b, c, d, e) parse_analyze_varparams(a, b, c, d, \ - e) -#define CREATE_SEQUENCE_COMMAND \ - "CREATE %sSEQUENCE IF NOT EXISTS %s AS %s INCREMENT BY " INT64_FORMAT \ - " MINVALUE " INT64_FORMAT " MAXVALUE " INT64_FORMAT \ - " START WITH " INT64_FORMAT " CACHE " INT64_FORMAT " %sCYCLE" -#else - -#include "nodes/value.h" -#include "storage/smgr.h" -#include "utils/int8.h" -#include "utils/rel.h" - -typedef Value String; - -#ifdef HAVE_LONG_INT_64 -#define strtoi64(str, endptr, base) ((int64) strtol(str, endptr, base)) -#define strtou64(str, endptr, base) ((uint64) strtoul(str, endptr, base)) -#else -#define strtoi64(str, endptr, base) ((int64) strtoll(str, endptr, base)) -#define strtou64(str, endptr, base) ((uint64) strtoull(str, endptr, base)) -#endif -#define RelationCreateStorage_compat(a, b, c) RelationCreateStorage(a, b) -#define parse_analyze_varparams_compat(a, b, c, d, e) parse_analyze_varparams(a, b, c, d) -#define pgstat_init_relation(r) pgstat_initstats(r) -#define pg_analyze_and_rewrite_fixedparams(a, b, c, d, e) pg_analyze_and_rewrite(a, b, c, \ - d, e) -#define boolVal(v) intVal(v) -#define makeBoolean(val) makeInteger(val) - -static inline int64 -pg_strtoint64(char *s) -{ - int64 result; - (void) scanint8(s, false, &result); - return result; -} - - -/* - * RelationGetSmgr got backported in 13.10 and 14.7 so redefining it for any - * version higher causes compilation errors due to redefining of the function. - * We want to use it in all versions. So we backport it ourselves in earlier - * versions, and rely on the Postgres provided version in the later versions. - */ -#if PG_VERSION_NUM < 140007 -static inline SMgrRelation -RelationGetSmgr(Relation rel) -{ - if (unlikely(rel->rd_smgr == NULL)) - { - smgrsetowner(&(rel->rd_smgr), smgropen(rel->rd_node, rel->rd_backend)); - } - return rel->rd_smgr; -} - - -#endif - - -#define CREATE_SEQUENCE_COMMAND \ - "CREATE SEQUENCE IF NOT EXISTS %s AS %s INCREMENT BY " INT64_FORMAT \ - " MINVALUE " INT64_FORMAT " MAXVALUE " INT64_FORMAT \ - " START WITH " INT64_FORMAT " CACHE " INT64_FORMAT " %sCYCLE" - -#endif - #define SetListCellPtr(a, b) ((a)->ptr_value = (b)) #define RangeTableEntryFromNSItem(a) ((a)->p_rte) #define fcGetArgValue(fc, n) ((fc)->args[n].value) @@ -399,4 +329,9 @@ RelationGetSmgr(Relation rel) #define fcSetArg(fc, n, value) fcSetArgExt(fc, n, value, false) #define fcSetArgNull(fc, n) fcSetArgExt(fc, n, (Datum) 0, true) +#define CREATE_SEQUENCE_COMMAND \ + "CREATE %sSEQUENCE IF NOT EXISTS %s AS %s INCREMENT BY " INT64_FORMAT \ + " MINVALUE " INT64_FORMAT " MAXVALUE " INT64_FORMAT \ + " START WITH " INT64_FORMAT " CACHE " INT64_FORMAT " %sCYCLE" + #endif /* PG_VERSION_COMPAT_H */ diff --git a/src/include/pg_version_constants.h b/src/include/pg_version_constants.h index ba2a9a03e..c8bfd319e 100644 --- a/src/include/pg_version_constants.h +++ b/src/include/pg_version_constants.h @@ -11,7 +11,6 @@ #ifndef PG_VERSION_CONSTANTS #define PG_VERSION_CONSTANTS -#define PG_VERSION_14 140000 #define PG_VERSION_15 150000 #define PG_VERSION_16 160000 #define PG_VERSION_17 170000 diff --git a/src/test/regress/bin/normalize.sed b/src/test/regress/bin/normalize.sed index 4fe2cc673..25bc9c15d 100644 --- a/src/test/regress/bin/normalize.sed +++ b/src/test/regress/bin/normalize.sed @@ -108,19 +108,13 @@ s/(ERROR: |WARNING: |error:) invalid socket/\1 connection not open/g /^\s*invalid socket$/d # pg15 changes -# can be removed when dropping PG13&14 support -#if (PG_VERSION_NUM >= PG_VERSION_14) && (PG_VERSION_NUM < PG_VERSION_15) -# (This is not preprocessor directive, but a reminder for the developer that will drop PG14 support ) -s/is not a PostgreSQL server process/is not a PostgreSQL backend process/g s/ AS "\?column\?"//g -s/".*\.(.*)": (found .* removable)/"\1": \2/g # We ignore multiline error messages, and substitute first line with a single line # alternative that is used in some older libpq versions. s/(ERROR: |WARNING: |error:) server closed the connection unexpectedly/\1 connection not open/g /^\s*This probably means the server terminated abnormally$/d /^\s*before or while processing the request.$/d /^\s*connection not open$/d -#endif /* (PG_VERSION_NUM >= PG_VERSION_13) && (PG_VERSION_NUM < PG_VERSION_14) */ # intermediate_results s/(ERROR.*)pgsql_job_cache\/([0-9]+_[0-9]+_[0-9]+)\/(.*).data/\1pgsql_job_cache\/xx_x_xxx\/\3.data/g diff --git a/src/test/regress/expected/citus_local_tables_queries.out b/src/test/regress/expected/citus_local_tables_queries.out index 2b2761644..148e08a4b 100644 --- a/src/test/regress/expected/citus_local_tables_queries.out +++ b/src/test/regress/expected/citus_local_tables_queries.out @@ -1,17 +1,6 @@ -- -- CITUS_LOCAL_TABLES_QUERIES -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - t -(1 row) - \set VERBOSITY terse SET citus.next_shard_id TO 1509000; SET citus.shard_replication_factor TO 1; diff --git a/src/test/regress/expected/citus_local_tables_queries_0.out b/src/test/regress/expected/citus_local_tables_queries_0.out deleted file mode 100644 index 4da695c89..000000000 --- a/src/test/regress/expected/citus_local_tables_queries_0.out +++ /dev/null @@ -1,1168 +0,0 @@ --- --- CITUS_LOCAL_TABLES_QUERIES --- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - f -(1 row) - -\set VERBOSITY terse -SET citus.next_shard_id TO 1509000; -SET citus.shard_replication_factor TO 1; -SET citus.enable_local_execution TO ON; -SET citus.log_local_commands TO ON; -CREATE SCHEMA citus_local_table_queries; -SET search_path TO citus_local_table_queries; --- ensure that coordinator is added to pg_dist_node -SET client_min_messages to ERROR; -SELECT 1 FROM master_add_node('localhost', :master_port, groupId => 0); - ?column? ---------------------------------------------------------------------- - 1 -(1 row) - -RESET client_min_messages; -CREATE TABLE dummy_reference_table(a int unique, b int); -SELECT create_reference_table('dummy_reference_table'); - create_reference_table ---------------------------------------------------------------------- - -(1 row) - -CREATE TABLE citus_local_table(a int, b int); -ALTER TABLE citus_local_table ADD CONSTRAINT fkey_to_dummy_1 FOREIGN KEY (a) REFERENCES dummy_reference_table(a); -NOTICE: executing the command locally: SELECT worker_apply_inter_shard_ddl_command (1509001, 'citus_local_table_queries', 1509000, 'citus_local_table_queries', 'ALTER TABLE citus_local_table ADD CONSTRAINT fkey_to_dummy_1 FOREIGN KEY (a) REFERENCES dummy_reference_table(a);') -CREATE TABLE citus_local_table_2(a int, b int); -ALTER TABLE citus_local_table_2 ADD CONSTRAINT fkey_to_dummy_2 FOREIGN KEY (a) REFERENCES dummy_reference_table(a); -NOTICE: executing the command locally: SELECT worker_apply_inter_shard_ddl_command (1509002, 'citus_local_table_queries', 1509000, 'citus_local_table_queries', 'ALTER TABLE citus_local_table_2 ADD CONSTRAINT fkey_to_dummy_2 FOREIGN KEY (a) REFERENCES dummy_reference_table(a);') -CREATE TABLE reference_table(a int, b int); -SELECT create_reference_table('reference_table'); - create_reference_table ---------------------------------------------------------------------- - -(1 row) - -CREATE TABLE distributed_table(a int, b int); -SELECT create_distributed_table('distributed_table', 'a'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -CREATE TABLE postgres_local_table(a int, b int); --- Define a helper function to truncate & insert some data into our test tables --- We should call this function at some places in this test file to prevent --- test to take a long time. --- We shouldn't use LIMIT in INSERT SELECT queries to make the test faster as --- LIMIT would force planner to wrap SELECT query in an intermediate result and --- this might reduce the coverage of the test cases. -CREATE FUNCTION clear_and_init_test_tables() RETURNS void AS $$ - BEGIN - SET client_min_messages to ERROR; - - TRUNCATE postgres_local_table, citus_local_table, reference_table, distributed_table, dummy_reference_table, citus_local_table_2; - - INSERT INTO dummy_reference_table SELECT i, i FROM generate_series(0, 5) i; - INSERT INTO citus_local_table SELECT i, i FROM generate_series(0, 5) i; - INSERT INTO citus_local_table_2 SELECT i, i FROM generate_series(0, 5) i; - INSERT INTO postgres_local_table SELECT i, i FROM generate_series(0, 5) i; - INSERT INTO distributed_table SELECT i, i FROM generate_series(0, 5) i; - INSERT INTO reference_table SELECT i, i FROM generate_series(0, 5) i; - - RESET client_min_messages; - END; -$$ LANGUAGE plpgsql; ---------------------------------------------------------------------- ----- SELECT ---- ---------------------------------------------------------------------- -SELECT clear_and_init_test_tables(); - clear_and_init_test_tables ---------------------------------------------------------------------- - -(1 row) - --- join between citus local tables and reference tables would succeed -SELECT count(*) FROM citus_local_table, reference_table WHERE citus_local_table.a = reference_table.a; -NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table, citus_local_table_queries.reference_table_1509003 reference_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table.a) - count ---------------------------------------------------------------------- - 6 -(1 row) - -SELECT * FROM citus_local_table, reference_table WHERE citus_local_table.a = reference_table.a ORDER BY 1,2,3,4 FOR UPDATE; -NOTICE: executing the command locally: SELECT citus_local_table.a, citus_local_table.b, reference_table.a, reference_table.b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table, citus_local_table_queries.reference_table_1509003 reference_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table.a) ORDER BY citus_local_table.a, citus_local_table.b, reference_table.a, reference_table.b FOR UPDATE OF citus_local_table FOR UPDATE OF reference_table - a | b | a | b ---------------------------------------------------------------------- - 0 | 0 | 0 | 0 - 1 | 1 | 1 | 1 - 2 | 2 | 2 | 2 - 3 | 3 | 3 | 3 - 4 | 4 | 4 | 4 - 5 | 5 | 5 | 5 -(6 rows) - --- should work -WITH cte_1 AS - (SELECT * FROM citus_local_table, reference_table WHERE citus_local_table.a = reference_table.a ORDER BY 1,2,3,4 FOR UPDATE) -SELECT count(*) FROM cte_1; -NOTICE: executing the command locally: WITH cte_1 AS (SELECT citus_local_table.a, citus_local_table.b, reference_table.a, reference_table.b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table, citus_local_table_queries.reference_table_1509003 reference_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table.a) ORDER BY citus_local_table.a, citus_local_table.b, reference_table.a, reference_table.b FOR UPDATE OF citus_local_table FOR UPDATE OF reference_table) SELECT count(*) AS count FROM cte_1 cte_1(a, b, a_1, b_1) - count ---------------------------------------------------------------------- - 6 -(1 row) - --- should work as joins are between ctes -WITH cte_citus_local_table AS - (SELECT * FROM citus_local_table), -cte_postgres_local_table AS - (SELECT * FROM postgres_local_table), -cte_distributed_table AS - (SELECT * FROM distributed_table) -SELECT count(*) FROM cte_distributed_table, cte_citus_local_table, cte_postgres_local_table -WHERE cte_citus_local_table.a = 1 AND cte_distributed_table.a = 1; -NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table - count ---------------------------------------------------------------------- - 6 -(1 row) - --- should fail as we don't support direct joins between distributed/local tables -SELECT count(*) FROM distributed_table d1, distributed_table d2, citus_local_table; -ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns --- local table inside subquery should just work -SELECT count(*) FROM -( - SELECT * FROM (SELECT * FROM citus_local_table) as subquery_inner -) as subquery_top; -NOTICE: executing the command locally: SELECT count(*) AS count FROM (SELECT subquery_inner.a, subquery_inner.b FROM (SELECT citus_local_table.a, citus_local_table.b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table) subquery_inner) subquery_top - count ---------------------------------------------------------------------- - 6 -(1 row) - -SELECT clear_and_init_test_tables(); - clear_and_init_test_tables ---------------------------------------------------------------------- - -(1 row) - --- join between citus/postgres local tables should just work -SELECT count(*) FROM -( - SELECT * FROM (SELECT count(*) FROM citus_local_table, postgres_local_table) as subquery_inner -) as subquery_top; -NOTICE: executing the command locally: SELECT count(*) AS count FROM (SELECT subquery_inner.count FROM (SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table, citus_local_table_queries.postgres_local_table) subquery_inner) subquery_top - count ---------------------------------------------------------------------- - 1 -(1 row) - --- should fail as we don't support direct joins between distributed/local tables -SELECT count(*) FROM -( - SELECT *, random() FROM (SELECT *, random() FROM citus_local_table, distributed_table) as subquery_inner -) as subquery_top; -NOTICE: executing the command locally: SELECT NULL::integer AS "dummy-1" FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE true - count ---------------------------------------------------------------------- - 36 -(1 row) - --- should fail as we don't support direct joins between distributed/local tables -SELECT count(*) FROM -( - SELECT *, random() - FROM ( - WITH cte_1 AS (SELECT *, random() FROM citus_local_table, distributed_table) SELECT * FROM cte_1) as subquery_inner -) as subquery_top; -NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM (SELECT subquery_inner.a, subquery_inner.b, subquery_inner.a_1 AS a, subquery_inner.b_1 AS b, subquery_inner.random, random() AS random FROM (SELECT cte_1.a, cte_1.b, cte_1.a_1 AS a, cte_1.b_1 AS b, cte_1.random FROM (SELECT intermediate_result.a, intermediate_result.b, intermediate_result.a_1 AS a, intermediate_result.b_1 AS b, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer, a_1 integer, b_1 integer, random double precision)) cte_1(a, b, a_1, b_1, random)) subquery_inner(a, b, a_1, b_1, random)) subquery_top(a, b, a_1, b_1, random, random_1) - count ---------------------------------------------------------------------- - 36 -(1 row) - --- should be fine -SELECT count(*) FROM -( - SELECT *, random() - FROM ( - WITH cte_1 AS (SELECT *, random() FROM citus_local_table), cte_2 AS (SELECT * FROM distributed_table) SELECT count(*) FROM cte_1, cte_2 - ) as subquery_inner -) as subquery_top; -NOTICE: executing the command locally: SELECT a, b, random() AS random FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table -NOTICE: executing the command locally: SELECT count(*) AS count FROM (SELECT subquery_inner.count, random() AS random FROM (SELECT intermediate_result.count FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(count bigint)) subquery_inner) subquery_top - count ---------------------------------------------------------------------- - 1 -(1 row) - -SELECT clear_and_init_test_tables(); - clear_and_init_test_tables ---------------------------------------------------------------------- - -(1 row) - --- prepared statement -PREPARE citus_local_only AS SELECT count(*) FROM citus_local_table; --- execute 6 times, local tables without params -EXECUTE citus_local_only; -NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table - count ---------------------------------------------------------------------- - 6 -(1 row) - -EXECUTE citus_local_only; -NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table - count ---------------------------------------------------------------------- - 6 -(1 row) - -EXECUTE citus_local_only; -NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table - count ---------------------------------------------------------------------- - 6 -(1 row) - -EXECUTE citus_local_only; -NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table - count ---------------------------------------------------------------------- - 6 -(1 row) - -EXECUTE citus_local_only; -NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table - count ---------------------------------------------------------------------- - 6 -(1 row) - -EXECUTE citus_local_only; -NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table - count ---------------------------------------------------------------------- - 6 -(1 row) - --- execute 6 times, with param -PREPARE citus_local_only_p(int) AS SELECT count(*) FROM citus_local_table WHERE a = $1; -EXECUTE citus_local_only_p(1); -NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) $1) - count ---------------------------------------------------------------------- - 1 -(1 row) - -EXECUTE citus_local_only_p(1); -NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) $1) - count ---------------------------------------------------------------------- - 1 -(1 row) - -EXECUTE citus_local_only_p(1); -NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) $1) - count ---------------------------------------------------------------------- - 1 -(1 row) - -EXECUTE citus_local_only_p(1); -NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) $1) - count ---------------------------------------------------------------------- - 1 -(1 row) - -EXECUTE citus_local_only_p(1); -NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) $1) - count ---------------------------------------------------------------------- - 1 -(1 row) - -EXECUTE citus_local_only_p(1); -NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) $1) - count ---------------------------------------------------------------------- - 1 -(1 row) - --- do not evalute the function --- show the logs -EXECUTE citus_local_only_p(random()); -NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) $1) - count ---------------------------------------------------------------------- - 1 -(1 row) - -EXECUTE citus_local_only_p(random()); -NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) $1) - count ---------------------------------------------------------------------- - 1 -(1 row) - -PREPARE mixed_query(int, int, int) AS - WITH cte_citus_local_table AS - (SELECT * FROM citus_local_table WHERE a = $1), - cte_postgres_local_table AS - (SELECT * FROM postgres_local_table WHERE a = $2), - cte_distributed_table AS - (SELECT * FROM distributed_table WHERE a = $3), - cte_mixes AS (SELECT * FROM cte_distributed_table, cte_citus_local_table, cte_postgres_local_table) - SELECT count(*) FROM cte_mixes; -EXECUTE mixed_query(1,2,3); -NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - -EXECUTE mixed_query(1,2,3); -NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - -EXECUTE mixed_query(1,2,3); -NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - -EXECUTE mixed_query(1,2,3); -NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - -EXECUTE mixed_query(1,2,3); -NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - -EXECUTE mixed_query(1,2,3); -NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - -EXECUTE mixed_query(1,2,3); -NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - -SELECT clear_and_init_test_tables(); - clear_and_init_test_tables ---------------------------------------------------------------------- - -(1 row) - --- anonymous columns -WITH a AS (SELECT a, '' FROM citus_local_table GROUP BY a) SELECT a.a FROM a ORDER BY 1 LIMIT 5; -NOTICE: executing the command locally: SELECT a FROM (SELECT citus_local_table.a, ''::text FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table GROUP BY citus_local_table.a) a(a, "?column?") ORDER BY a LIMIT 5 - a ---------------------------------------------------------------------- - 0 - 1 - 2 - 3 - 4 -(5 rows) - -WITH a AS (SELECT b, '' FROM citus_local_table WHERE a = 1) SELECT * FROM a, a b ORDER BY 1 LIMIT 5; -NOTICE: executing the command locally: WITH a AS (SELECT citus_local_table.b, ''::text FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) 1)) SELECT a.b, a."?column?", b.b, b."?column?" FROM a a(b, "?column?"), a b(b, "?column?") ORDER BY a.b LIMIT 5 - b | ?column? | b | ?column? ---------------------------------------------------------------------- - 1 | | 1 | -(1 row) - --- weird expression on citus/pg table joins should be fine -SELECT * FROM citus_local_table, postgres_local_table -WHERE citus_local_table.a - postgres_local_table.a = 0 -ORDER BY 1,2,3,4 -LIMIT 10; -NOTICE: executing the command locally: SELECT citus_local_table.a, citus_local_table.b, postgres_local_table.a, postgres_local_table.b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table, citus_local_table_queries.postgres_local_table WHERE ((citus_local_table.a OPERATOR(pg_catalog.-) postgres_local_table.a) OPERATOR(pg_catalog.=) 0) ORDER BY citus_local_table.a, citus_local_table.b, postgres_local_table.a, postgres_local_table.b LIMIT 10 - a | b | a | b ---------------------------------------------------------------------- - 0 | 0 | 0 | 0 - 1 | 1 | 1 | 1 - 2 | 2 | 2 | 2 - 3 | 3 | 3 | 3 - 4 | 4 | 4 | 4 - 5 | 5 | 5 | 5 -(6 rows) - --- set operations should just work -SELECT * FROM citus_local_table UNION SELECT * FROM postgres_local_table UNION SELECT * FROM distributed_table ORDER BY 1,2; -NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table -NOTICE: executing the command locally: SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer) UNION SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer) UNION SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer) ORDER BY 1, 2 - a | b ---------------------------------------------------------------------- - 0 | 0 - 1 | 1 - 2 | 2 - 3 | 3 - 4 | 4 - 5 | 5 -(6 rows) - -(SELECT * FROM citus_local_table ORDER BY 1,2 LIMIT 5) INTERSECT (SELECT i, i FROM generate_series(0, 100) i) ORDER BY 1, 2; -NOTICE: executing the command locally: (SELECT citus_local_table.a, citus_local_table.b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table ORDER BY citus_local_table.a, citus_local_table.b LIMIT 5) INTERSECT SELECT i.i, i.i FROM generate_series(0, 100) i(i) ORDER BY 1, 2 - a | b ---------------------------------------------------------------------- - 0 | 0 - 1 | 1 - 2 | 2 - 3 | 3 - 4 | 4 -(5 rows) - --- should just work as recursive planner kicks in -SELECT count(*) FROM distributed_table WHERE a IN (SELECT a FROM citus_local_table); -NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table - count ---------------------------------------------------------------------- - 6 -(1 row) - -SELECT count(*) FROM citus_local_table WHERE a IN (SELECT a FROM distributed_table); -NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer))) - count ---------------------------------------------------------------------- - 6 -(1 row) - -SELECT count(*) FROM reference_table WHERE a IN (SELECT a FROM citus_local_table); -NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.reference_table_1509003 reference_table WHERE (a OPERATOR(pg_catalog.=) ANY (SELECT citus_local_table.a FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table)) - count ---------------------------------------------------------------------- - 6 -(1 row) - -SELECT count(*) FROM citus_local_table WHERE a IN (SELECT a FROM reference_table); -NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) ANY (SELECT reference_table.a FROM citus_local_table_queries.reference_table_1509003 reference_table)) - count ---------------------------------------------------------------------- - 6 -(1 row) - --- nested recursive queries should just work -SELECT count(*) FROM citus_local_table - WHERE a IN - (SELECT a FROM distributed_table WHERE a IN - (SELECT b FROM citus_local_table WHERE b IN (SELECT b FROM postgres_local_table))); -NOTICE: executing the command locally: SELECT b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (b OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(b integer))) -NOTICE: executing the command locally: SELECT count(*) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.a FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(a integer))) - count ---------------------------------------------------------------------- - 6 -(1 row) - --- local outer joins -SELECT count(*) FROM citus_local_table LEFT JOIN reference_table ON (true); -NOTICE: executing the command locally: SELECT count(*) AS count FROM (citus_local_table_queries.citus_local_table_1509001 citus_local_table LEFT JOIN citus_local_table_queries.reference_table_1509003 reference_table ON (true)) - count ---------------------------------------------------------------------- - 36 -(1 row) - -SELECT count(*) FROM reference_table - LEFT JOIN citus_local_table ON (true) - LEFT JOIN postgres_local_table ON (true) - LEFT JOIN reference_table r2 ON (true); -NOTICE: executing the command locally: SELECT count(*) AS count FROM (((citus_local_table_queries.reference_table_1509003 reference_table LEFT JOIN citus_local_table_queries.citus_local_table_1509001 citus_local_table ON (true)) LEFT JOIN citus_local_table_queries.postgres_local_table ON (true)) LEFT JOIN citus_local_table_queries.reference_table_1509003 r2 ON (true)) - count ---------------------------------------------------------------------- - 1296 -(1 row) - -SELECT count(*) FROM citus_local_table LEFT JOIN distributed_table ON (true); -NOTICE: executing the command locally: SELECT NULL::integer AS "dummy-1" FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM ((SELECT NULL::integer AS a, NULL::integer AS b FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) citus_local_table_1) citus_local_table LEFT JOIN (SELECT NULL::integer AS a, NULL::integer AS b FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) distributed_table_1) distributed_table ON (true)) - count ---------------------------------------------------------------------- - 36 -(1 row) - --- distinct in subquery on CTE -WITH one_row AS ( - SELECT a from citus_local_table WHERE b = 1 -) -SELECT - * -FROM - distributed_table -WHERE - b IN (SELECT DISTINCT a FROM one_row) -ORDER BY - 1, 2 -LIMIT - 1; -NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (b OPERATOR(pg_catalog.=) 1) - a | b ---------------------------------------------------------------------- - 1 | 1 -(1 row) - -WITH one_row_2 AS ( - SELECT a from distributed_table WHERE b = 1 -) -SELECT - * -FROM - citus_local_table -WHERE - b IN (SELECT DISTINCT a FROM one_row_2) -ORDER BY - 1 ,2 -LIMIT - 1; -NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (b OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer))) ORDER BY a, b LIMIT 1 - a | b ---------------------------------------------------------------------- - 1 | 1 -(1 row) - --- join between citus local tables and distributed tables would fail -SELECT count(*) FROM citus_local_table, distributed_table; -NOTICE: executing the command locally: SELECT NULL::integer AS "dummy-1" FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE true - count ---------------------------------------------------------------------- - 36 -(1 row) - -SELECT * FROM citus_local_table, distributed_table ORDER BY 1,2,3,4 FOR UPDATE; -ERROR: could not run distributed query with FOR UPDATE/SHARE commands --- join between citus local tables and postgres local tables are okey -SELECT count(citus_local_table.b), count(postgres_local_table.a) -FROM citus_local_table, postgres_local_table -WHERE citus_local_table.a = postgres_local_table.b; -NOTICE: executing the command locally: SELECT count(citus_local_table.b) AS count, count(postgres_local_table.a) AS count FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table, citus_local_table_queries.postgres_local_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) postgres_local_table.b) - count | count ---------------------------------------------------------------------- - 6 | 6 -(1 row) - --- select for update is just OK -SELECT * FROM citus_local_table ORDER BY 1,2 FOR UPDATE; -NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table ORDER BY a, b FOR UPDATE OF citus_local_table - a | b ---------------------------------------------------------------------- - 0 | 0 - 1 | 1 - 2 | 2 - 3 | 3 - 4 | 4 - 5 | 5 -(6 rows) - ---------------------------------------------------------------------- ------ INSERT SELECT ----- ---------------------------------------------------------------------- --- simple INSERT SELECT is OK -SELECT clear_and_init_test_tables(); - clear_and_init_test_tables ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO citus_local_table -SELECT * from reference_table; -NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 AS citus_table_alias (a, b) SELECT a, b FROM citus_local_table_queries.reference_table_1509003 reference_table -INSERT INTO reference_table -SELECT * from citus_local_table; -NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table -NOTICE: executing the copy locally for shard xxxxx -INSERT INTO citus_local_table -SELECT * from distributed_table; -NOTICE: executing the copy locally for shard xxxxx -INSERT INTO distributed_table -SELECT * from citus_local_table; -NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table -INSERT INTO citus_local_table -SELECT * from citus_local_table_2; -NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 AS citus_table_alias (a, b) SELECT a, b FROM citus_local_table_queries.citus_local_table_2_1509002 citus_local_table_2 -INSERT INTO citus_local_table -SELECT sum(a), b from citus_local_table_2 -GROUP BY b; -NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 AS citus_table_alias (a, b) SELECT sum(a) AS sum, b FROM citus_local_table_queries.citus_local_table_2_1509002 citus_local_table_2 GROUP BY b -INSERT INTO citus_local_table -SELECT * from postgres_local_table; -NOTICE: executing the copy locally for shard xxxxx -INSERT INTO postgres_local_table -SELECT * from citus_local_table; -NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table --- INSERT SELECT with local joins are OK -SELECT clear_and_init_test_tables(); - clear_and_init_test_tables ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO citus_local_table -SELECT reference_table.* FROM reference_table -JOIN citus_local_table ON (true); -NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 AS citus_table_alias (a, b) SELECT reference_table.a, reference_table.b FROM (citus_local_table_queries.reference_table_1509003 reference_table JOIN citus_local_table_queries.citus_local_table_1509001 citus_local_table ON (true)) -INSERT INTO reference_table -SELECT reference_table.* FROM reference_table -JOIN citus_local_table ON (true); -NOTICE: executing the command locally: SELECT reference_table.a, reference_table.b FROM (citus_local_table_queries.reference_table_1509003 reference_table JOIN citus_local_table_queries.citus_local_table_1509001 citus_local_table ON (true)) -NOTICE: executing the copy locally for shard xxxxx -INSERT INTO reference_table -SELECT reference_table.* FROM reference_table, postgres_local_table -JOIN citus_local_table ON (true); -NOTICE: executing the command locally: SELECT reference_table.a, reference_table.b FROM citus_local_table_queries.reference_table_1509003 reference_table, (citus_local_table_queries.postgres_local_table JOIN citus_local_table_queries.citus_local_table_1509001 citus_local_table ON (true)) -NOTICE: executing the copy locally for shard xxxxx -SELECT clear_and_init_test_tables(); - clear_and_init_test_tables ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO distributed_table -SELECT reference_table.* FROM reference_table -JOIN citus_local_table ON (true); -NOTICE: executing the command locally: SELECT reference_table.a, reference_table.b FROM (citus_local_table_queries.reference_table_1509003 reference_table JOIN citus_local_table_queries.citus_local_table_1509001 citus_local_table ON (true)) -INSERT INTO distributed_table -SELECT reference_table.* FROM reference_table, postgres_local_table -JOIN citus_local_table ON (true); -NOTICE: executing the command locally: SELECT reference_table.a, reference_table.b FROM citus_local_table_queries.reference_table_1509003 reference_table, (citus_local_table_queries.postgres_local_table JOIN citus_local_table_queries.citus_local_table_1509001 citus_local_table ON (true)) -INSERT INTO postgres_local_table -SELECT reference_table.* FROM reference_table -JOIN citus_local_table ON (true); -NOTICE: executing the command locally: SELECT reference_table.a, reference_table.b FROM (citus_local_table_queries.reference_table_1509003 reference_table JOIN citus_local_table_queries.citus_local_table_1509001 citus_local_table ON (true)) --- INSERT SELECT that joins reference and distributed tables is also OK -SELECT clear_and_init_test_tables(); - clear_and_init_test_tables ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO citus_local_table -SELECT reference_table.* FROM reference_table -JOIN distributed_table ON (true); -NOTICE: executing the copy locally for shard xxxxx -INSERT INTO citus_local_table -SELECT reference_table.* -FROM reference_table, distributed_table; -NOTICE: executing the copy locally for shard xxxxx --- INSERT SELECT that joins citus local and distributed table directly will fail .. -INSERT INTO citus_local_table -SELECT distributed_table.* FROM distributed_table -JOIN citus_local_table ON (true); -NOTICE: executing the command locally: SELECT NULL::integer AS "dummy-1" FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE true -NOTICE: executing the copy locally for shard xxxxx --- .. but when wrapped into a CTE, join works fine -INSERT INTO citus_local_table -SELECT distributed_table.* FROM distributed_table -JOIN (WITH cte AS (SELECT * FROM citus_local_table) SELECT * FROM cte) as foo ON (true); -NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table -NOTICE: executing the copy locally for shard xxxxx --- multi row insert is OK -INSERT INTO citus_local_table VALUES (1, 2), (3, 4); -NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 AS citus_table_alias (a, b) VALUES (1,2), (3,4) ---------------------------------------------------------------------- ------ DELETE / UPDATE ----- ---------------------------------------------------------------------- --- modifications using citus local tables and postgres local tables --- are not supported, see below four tests -SELECT clear_and_init_test_tables(); - clear_and_init_test_tables ---------------------------------------------------------------------- - -(1 row) - -DELETE FROM citus_local_table -USING postgres_local_table -WHERE citus_local_table.b = postgres_local_table.b; -NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table USING citus_local_table_queries.postgres_local_table WHERE (citus_local_table.b OPERATOR(pg_catalog.=) postgres_local_table.b) -UPDATE citus_local_table -SET b = 5 -FROM postgres_local_table -WHERE citus_local_table.a = 3 AND citus_local_table.b = postgres_local_table.b; -NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509001 citus_local_table SET b = 5 FROM citus_local_table_queries.postgres_local_table WHERE ((citus_local_table.a OPERATOR(pg_catalog.=) 3) AND (citus_local_table.b OPERATOR(pg_catalog.=) postgres_local_table.b)) -DELETE FROM postgres_local_table -USING citus_local_table -WHERE citus_local_table.b = postgres_local_table.b; -NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.postgres_local_table USING citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (citus_local_table.b OPERATOR(pg_catalog.=) postgres_local_table.b) -UPDATE postgres_local_table -SET b = 5 -FROM citus_local_table -WHERE citus_local_table.a = 3 AND citus_local_table.b = postgres_local_table.b; -NOTICE: executing the command locally: UPDATE citus_local_table_queries.postgres_local_table SET b = 5 FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE ((citus_local_table.a OPERATOR(pg_catalog.=) 3) AND (citus_local_table.b OPERATOR(pg_catalog.=) postgres_local_table.b)) --- no direct joins supported -UPDATE distributed_table -SET b = 6 -FROM citus_local_table -WHERE citus_local_table.a = distributed_table.a; -NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE true -UPDATE reference_table -SET b = 6 -FROM citus_local_table -WHERE citus_local_table.a = reference_table.a; -NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE true -NOTICE: executing the command locally: UPDATE citus_local_table_queries.reference_table_1509003 reference_table SET b = 6 FROM (SELECT citus_local_table_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) citus_local_table_1) citus_local_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table.a) --- should not work, add HINT use CTEs -UPDATE citus_local_table -SET b = 6 -FROM distributed_table -WHERE citus_local_table.a = distributed_table.a; -NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509001 citus_local_table SET b = 6 FROM (SELECT distributed_table_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) distributed_table_1) distributed_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) distributed_table.a) --- should work, add HINT use CTEs -UPDATE citus_local_table -SET b = 6 -FROM reference_table -WHERE citus_local_table.a = reference_table.a; -NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.reference_table_1509003 reference_table WHERE true -NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509001 citus_local_table SET b = 6 FROM (SELECT reference_table_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) reference_table_1) reference_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table.a) --- should not work, add HINT use CTEs -DELETE FROM distributed_table -USING citus_local_table -WHERE citus_local_table.a = distributed_table.a; -NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE true --- should not work, add HINT use CTEs -DELETE FROM citus_local_table -USING distributed_table -WHERE citus_local_table.a = distributed_table.a; -NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table USING (SELECT distributed_table_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) distributed_table_1) distributed_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) distributed_table.a) -DELETE FROM reference_table -USING citus_local_table -WHERE citus_local_table.a = reference_table.a; -NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE true -NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.reference_table_1509003 reference_table USING (SELECT citus_local_table_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) citus_local_table_1) citus_local_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table.a) --- should work, add HINT use CTEs -DELETE FROM citus_local_table -USING reference_table -WHERE citus_local_table.a = reference_table.a; -NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.reference_table_1509003 reference_table WHERE true -NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table USING (SELECT reference_table_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) reference_table_1) reference_table WHERE (citus_local_table.a OPERATOR(pg_catalog.=) reference_table.a) --- just works -DELETE FROM citus_local_table -WHERE citus_local_table.a IN (SELECT a FROM distributed_table); -NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer))) --- just works -DELETE FROM citus_local_table -WHERE citus_local_table.a IN (SELECT a FROM reference_table); -NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.reference_table_1509003 reference_table -NOTICE: executing the command locally: DELETE FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE (a OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer))) --- just works -WITH distributed_table_cte AS (SELECT * FROM distributed_table) -UPDATE citus_local_table -SET b = 6 -FROM distributed_table_cte -WHERE citus_local_table.a = distributed_table_cte.a; -NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509001 citus_local_table SET b = 6 FROM (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) distributed_table_cte WHERE (citus_local_table.a OPERATOR(pg_catalog.=) distributed_table_cte.a) -SET citus.log_local_commands to off; --- just works -WITH reference_table_cte AS (SELECT * FROM reference_table) -UPDATE citus_local_table -SET b = 6 -FROM reference_table_cte -WHERE citus_local_table.a = reference_table_cte.a; -set citus.log_local_commands to on; ---------------------------------------------------------------------- ------ VIEW QUERIES ----- ---------------------------------------------------------------------- -CREATE MATERIALIZED VIEW mat_view_4 AS -SELECT count(*) -FROM citus_local_table -JOIN reference_table -USING (a); -NOTICE: executing the command locally: SELECT count(*) AS count FROM (citus_local_table_queries.citus_local_table_1509001 citus_local_table(a, b) JOIN citus_local_table_queries.reference_table_1509003 reference_table(a, b) USING (a)) --- ok -SELECT count(*) FROM mat_view_4; - count ---------------------------------------------------------------------- - 1 -(1 row) - --- should work -SELECT count(*) FROM distributed_table WHERE b in -(SELECT count FROM mat_view_4); - count ---------------------------------------------------------------------- - 1 -(1 row) - -CREATE VIEW view_2 AS -SELECT count(*) -FROM citus_local_table -JOIN citus_local_table_2 USING (a) -JOIN distributed_table USING (a); --- should fail as view contains direct local dist join -SELECT count(*) FROM view_2; -NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table WHERE true -NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.citus_local_table_2_1509002 citus_local_table_2 WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM (SELECT intermediate_result.count FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(count bigint)) view_2 - count ---------------------------------------------------------------------- - 1 -(1 row) - -CREATE VIEW view_3 -AS SELECT count(*) -FROM citus_local_table_2 -JOIN reference_table -USING (a); --- ok -SELECT count(*) FROM view_3; -NOTICE: executing the command locally: SELECT count(*) AS count FROM (SELECT count(*) AS count FROM (citus_local_table_queries.citus_local_table_2_1509002 citus_local_table_2(a, b) JOIN citus_local_table_queries.reference_table_1509003 reference_table(a, b) USING (a))) view_3 - count ---------------------------------------------------------------------- - 1 -(1 row) - --- view treated as subquery, so should work -SELECT count(*) FROM view_3, distributed_table; -NOTICE: executing the command locally: SELECT a FROM citus_local_table_queries.citus_local_table_2_1509002 citus_local_table_2 WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM ((SELECT citus_local_table_2_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) citus_local_table_2_1) citus_local_table_2 JOIN citus_local_table_queries.reference_table_1509003 reference_table(a, b) USING (a)) - count ---------------------------------------------------------------------- - 6 -(1 row) - ---------------------------------------------------------------------- --- Some other tests with subqueries & CTE's -- ---------------------------------------------------------------------- -SELECT clear_and_init_test_tables(); - clear_and_init_test_tables ---------------------------------------------------------------------- - -(1 row) - -SELECT count(*) AS a, count(*) AS b -FROM reference_table -JOIN (SELECT count(*) as a, count(*) as b - FROM citus_local_table_2 - JOIN (SELECT count(*) as a, count(*) as b - FROM postgres_local_table - JOIN (SELECT count(*) as a, count(*) as b - FROM reference_table as table_4677) subquery5108 - USING (a)) subquery7132 - USING (b)) subquery7294 -USING (a); -NOTICE: executing the command locally: SELECT count(*) AS a, count(*) AS b FROM (citus_local_table_queries.reference_table_1509003 reference_table(a, b) JOIN (SELECT count(*) AS a, count(*) AS b FROM (citus_local_table_queries.citus_local_table_2_1509002 citus_local_table_2(a, b) JOIN (SELECT count(*) AS a, count(*) AS b FROM (citus_local_table_queries.postgres_local_table JOIN (SELECT count(*) AS a, count(*) AS b FROM citus_local_table_queries.reference_table_1509003 table_4677) subquery5108 USING (a))) subquery7132 USING (b))) subquery7294 USING (a)) - a | b ---------------------------------------------------------------------- - 1 | 1 -(1 row) - --- direct join inside CTE not supported -WITH cte AS ( -UPDATE citus_local_table lt SET a = mt.a -FROM distributed_table mt WHERE mt.b = lt.b -RETURNING lt.b, lt.a -) SELECT * FROM cte JOIN distributed_table mt ON mt.b = cte.b ORDER BY 1,2,3,4; -NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509001 lt SET a = mt.a FROM (SELECT mt_1.a, mt_1.b FROM (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) mt_1) mt WHERE (mt.b OPERATOR(pg_catalog.=) lt.b) RETURNING lt.b, lt.a - b | a | a | b ---------------------------------------------------------------------- - 0 | 0 | 0 | 0 - 1 | 1 | 1 | 1 - 2 | 2 | 2 | 2 - 3 | 3 | 3 | 3 - 4 | 4 | 4 | 4 - 5 | 5 | 5 | 5 -(6 rows) - --- join with CTE just works -UPDATE citus_local_table -SET a=5 -FROM (SELECT avg(distributed_table.b) as avg_b - FROM distributed_table) as foo -WHERE -foo.avg_b = citus_local_table.b; -NOTICE: executing the command locally: UPDATE citus_local_table_queries.citus_local_table_1509001 citus_local_table SET a = 5 FROM (SELECT intermediate_result.avg_b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(avg_b numeric)) foo WHERE (foo.avg_b OPERATOR(pg_catalog.=) (citus_local_table.b)::numeric) --- should work -UPDATE distributed_table -SET b = avg_a -FROM (SELECT avg(citus_local_table.a) as avg_a FROM citus_local_table) as foo -WHERE foo.avg_a = distributed_table.a -RETURNING distributed_table.*; -NOTICE: executing the command locally: SELECT avg(a) AS avg_a FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table - a | b ---------------------------------------------------------------------- -(0 rows) - --- it is unfortunate that recursive planner cannot detect this --- but expected to not work -UPDATE citus_local_table -SET a=5 -FROM (SELECT b FROM distributed_table) AS foo -WHERE foo.b = citus_local_table.b; -ERROR: local table citus_local_table cannot be joined with these distributed tables ---------------------------------------------------------------------- --- test different execution paths -- ---------------------------------------------------------------------- --- a bit different explain output than for postgres local tables -EXPLAIN (COSTS FALSE) -INSERT INTO citus_local_table -SELECT * FROM distributed_table -ORDER BY distributed_table.* -LIMIT 10; - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> Limit - -> Sort - Sort Key: remote_scan.worker_column_3 - -> Custom Scan (Citus Adaptive) - Task Count: 4 - Tasks Shown: One of 4 - -> Task - Node: host=localhost port=xxxxx dbname=regression - -> Limit - -> Sort - Sort Key: distributed_table.* - -> Seq Scan on distributed_table_1509004 distributed_table -(14 rows) - --- show that we do not pull to coordinator -EXPLAIN (COSTS FALSE) -INSERT INTO citus_local_table -SELECT * FROM citus_local_table; - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus Adaptive) - Task Count: 1 - Tasks Shown: All - -> Task - Node: host=localhost port=xxxxx dbname=regression - -> Insert on citus_local_table_1509001 citus_table_alias - -> Seq Scan on citus_local_table_1509001 citus_local_table -(7 rows) - -EXPLAIN (COSTS FALSE) -INSERT INTO citus_local_table -SELECT reference_table.* FROM reference_table; - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus Adaptive) - Task Count: 1 - Tasks Shown: All - -> Task - Node: host=localhost port=xxxxx dbname=regression - -> Insert on citus_local_table_1509001 citus_table_alias - -> Seq Scan on reference_table_1509003 reference_table -(7 rows) - -EXPLAIN (COSTS FALSE) -INSERT INTO citus_local_table -SELECT reference_table.* FROM reference_table, postgres_local_table; - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> Custom Scan (Citus Adaptive) - Task Count: 1 - Tasks Shown: All - -> Task - Node: host=localhost port=xxxxx dbname=regression - -> Nested Loop - -> Seq Scan on reference_table_1509003 reference_table - -> Materialize - -> Seq Scan on postgres_local_table -(11 rows) - --- show that we pull to coordinator when a distributed table is involved -EXPLAIN (COSTS FALSE) -INSERT INTO citus_local_table -SELECT reference_table.* FROM reference_table, distributed_table; - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> Custom Scan (Citus Adaptive) - Task Count: 4 - Tasks Shown: One of 4 - -> Task - Node: host=localhost port=xxxxx dbname=regression - -> Nested Loop - -> Seq Scan on distributed_table_1509004 distributed_table - -> Materialize - -> Seq Scan on reference_table_1509003 reference_table -(11 rows) - --- truncate tables & add unique constraints to be able to define foreign keys -TRUNCATE reference_table, citus_local_table, distributed_table; -NOTICE: executing the command locally: TRUNCATE TABLE citus_local_table_queries.reference_table_xxxxx CASCADE -NOTICE: executing the command locally: TRUNCATE TABLE citus_local_table_queries.citus_local_table_xxxxx CASCADE -ALTER TABLE reference_table ADD CONSTRAINT pkey_ref PRIMARY KEY (a); -NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1509003, 'citus_local_table_queries', 'ALTER TABLE reference_table ADD CONSTRAINT pkey_ref PRIMARY KEY (a);') -ALTER TABLE citus_local_table ADD CONSTRAINT pkey_c PRIMARY KEY (a); -NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1509001, 'citus_local_table_queries', 'ALTER TABLE citus_local_table ADD CONSTRAINT pkey_c PRIMARY KEY (a);') --- define a foreign key chain distributed table -> reference table -> citus local table --- to test sequential execution -ALTER TABLE distributed_table ADD CONSTRAINT fkey_dist_to_ref FOREIGN KEY(a) REFERENCES reference_table(a) ON DELETE RESTRICT; -ALTER TABLE reference_table ADD CONSTRAINT fkey_ref_to_local FOREIGN KEY(a) REFERENCES citus_local_table(a) ON DELETE RESTRICT; -NOTICE: executing the command locally: SELECT worker_apply_inter_shard_ddl_command (1509003, 'citus_local_table_queries', 1509001, 'citus_local_table_queries', 'ALTER TABLE reference_table ADD CONSTRAINT fkey_ref_to_local FOREIGN KEY(a) REFERENCES citus_local_table(a) ON DELETE RESTRICT;') -INSERT INTO citus_local_table VALUES (1); -NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 (a) VALUES (1) -INSERT INTO reference_table VALUES (1); -NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.reference_table_1509003 (a) VALUES (1) -BEGIN; - INSERT INTO citus_local_table VALUES (1) ON CONFLICT (a) DO NOTHING; -NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 AS citus_table_alias (a) VALUES (1) ON CONFLICT(a) DO NOTHING - INSERT INTO distributed_table VALUES (1); - -- should show sequential as first inserting into citus local table - -- would force the xact block to use sequential execution - show citus.multi_shard_modify_mode; - citus.multi_shard_modify_mode ---------------------------------------------------------------------- - sequential -(1 row) - -ROLLBACK; -BEGIN; - TRUNCATE distributed_table; - -- should error out as we truncated distributed_table via parallel execution - TRUNCATE citus_local_table CASCADE; -NOTICE: truncate cascades to table "reference_table" -NOTICE: truncate cascades to table "distributed_table" -NOTICE: executing the command locally: TRUNCATE TABLE citus_local_table_queries.citus_local_table_xxxxx CASCADE -ERROR: cannot execute DDL on table "citus_local_table" because there was a parallel DDL access to distributed table "distributed_table" in the same transaction -ROLLBACK; -BEGIN; - SET LOCAL citus.multi_shard_modify_mode TO 'sequential'; - TRUNCATE distributed_table; - -- should work fine as we already switched to sequential execution - -- before parallel truncate - TRUNCATE citus_local_table CASCADE; -NOTICE: truncate cascades to table "reference_table" -NOTICE: truncate cascades to table "distributed_table" -NOTICE: executing the command locally: TRUNCATE TABLE citus_local_table_queries.citus_local_table_xxxxx CASCADE -NOTICE: truncate cascades to table "reference_table_xxxxx" -NOTICE: executing the command locally: TRUNCATE TABLE citus_local_table_queries.reference_table_xxxxx CASCADE -ROLLBACK; -ALTER TABLE distributed_table DROP CONSTRAINT fkey_dist_to_ref; -BEGIN; - INSERT INTO citus_local_table VALUES (1) ON CONFLICT (a) DO NOTHING; -NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 AS citus_table_alias (a) VALUES (1) ON CONFLICT(a) DO NOTHING - show citus.multi_shard_modify_mode; - citus.multi_shard_modify_mode ---------------------------------------------------------------------- - sequential -(1 row) - -ROLLBACK; --- remove uniqueness constraint and dependent foreign key constraint for next tests -ALTER TABLE reference_table DROP CONSTRAINT fkey_ref_to_local; -NOTICE: executing the command locally: SELECT worker_apply_inter_shard_ddl_command (1509003, 'citus_local_table_queries', 1509001, 'citus_local_table_queries', 'ALTER TABLE reference_table DROP CONSTRAINT fkey_ref_to_local;') -ALTER TABLE citus_local_table DROP CONSTRAINT pkey_c; -NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1509001, 'citus_local_table_queries', 'ALTER TABLE citus_local_table DROP CONSTRAINT pkey_c;') -COPY citus_local_table(a) FROM PROGRAM 'seq 1'; --- should use local execution -BEGIN; - COPY citus_local_table(a) FROM PROGRAM 'seq 1'; -NOTICE: executing the copy locally for shard xxxxx - COPY citus_local_table(a) FROM PROGRAM 'seq 1'; -NOTICE: executing the copy locally for shard xxxxx -COMMIT; -COPY citus_local_table TO STDOUT; -1 \N -1 \N -1 \N -1 \N -COPY (SELECT * FROM citus_local_table) TO STDOUT; -NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table -1 \N -1 \N -1 \N -1 \N -BEGIN; - COPY citus_local_table TO STDOUT; -1 \N -1 \N -1 \N -1 \N -COMMIT; -BEGIN; - COPY (SELECT * FROM citus_local_table) TO STDOUT; -NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table -1 \N -1 \N -1 \N -1 \N -COMMIT; --- truncate test tables for next test -TRUNCATE citus_local_table, reference_table, distributed_table; -NOTICE: executing the command locally: TRUNCATE TABLE citus_local_table_queries.citus_local_table_xxxxx CASCADE -NOTICE: executing the command locally: TRUNCATE TABLE citus_local_table_queries.reference_table_xxxxx CASCADE -BEGIN; - INSERT INTO citus_local_table VALUES (1), (2); -NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 AS citus_table_alias (a) VALUES (1), (2) - SAVEPOINT sp1; - INSERT INTO citus_local_table VALUES (3), (4); -NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 AS citus_table_alias (a) VALUES (3), (4) - ROLLBACK TO SAVEPOINT sp1; - SELECT * FROM citus_local_table ORDER BY 1,2; -NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table ORDER BY a, b - a | b ---------------------------------------------------------------------- - 1 | - 2 | -(2 rows) - - SAVEPOINT sp2; - INSERT INTO citus_local_table VALUES (3), (4); -NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 AS citus_table_alias (a) VALUES (3), (4) - INSERT INTO distributed_table VALUES (3), (4); - ROLLBACK TO SAVEPOINT sp2; - SELECT * FROM citus_local_table ORDER BY 1,2; -NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table ORDER BY a, b - a | b ---------------------------------------------------------------------- - 1 | - 2 | -(2 rows) - - SELECT * FROM distributed_table ORDER BY 1,2; - a | b ---------------------------------------------------------------------- -(0 rows) - - SAVEPOINT sp3; - INSERT INTO citus_local_table VALUES (3), (2); -NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.citus_local_table_1509001 AS citus_table_alias (a) VALUES (3), (2) - INSERT INTO reference_table VALUES (3), (2); -NOTICE: executing the command locally: INSERT INTO citus_local_table_queries.reference_table_1509003 AS citus_table_alias (a) VALUES (3), (2) - ROLLBACK TO SAVEPOINT sp3; - SELECT * FROM citus_local_table ORDER BY 1,2; -NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.citus_local_table_1509001 citus_local_table ORDER BY a, b - a | b ---------------------------------------------------------------------- - 1 | - 2 | -(2 rows) - - SELECT * FROM reference_table ORDER BY 1,2; -NOTICE: executing the command locally: SELECT a, b FROM citus_local_table_queries.reference_table_1509003 reference_table ORDER BY a, b - a | b ---------------------------------------------------------------------- -(0 rows) - -COMMIT; --- cleanup at exit -DROP SCHEMA citus_local_table_queries CASCADE; -NOTICE: drop cascades to 14 other objects diff --git a/src/test/regress/expected/columnar_pg15.out b/src/test/regress/expected/columnar_pg15.out index 2ad95fcaf..62d2de2dc 100644 --- a/src/test/regress/expected/columnar_pg15.out +++ b/src/test/regress/expected/columnar_pg15.out @@ -1,10 +1,3 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif CREATE TABLE alter_am(i int); INSERT INTO alter_am SELECT generate_series(1,1000000); SELECT * FROM columnar.options WHERE relation = 'alter_am'::regclass; diff --git a/src/test/regress/expected/columnar_pg15_0.out b/src/test/regress/expected/columnar_pg15_0.out deleted file mode 100644 index a7e3fbf20..000000000 --- a/src/test/regress/expected/columnar_pg15_0.out +++ /dev/null @@ -1,6 +0,0 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q diff --git a/src/test/regress/expected/columnar_vacuum_vs_insert.out b/src/test/regress/expected/columnar_vacuum_vs_insert.out index f229c4c71..0d88e8a04 100644 --- a/src/test/regress/expected/columnar_vacuum_vs_insert.out +++ b/src/test/regress/expected/columnar_vacuum_vs_insert.out @@ -55,7 +55,7 @@ step s1-commit: COMMIT; s2: INFO: vacuuming "public.test_vacuum_vs_insert" -s2: INFO: "test_vacuum_vs_insert": found 0 removable, 6 nonremovable row versions in 4 pages +s2: INFO: "public.test_vacuum_vs_insert": found 0 removable, 6 nonremovable row versions in 4 pages DETAIL: 0 dead row versions cannot be removed yet. step s2-vacuum-full: <... completed> step s2-select: diff --git a/src/test/regress/expected/coordinator_shouldhaveshards.out b/src/test/regress/expected/coordinator_shouldhaveshards.out index 047827dd8..6f24614ba 100644 --- a/src/test/regress/expected/coordinator_shouldhaveshards.out +++ b/src/test/regress/expected/coordinator_shouldhaveshards.out @@ -3,17 +3,6 @@ -- -- Test queries on a distributed table with shards on the coordinator -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - t -(1 row) - CREATE SCHEMA coordinator_shouldhaveshards; SET search_path TO coordinator_shouldhaveshards; SET citus.next_shard_id TO 1503000; diff --git a/src/test/regress/expected/coordinator_shouldhaveshards_0.out b/src/test/regress/expected/coordinator_shouldhaveshards_0.out deleted file mode 100644 index 00ccedb15..000000000 --- a/src/test/regress/expected/coordinator_shouldhaveshards_0.out +++ /dev/null @@ -1,1190 +0,0 @@ --- --- COORDINATOR_SHOULDHAVESHARDS --- --- Test queries on a distributed table with shards on the coordinator --- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - f -(1 row) - -CREATE SCHEMA coordinator_shouldhaveshards; -SET search_path TO coordinator_shouldhaveshards; -SET citus.next_shard_id TO 1503000; -SET citus.next_placement_id TO 1503000; --- idempotently add node to allow this test to run without add_coordinator -SET client_min_messages TO WARNING; -SELECT 1 FROM master_add_node('localhost', :master_port, groupid => 0); - ?column? ---------------------------------------------------------------------- - 1 -(1 row) - -RESET client_min_messages; -SELECT 1 FROM master_set_node_property('localhost', :master_port, 'shouldhaveshards', true); - ?column? ---------------------------------------------------------------------- - 1 -(1 row) - -SET citus.shard_replication_factor TO 1; -CREATE TABLE test (x int, y int); -SELECT create_distributed_table('test','x', colocate_with := 'none'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -SELECT count(*) FROM pg_dist_shard JOIN pg_dist_placement USING (shardid) -WHERE logicalrelid = 'test'::regclass AND groupid = 0; - count ---------------------------------------------------------------------- - 2 -(1 row) - ---- enable logging to see which tasks are executed locally -SET client_min_messages TO LOG; -SET citus.log_local_commands TO ON; --- INSERT..SELECT with COPY under the covers -INSERT INTO test SELECT s,s FROM generate_series(2,100) s; -NOTICE: executing the copy locally for shard xxxxx -NOTICE: executing the copy locally for shard xxxxx --- router queries execute locally -INSERT INTO test VALUES (1, 1); -NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.test_1503000 (x, y) VALUES (1, 1) -SELECT y FROM test WHERE x = 1; -NOTICE: executing the command locally: SELECT y FROM coordinator_shouldhaveshards.test_1503000 test WHERE (x OPERATOR(pg_catalog.=) 1) - y ---------------------------------------------------------------------- - 1 -(1 row) - --- multi-shard queries connect to localhost -SELECT count(*) FROM test; - count ---------------------------------------------------------------------- - 100 -(1 row) - -WITH a AS (SELECT * FROM test) SELECT count(*) FROM test; - count ---------------------------------------------------------------------- - 100 -(1 row) - --- multi-shard queries in transaction blocks execute locally -BEGIN; -SELECT y FROM test WHERE x = 1; -NOTICE: executing the command locally: SELECT y FROM coordinator_shouldhaveshards.test_1503000 test WHERE (x OPERATOR(pg_catalog.=) 1) - y ---------------------------------------------------------------------- - 1 -(1 row) - -SELECT count(*) FROM test; -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503000 test WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503003 test WHERE true - count ---------------------------------------------------------------------- - 100 -(1 row) - -END; -BEGIN; -SELECT y FROM test WHERE x = 1; -NOTICE: executing the command locally: SELECT y FROM coordinator_shouldhaveshards.test_1503000 test WHERE (x OPERATOR(pg_catalog.=) 1) - y ---------------------------------------------------------------------- - 1 -(1 row) - -SELECT count(*) FROM test; -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503000 test WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503003 test WHERE true - count ---------------------------------------------------------------------- - 100 -(1 row) - -END; --- INSERT..SELECT with re-partitioning after local execution -BEGIN; -INSERT INTO test VALUES (0,1000); -CREATE TABLE repart_test (x int primary key, y int); -SELECT create_distributed_table('repart_test','x', colocate_with := 'none'); -NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503004, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.repart_test (x integer NOT NULL, y integer) USING heap');SELECT worker_apply_shard_ddl_command (1503004, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.repart_test OWNER TO postgres');SELECT worker_apply_shard_ddl_command (1503004, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.repart_test ADD CONSTRAINT repart_test_pkey PRIMARY KEY (x)') -NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503007, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.repart_test (x integer NOT NULL, y integer) USING heap');SELECT worker_apply_shard_ddl_command (1503007, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.repart_test OWNER TO postgres');SELECT worker_apply_shard_ddl_command (1503007, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.repart_test ADD CONSTRAINT repart_test_pkey PRIMARY KEY (x)') - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO repart_test (x, y) SELECT y, x FROM test; -NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_1503000_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_1503000_to','SELECT y AS x, x AS y FROM coordinator_shouldhaveshards.test_1503000 test WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true) WHERE rows_written > 0 -NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_1503003_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_1503003_to','SELECT y AS x, x AS y FROM coordinator_shouldhaveshards.test_1503003 test WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true) WHERE rows_written > 0 -NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.repart_test_1503004 AS citus_table_alias (x, y) SELECT x, y FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1503000_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(x integer, y integer) -NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.repart_test_1503007 AS citus_table_alias (x, y) SELECT x, y FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1503003_to_3}'::text[], 'binary'::citus_copy_format) intermediate_result(x integer, y integer) -SELECT y FROM repart_test WHERE x = 1000; - y ---------------------------------------------------------------------- - 0 -(1 row) - -INSERT INTO repart_test (x, y) SELECT y, x FROM test ON CONFLICT (x) DO UPDATE SET y = -1; -NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_1503000_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_1503000_to','SELECT y AS x, x AS y FROM coordinator_shouldhaveshards.test_1503000 test WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true) WHERE rows_written > 0 -NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_1503003_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_1503003_to','SELECT y AS x, x AS y FROM coordinator_shouldhaveshards.test_1503003 test WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true) WHERE rows_written > 0 -NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.repart_test_1503004 AS citus_table_alias (x, y) SELECT x, y FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1503000_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(x integer, y integer) ON CONFLICT(x) DO UPDATE SET y = '-1'::integer -NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.repart_test_1503007 AS citus_table_alias (x, y) SELECT x, y FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1503003_to_3}'::text[], 'binary'::citus_copy_format) intermediate_result(x integer, y integer) ON CONFLICT(x) DO UPDATE SET y = '-1'::integer -SELECT y FROM repart_test WHERE x = 1000; - y ---------------------------------------------------------------------- - -1 -(1 row) - -ROLLBACK; --- INSERT..SELECT with re-partitioning in EXPLAIN ANALYZE after local execution -BEGIN; -INSERT INTO test VALUES (0,1000); -EXPLAIN (COSTS FALSE, ANALYZE TRUE, TIMING FALSE, SUMMARY FALSE) INSERT INTO test (x, y) SELECT y, x FROM test; -ERROR: EXPLAIN ANALYZE is currently not supported for INSERT ... SELECT commands with repartitioning -ROLLBACK; --- DDL connects to locahost -ALTER TABLE test ADD COLUMN z int; --- DDL after local execution -BEGIN; -SELECT y FROM test WHERE x = 1; -NOTICE: executing the command locally: SELECT y FROM coordinator_shouldhaveshards.test_1503000 test WHERE (x OPERATOR(pg_catalog.=) 1) - y ---------------------------------------------------------------------- - 1 -(1 row) - -ALTER TABLE test DROP COLUMN z; -NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503000, 'coordinator_shouldhaveshards', 'ALTER TABLE test DROP COLUMN z;') -NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503003, 'coordinator_shouldhaveshards', 'ALTER TABLE test DROP COLUMN z;') -ROLLBACK; -BEGIN; -ALTER TABLE test DROP COLUMN z; -NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503000, 'coordinator_shouldhaveshards', 'ALTER TABLE test DROP COLUMN z;') -NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503003, 'coordinator_shouldhaveshards', 'ALTER TABLE test DROP COLUMN z;') -SELECT y FROM test WHERE x = 1; -NOTICE: executing the command locally: SELECT y FROM coordinator_shouldhaveshards.test_1503000 test WHERE (x OPERATOR(pg_catalog.=) 1) - y ---------------------------------------------------------------------- - 1 -(1 row) - -END; -SET citus.shard_count TO 6; -SET citus.log_remote_commands TO OFF; -BEGIN; -SET citus.log_local_commands TO ON; -CREATE TABLE dist_table (a int); -INSERT INTO dist_table SELECT * FROM generate_series(1, 100); --- trigger local execution -SELECT y FROM test WHERE x = 1; -NOTICE: executing the command locally: SELECT y FROM coordinator_shouldhaveshards.test_1503000 test WHERE (x OPERATOR(pg_catalog.=) 1) - y ---------------------------------------------------------------------- - 1 -(1 row) - --- this should be run locally -SELECT create_distributed_table('dist_table', 'a', colocate_with := 'none'); -NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503008, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table (a integer) USING heap');SELECT worker_apply_shard_ddl_command (1503008, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table OWNER TO postgres') -NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503011, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table (a integer) USING heap');SELECT worker_apply_shard_ddl_command (1503011, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table OWNER TO postgres') -NOTICE: executing the copy locally for shard xxxxx -NOTICE: Copying data from local table... -NOTICE: executing the copy locally for shard xxxxx -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($$coordinator_shouldhaveshards.dist_table$$) - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -SELECT count(*) FROM dist_table; -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.dist_table_1503008 dist_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.dist_table_1503011 dist_table WHERE true - count ---------------------------------------------------------------------- - 100 -(1 row) - -ROLLBACK; -CREATE TABLE dist_table (a int); -INSERT INTO dist_table SELECT * FROM generate_series(1, 100); -BEGIN; -SET citus.log_local_commands TO ON; --- trigger local execution -SELECT y FROM test WHERE x = 1; -NOTICE: executing the command locally: SELECT y FROM coordinator_shouldhaveshards.test_1503000 test WHERE (x OPERATOR(pg_catalog.=) 1) - y ---------------------------------------------------------------------- - 1 -(1 row) - --- this should be run locally -SELECT create_distributed_table('dist_table', 'a', colocate_with := 'none'); -NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503014, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table (a integer) USING heap');SELECT worker_apply_shard_ddl_command (1503014, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table OWNER TO postgres') -NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503017, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table (a integer) USING heap');SELECT worker_apply_shard_ddl_command (1503017, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table OWNER TO postgres') -NOTICE: executing the copy locally for shard xxxxx -NOTICE: Copying data from local table... -NOTICE: executing the copy locally for shard xxxxx -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($$coordinator_shouldhaveshards.dist_table$$) - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -SELECT count(*) FROM dist_table; -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.dist_table_1503014 dist_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.dist_table_1503017 dist_table WHERE true - count ---------------------------------------------------------------------- - 100 -(1 row) - -ROLLBACK; --- repartition queries should work fine -SET citus.enable_repartition_joins TO ON; -SELECT count(*) FROM test t1, test t2 WHERE t1.x = t2.y; - count ---------------------------------------------------------------------- - 100 -(1 row) - -BEGIN; -SET citus.enable_unique_job_ids TO off; -SELECT count(*) FROM test t1, test t2 WHERE t1.x = t2.y; -NOTICE: executing the command locally: SELECT partition_index, 'repartition_26_1' || '_' || partition_index::text , rows_written FROM pg_catalog.worker_partition_query_result('repartition_26_1','SELECT x AS column1 FROM coordinator_shouldhaveshards.test_1503000 t1 WHERE true',0,'hash','{-2147483648,-1431655766,-715827884,-2,715827880,1431655762}'::text[],'{-1431655767,-715827885,-3,715827879,1431655761,2147483647}'::text[],true,true,true) WHERE rows_written > 0 -NOTICE: executing the command locally: SELECT partition_index, 'repartition_26_4' || '_' || partition_index::text , rows_written FROM pg_catalog.worker_partition_query_result('repartition_26_4','SELECT x AS column1 FROM coordinator_shouldhaveshards.test_1503003 t1 WHERE true',0,'hash','{-2147483648,-1431655766,-715827884,-2,715827880,1431655762}'::text[],'{-1431655767,-715827885,-3,715827879,1431655761,2147483647}'::text[],true,true,true) WHERE rows_written > 0 -NOTICE: executing the command locally: SELECT partition_index, 'repartition_27_1' || '_' || partition_index::text , rows_written FROM pg_catalog.worker_partition_query_result('repartition_27_1','SELECT y AS column1 FROM coordinator_shouldhaveshards.test_1503000 t2 WHERE true',0,'hash','{-2147483648,-1431655766,-715827884,-2,715827880,1431655762}'::text[],'{-1431655767,-715827885,-3,715827879,1431655761,2147483647}'::text[],true,true,true) WHERE rows_written > 0 -NOTICE: executing the command locally: SELECT partition_index, 'repartition_27_4' || '_' || partition_index::text , rows_written FROM pg_catalog.worker_partition_query_result('repartition_27_4','SELECT y AS column1 FROM coordinator_shouldhaveshards.test_1503003 t2 WHERE true',0,'hash','{-2147483648,-1431655766,-715827884,-2,715827880,1431655762}'::text[],'{-1431655767,-715827885,-3,715827879,1431655761,2147483647}'::text[],true,true,true) WHERE rows_written > 0 -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_26_1_2']::text[],'localhost',57636) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_26_2_2']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_26_3_2']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_26_4_2']::text[],'localhost',57636) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_27_1_2']::text[],'localhost',57636) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_27_2_2']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_27_3_2']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_27_4_2']::text[],'localhost',57636) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_26_1_5']::text[],'localhost',57636) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_26_2_5']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_26_3_5']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_26_4_5']::text[],'localhost',57636) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_27_1_5']::text[],'localhost',57636) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_27_2_5']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_27_3_5']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_27_4_5']::text[],'localhost',57636) bytes -NOTICE: executing the command locally: SELECT count(*) AS count FROM (read_intermediate_results('{repartition_26_1_2,repartition_26_2_2,repartition_26_3_2,repartition_26_4_2}'::text[], 'binary'::citus_copy_format) intermediate_result(column1 integer) JOIN read_intermediate_results('{repartition_27_1_2,repartition_27_2_2,repartition_27_3_2,repartition_27_4_2}'::text[], 'binary'::citus_copy_format) intermediate_result_1(column1 integer) ON ((intermediate_result.column1 OPERATOR(pg_catalog.=) intermediate_result_1.column1))) WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM (read_intermediate_results('{repartition_26_1_5,repartition_26_2_5,repartition_26_3_5,repartition_26_4_5}'::text[], 'binary'::citus_copy_format) intermediate_result(column1 integer) JOIN read_intermediate_results('{repartition_27_1_5,repartition_27_2_5,repartition_27_3_5,repartition_27_4_5}'::text[], 'binary'::citus_copy_format) intermediate_result_1(column1 integer) ON ((intermediate_result.column1 OPERATOR(pg_catalog.=) intermediate_result_1.column1))) WHERE true - count ---------------------------------------------------------------------- - 100 -(1 row) - -END; -BEGIN; -SET citus.enable_repartition_joins TO ON; --- trigger local execution -SELECT y FROM test WHERE x = 1; -NOTICE: executing the command locally: SELECT y FROM coordinator_shouldhaveshards.test_1503000 test WHERE (x OPERATOR(pg_catalog.=) 1) - y ---------------------------------------------------------------------- - 1 -(1 row) - -SELECT count(*) FROM test t1, test t2 WHERE t1.x = t2.y; -NOTICE: executing the command locally: SELECT partition_index, 'repartition_30_1' || '_' || partition_index::text , rows_written FROM pg_catalog.worker_partition_query_result('repartition_30_1','SELECT x AS column1 FROM coordinator_shouldhaveshards.test_1503000 t1 WHERE true',0,'hash','{-2147483648,-1431655766,-715827884,-2,715827880,1431655762}'::text[],'{-1431655767,-715827885,-3,715827879,1431655761,2147483647}'::text[],true,true,true) WHERE rows_written > 0 -NOTICE: executing the command locally: SELECT partition_index, 'repartition_30_4' || '_' || partition_index::text , rows_written FROM pg_catalog.worker_partition_query_result('repartition_30_4','SELECT x AS column1 FROM coordinator_shouldhaveshards.test_1503003 t1 WHERE true',0,'hash','{-2147483648,-1431655766,-715827884,-2,715827880,1431655762}'::text[],'{-1431655767,-715827885,-3,715827879,1431655761,2147483647}'::text[],true,true,true) WHERE rows_written > 0 -NOTICE: executing the command locally: SELECT partition_index, 'repartition_31_1' || '_' || partition_index::text , rows_written FROM pg_catalog.worker_partition_query_result('repartition_31_1','SELECT y AS column1 FROM coordinator_shouldhaveshards.test_1503000 t2 WHERE true',0,'hash','{-2147483648,-1431655766,-715827884,-2,715827880,1431655762}'::text[],'{-1431655767,-715827885,-3,715827879,1431655761,2147483647}'::text[],true,true,true) WHERE rows_written > 0 -NOTICE: executing the command locally: SELECT partition_index, 'repartition_31_4' || '_' || partition_index::text , rows_written FROM pg_catalog.worker_partition_query_result('repartition_31_4','SELECT y AS column1 FROM coordinator_shouldhaveshards.test_1503003 t2 WHERE true',0,'hash','{-2147483648,-1431655766,-715827884,-2,715827880,1431655762}'::text[],'{-1431655767,-715827885,-3,715827879,1431655761,2147483647}'::text[],true,true,true) WHERE rows_written > 0 -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_30_1_1']::text[],'localhost',57636) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_30_2_1']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_30_3_1']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_30_4_1']::text[],'localhost',57636) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_31_1_1']::text[],'localhost',57636) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_31_2_1']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_31_3_1']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_31_4_1']::text[],'localhost',57636) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_30_1_4']::text[],'localhost',57636) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_30_2_4']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_30_3_4']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_30_4_4']::text[],'localhost',57636) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_31_1_4']::text[],'localhost',57636) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_31_2_4']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_31_3_4']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_31_4_4']::text[],'localhost',57636) bytes -NOTICE: executing the command locally: SELECT count(*) AS count FROM (read_intermediate_results('{repartition_30_1_1,repartition_30_2_1,repartition_30_3_1,repartition_30_4_1}'::text[], 'binary'::citus_copy_format) intermediate_result(column1 integer) JOIN read_intermediate_results('{repartition_31_1_1,repartition_31_2_1,repartition_31_3_1,repartition_31_4_1}'::text[], 'binary'::citus_copy_format) intermediate_result_1(column1 integer) ON ((intermediate_result.column1 OPERATOR(pg_catalog.=) intermediate_result_1.column1))) WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM (read_intermediate_results('{repartition_30_1_4,repartition_30_2_4,repartition_30_3_4,repartition_30_4_4}'::text[], 'binary'::citus_copy_format) intermediate_result(column1 integer) JOIN read_intermediate_results('{repartition_31_1_4,repartition_31_2_4,repartition_31_3_4,repartition_31_4_4}'::text[], 'binary'::citus_copy_format) intermediate_result_1(column1 integer) ON ((intermediate_result.column1 OPERATOR(pg_catalog.=) intermediate_result_1.column1))) WHERE true - count ---------------------------------------------------------------------- - 100 -(1 row) - -ROLLBACK; -CREATE TABLE ref (a int, b int); -SELECT create_reference_table('ref'); - create_reference_table ---------------------------------------------------------------------- - -(1 row) - -CREATE TABLE local (x int, y int); -BEGIN; -SELECT count(*) FROM test; -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503000 test WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503003 test WHERE true - count ---------------------------------------------------------------------- - 100 -(1 row) - -SELECT * FROM ref JOIN local ON (a = x); -NOTICE: executing the command locally: SELECT ref.a, ref.b, local.x, local.y FROM (coordinator_shouldhaveshards.ref_1503020 ref JOIN coordinator_shouldhaveshards.local ON ((ref.a OPERATOR(pg_catalog.=) local.x))) - a | b | x | y ---------------------------------------------------------------------- -(0 rows) - -TRUNCATE ref; -NOTICE: executing the command locally: TRUNCATE TABLE coordinator_shouldhaveshards.ref_xxxxx CASCADE -ROLLBACK; -BEGIN; -SELECT count(*) FROM test; -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503000 test WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503003 test WHERE true - count ---------------------------------------------------------------------- - 100 -(1 row) - -TRUNCATE ref; -NOTICE: executing the command locally: TRUNCATE TABLE coordinator_shouldhaveshards.ref_xxxxx CASCADE -SELECT * FROM ref JOIN local ON (a = x); -NOTICE: executing the command locally: SELECT ref.a, ref.b, local.x, local.y FROM (coordinator_shouldhaveshards.ref_1503020 ref JOIN coordinator_shouldhaveshards.local ON ((ref.a OPERATOR(pg_catalog.=) local.x))) - a | b | x | y ---------------------------------------------------------------------- -(0 rows) - -ROLLBACK; -BEGIN; -SELECT count(*) FROM test; -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503000 test WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503003 test WHERE true - count ---------------------------------------------------------------------- - 100 -(1 row) - -INSERT INTO ref VALUES (1,2); -NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.ref_1503020 (a, b) VALUES (1, 2) -INSERT INTO local VALUES (1,2); -SELECT * FROM ref JOIN local ON (a = x); -NOTICE: executing the command locally: SELECT ref.a, ref.b, local.x, local.y FROM (coordinator_shouldhaveshards.ref_1503020 ref JOIN coordinator_shouldhaveshards.local ON ((ref.a OPERATOR(pg_catalog.=) local.x))) - a | b | x | y ---------------------------------------------------------------------- - 1 | 2 | 1 | 2 -(1 row) - -ROLLBACK; -BEGIN; -SELECT count(*) FROM test; -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503000 test WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503003 test WHERE true - count ---------------------------------------------------------------------- - 100 -(1 row) - --- we wont see the modifying cte in this query because we will use local execution and --- in postgres we wouldn't see this modifying cte, so it is consistent with postgres. -WITH a AS (SELECT count(*) FROM test), b AS (INSERT INTO local VALUES (3,2) RETURNING *), c AS (INSERT INTO ref VALUES (3,2) RETURNING *), d AS (SELECT count(*) FROM ref JOIN local ON (a = x)) SELECT * FROM a, b, c, d ORDER BY x,y,a,b; -NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.ref_1503020 (a, b) VALUES (3, 2) RETURNING a, b -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503000 test WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503003 test WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM (coordinator_shouldhaveshards.ref_1503020 ref JOIN (SELECT local_1.x, NULL::integer AS y FROM (SELECT intermediate_result.x FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(x integer)) local_1) local ON ((ref.a OPERATOR(pg_catalog.=) local.x))) -NOTICE: executing the command locally: SELECT a.count, b.x, b.y, c.a, c.b, d.count FROM (SELECT intermediate_result.count FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(count bigint)) a, (SELECT intermediate_result.x, intermediate_result.y FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(x integer, y integer)) b, (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) c, (SELECT intermediate_result.count FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(count bigint)) d ORDER BY b.x, b.y, c.a, c.b - count | x | y | a | b | count ---------------------------------------------------------------------- - 100 | 3 | 2 | 3 | 2 | 0 -(1 row) - -TRUNCATE ref; -NOTICE: executing the command locally: TRUNCATE TABLE coordinator_shouldhaveshards.ref_xxxxx CASCADE -SELECT * FROM ref JOIN local ON (a = x); -NOTICE: executing the command locally: SELECT ref.a, ref.b, local.x, local.y FROM (coordinator_shouldhaveshards.ref_1503020 ref JOIN coordinator_shouldhaveshards.local ON ((ref.a OPERATOR(pg_catalog.=) local.x))) - a | b | x | y ---------------------------------------------------------------------- -(0 rows) - --- we wont see the modifying cte in this query because we will use local execution and --- in postgres we wouldn't see this modifying cte, so it is consistent with postgres. -WITH a AS (SELECT count(*) FROM test), b AS (INSERT INTO local VALUES (3,2) RETURNING *), c AS (INSERT INTO ref VALUES (3,2) RETURNING *), d AS (SELECT count(*) FROM ref JOIN local ON (a = x)) SELECT * FROM a, b, c, d ORDER BY x,y,a,b; -NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.ref_1503020 (a, b) VALUES (3, 2) RETURNING a, b -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503000 test WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503003 test WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM (coordinator_shouldhaveshards.ref_1503020 ref JOIN (SELECT local_1.x, NULL::integer AS y FROM (SELECT intermediate_result.x FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(x integer)) local_1) local ON ((ref.a OPERATOR(pg_catalog.=) local.x))) -NOTICE: executing the command locally: SELECT a.count, b.x, b.y, c.a, c.b, d.count FROM (SELECT intermediate_result.count FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(count bigint)) a, (SELECT intermediate_result.x, intermediate_result.y FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(x integer, y integer)) b, (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) c, (SELECT intermediate_result.count FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(count bigint)) d ORDER BY b.x, b.y, c.a, c.b - count | x | y | a | b | count ---------------------------------------------------------------------- - 100 | 3 | 2 | 3 | 2 | 0 -(1 row) - -ROLLBACK; -BEGIN; --- we wont see the modifying cte in this query because we will use local execution and --- in postgres we wouldn't see this modifying cte, so it is consistent with postgres. -WITH a AS (SELECT count(*) FROM test), b AS (INSERT INTO local VALUES (3,2) RETURNING *), c AS (INSERT INTO ref VALUES (3,2) RETURNING *), d AS (SELECT count(*) FROM ref JOIN local ON (a = x)) SELECT * FROM a, b, c, d ORDER BY x,y,a,b; -NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.ref_1503020 (a, b) VALUES (3, 2) RETURNING a, b -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503000 test WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503003 test WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM (coordinator_shouldhaveshards.ref_1503020 ref JOIN (SELECT local_1.x, NULL::integer AS y FROM (SELECT intermediate_result.x FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(x integer)) local_1) local ON ((ref.a OPERATOR(pg_catalog.=) local.x))) -NOTICE: executing the command locally: SELECT a.count, b.x, b.y, c.a, c.b, d.count FROM (SELECT intermediate_result.count FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(count bigint)) a, (SELECT intermediate_result.x, intermediate_result.y FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(x integer, y integer)) b, (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) c, (SELECT intermediate_result.count FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(count bigint)) d ORDER BY b.x, b.y, c.a, c.b - count | x | y | a | b | count ---------------------------------------------------------------------- - 100 | 3 | 2 | 3 | 2 | 0 -(1 row) - -ROLLBACK; -BEGIN; --- we wont see the modifying cte in this query because we will use local execution and --- in postgres we wouldn't see this modifying cte, so it is consistent with postgres. -WITH a AS (SELECT count(*) FROM test), b AS (INSERT INTO local VALUES (3,2) RETURNING *), c AS (INSERT INTO ref SELECT *,* FROM generate_series(1,10) RETURNING *), d AS (SELECT count(*) FROM ref JOIN local ON (a = x)) SELECT * FROM a, b, c, d ORDER BY x,y,a,b; -NOTICE: executing the copy locally for colocated file with shard xxxxx -NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.ref_1503020 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_result('insert_select_XXX_1503020'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer) RETURNING citus_table_alias.a, citus_table_alias.b -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503000 test WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503003 test WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM (coordinator_shouldhaveshards.ref_1503020 ref JOIN (SELECT local_1.x, NULL::integer AS y FROM (SELECT intermediate_result.x FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(x integer)) local_1) local ON ((ref.a OPERATOR(pg_catalog.=) local.x))) -NOTICE: executing the command locally: SELECT a.count, b.x, b.y, c.a, c.b, d.count FROM (SELECT intermediate_result.count FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(count bigint)) a, (SELECT intermediate_result.x, intermediate_result.y FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(x integer, y integer)) b, (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) c, (SELECT intermediate_result.count FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(count bigint)) d ORDER BY b.x, b.y, c.a, c.b - count | x | y | a | b | count ---------------------------------------------------------------------- - 100 | 3 | 2 | 1 | 1 | 0 - 100 | 3 | 2 | 2 | 2 | 0 - 100 | 3 | 2 | 3 | 3 | 0 - 100 | 3 | 2 | 4 | 4 | 0 - 100 | 3 | 2 | 5 | 5 | 0 - 100 | 3 | 2 | 6 | 6 | 0 - 100 | 3 | 2 | 7 | 7 | 0 - 100 | 3 | 2 | 8 | 8 | 0 - 100 | 3 | 2 | 9 | 9 | 0 - 100 | 3 | 2 | 10 | 10 | 0 -(10 rows) - -ROLLBACK; --- same local table reference table tests, but outside a transaction block -INSERT INTO ref VALUES (1,2); -NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.ref_1503020 (a, b) VALUES (1, 2) -INSERT INTO local VALUES (1,2); -SELECT * FROM ref JOIN local ON (a = x); -NOTICE: executing the command locally: SELECT ref.a, ref.b, local.x, local.y FROM (coordinator_shouldhaveshards.ref_1503020 ref JOIN coordinator_shouldhaveshards.local ON ((ref.a OPERATOR(pg_catalog.=) local.x))) - a | b | x | y ---------------------------------------------------------------------- - 1 | 2 | 1 | 2 -(1 row) - --- we wont see the modifying cte in this query because we will use local execution and --- in postgres we wouldn't see this modifying cte, so it is consistent with postgres. -WITH a AS (SELECT count(*) FROM test), b AS (INSERT INTO local VALUES (3,2) RETURNING *), c AS (INSERT INTO ref VALUES (3,2) RETURNING *), d AS (SELECT count(*) FROM ref JOIN local ON (a = x)) SELECT * FROM a, b, c, d ORDER BY x,y,a,b; -NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.ref_1503020 (a, b) VALUES (3, 2) RETURNING a, b -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503000 test WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503003 test WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM (coordinator_shouldhaveshards.ref_1503020 ref JOIN (SELECT local_1.x, NULL::integer AS y FROM (SELECT intermediate_result.x FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(x integer)) local_1) local ON ((ref.a OPERATOR(pg_catalog.=) local.x))) -NOTICE: executing the command locally: SELECT a.count, b.x, b.y, c.a, c.b, d.count FROM (SELECT intermediate_result.count FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(count bigint)) a, (SELECT intermediate_result.x, intermediate_result.y FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(x integer, y integer)) b, (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) c, (SELECT intermediate_result.count FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(count bigint)) d ORDER BY b.x, b.y, c.a, c.b - count | x | y | a | b | count ---------------------------------------------------------------------- - 100 | 3 | 2 | 3 | 2 | 1 -(1 row) - --- joins between local tables and distributed tables are disallowed -CREATE TABLE dist_table(a int); -ERROR: relation "dist_table" already exists -SELECT create_distributed_table('dist_table', 'a'); -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($$coordinator_shouldhaveshards.dist_table$$) - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO dist_table VALUES(1); -NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.dist_table_1503021 (a) VALUES (1) -SELECT * FROM local JOIN dist_table ON (a = x) ORDER BY 1,2,3; - x | y | a ---------------------------------------------------------------------- - 1 | 2 | 1 - 1 | 2 | 1 - 3 | 2 | 3 -(3 rows) - -SELECT * FROM local JOIN dist_table ON (a = x) WHERE a = 1 ORDER BY 1,2,3; -NOTICE: executing the command locally: SELECT local.x, local.y, dist_table.a FROM ((SELECT local_1.x, local_1.y FROM (SELECT intermediate_result.x, intermediate_result.y FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(x integer, y integer)) local_1) local JOIN coordinator_shouldhaveshards.dist_table_1503021 dist_table ON ((dist_table.a OPERATOR(pg_catalog.=) local.x))) WHERE (dist_table.a OPERATOR(pg_catalog.=) 1) ORDER BY local.x, local.y, dist_table.a - x | y | a ---------------------------------------------------------------------- - 1 | 2 | 1 - 1 | 2 | 1 -(2 rows) - --- intermediate results are allowed -WITH cte_1 AS (SELECT * FROM dist_table ORDER BY 1 LIMIT 1) -SELECT * FROM ref JOIN local ON (a = x) JOIN cte_1 ON (local.x = cte_1.a); -NOTICE: executing the command locally: SELECT a FROM coordinator_shouldhaveshards.dist_table_1503021 dist_table WHERE true ORDER BY a LIMIT '1'::bigint -NOTICE: executing the command locally: SELECT a FROM coordinator_shouldhaveshards.dist_table_1503024 dist_table WHERE true ORDER BY a LIMIT '1'::bigint -NOTICE: executing the command locally: SELECT ref.a, ref.b, local.x, local.y, cte_1.a FROM ((coordinator_shouldhaveshards.ref_1503020 ref JOIN (SELECT local_1.x, local_1.y FROM (SELECT intermediate_result.x, intermediate_result.y FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(x integer, y integer)) local_1) local ON ((ref.a OPERATOR(pg_catalog.=) local.x))) JOIN (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) cte_1 ON ((local.x OPERATOR(pg_catalog.=) cte_1.a))) - a | b | x | y | a ---------------------------------------------------------------------- - 1 | 2 | 1 | 2 | 1 -(1 row) - --- full router query with CTE and local -WITH cte_1 AS (SELECT * FROM ref LIMIT 1) -SELECT * FROM ref JOIN local ON (a = x) JOIN cte_1 ON (local.x = cte_1.a); -NOTICE: executing the command locally: SELECT ref.a, ref.b, local.x, local.y, cte_1.a, cte_1.b FROM ((coordinator_shouldhaveshards.ref_1503020 ref JOIN coordinator_shouldhaveshards.local ON ((ref.a OPERATOR(pg_catalog.=) local.x))) JOIN (SELECT ref_1.a, ref_1.b FROM coordinator_shouldhaveshards.ref_1503020 ref_1 LIMIT 1) cte_1 ON ((local.x OPERATOR(pg_catalog.=) cte_1.a))) - a | b | x | y | a | b ---------------------------------------------------------------------- - 1 | 2 | 1 | 2 | 1 | 2 -(1 row) - -DROP TABLE dist_table; --- issue #3801 -SET citus.shard_replication_factor TO 2; -CREATE TABLE dist_table(a int); -SELECT create_distributed_table('dist_table', 'a'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -BEGIN; --- this will use perPlacementQueryStrings, make sure it works correctly with --- copying task -INSERT INTO dist_table SELECT a + 1 FROM dist_table; -NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_1503027_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_1503027_to','SELECT (a OPERATOR(pg_catalog.+) 1) AS a FROM coordinator_shouldhaveshards.dist_table_1503027 dist_table WHERE true',0,'hash','{-2147483648,-1431655766,-715827884,-2,715827880,1431655762}'::text[],'{-1431655767,-715827885,-3,715827879,1431655761,2147483647}'::text[],true) WHERE rows_written > 0 -NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_1503029_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_1503029_to','SELECT (a OPERATOR(pg_catalog.+) 1) AS a FROM coordinator_shouldhaveshards.dist_table_1503029 dist_table WHERE true',0,'hash','{-2147483648,-1431655766,-715827884,-2,715827880,1431655762}'::text[],'{-1431655767,-715827885,-3,715827879,1431655761,2147483647}'::text[],true) WHERE rows_written > 0 -NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_1503030_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_1503030_to','SELECT (a OPERATOR(pg_catalog.+) 1) AS a FROM coordinator_shouldhaveshards.dist_table_1503030 dist_table WHERE true',0,'hash','{-2147483648,-1431655766,-715827884,-2,715827880,1431655762}'::text[],'{-1431655767,-715827885,-3,715827879,1431655761,2147483647}'::text[],true) WHERE rows_written > 0 -NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_1503032_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_1503032_to','SELECT (a OPERATOR(pg_catalog.+) 1) AS a FROM coordinator_shouldhaveshards.dist_table_1503032 dist_table WHERE true',0,'hash','{-2147483648,-1431655766,-715827884,-2,715827880,1431655762}'::text[],'{-1431655767,-715827885,-3,715827879,1431655761,2147483647}'::text[],true) WHERE rows_written > 0 -ROLLBACK; -SET citus.shard_replication_factor TO 1; -BEGIN; -SET citus.shard_replication_factor TO 2; -CREATE TABLE dist_table1(a int); --- this will use queryStringList, make sure it works correctly with --- copying task -SELECT create_distributed_table('dist_table1', 'a'); -NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503033, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table1 (a integer) USING heap');SELECT worker_apply_shard_ddl_command (1503033, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table1 OWNER TO postgres') -NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503035, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table1 (a integer) USING heap');SELECT worker_apply_shard_ddl_command (1503035, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table1 OWNER TO postgres') -NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503036, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table1 (a integer) USING heap');SELECT worker_apply_shard_ddl_command (1503036, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table1 OWNER TO postgres') -NOTICE: executing the command locally: SELECT worker_apply_shard_ddl_command (1503038, 'coordinator_shouldhaveshards', 'CREATE TABLE coordinator_shouldhaveshards.dist_table1 (a integer) USING heap');SELECT worker_apply_shard_ddl_command (1503038, 'coordinator_shouldhaveshards', 'ALTER TABLE coordinator_shouldhaveshards.dist_table1 OWNER TO postgres') - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -ROLLBACK; -CREATE table ref_table(x int, y int); --- this will be replicated to the coordinator because of add_coordinator test -SELECT create_reference_table('ref_table'); - create_reference_table ---------------------------------------------------------------------- - -(1 row) - -TRUNCATE TABLE test; -BEGIN; -INSERT INTO test SELECT *, * FROM generate_series(1, 100); -NOTICE: executing the copy locally for shard xxxxx -NOTICE: executing the copy locally for shard xxxxx -INSERT INTO ref_table SELECT *, * FROM generate_series(1, 100); -NOTICE: executing the copy locally for shard xxxxx -SELECT COUNT(*) FROM test JOIN ref_table USING(x); -NOTICE: executing the command locally: SELECT count(*) AS count FROM (coordinator_shouldhaveshards.test_1503000 test JOIN coordinator_shouldhaveshards.ref_table_1503039 ref_table ON ((test.x OPERATOR(pg_catalog.=) ref_table.x))) WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM (coordinator_shouldhaveshards.test_1503003 test JOIN coordinator_shouldhaveshards.ref_table_1503039 ref_table ON ((test.x OPERATOR(pg_catalog.=) ref_table.x))) WHERE true - count ---------------------------------------------------------------------- - 100 -(1 row) - -ROLLBACK; --- writing to local file and remote intermediate files --- at the same time -INSERT INTO ref_table SELECT *, * FROM generate_series(1, 100); -NOTICE: executing the copy locally for shard xxxxx -CREATE UNIQUE INDEX test_x_unique ON test(x); -WITH cte_1 AS ( -INSERT INTO test SELECT sum(x), y FROM test GROUP BY y ON CONFLICT (x) DO UPDATE SET y = EXCLUDED.y + 1 RETURNING *) -SELECT count(*) FROM cte_1; -NOTICE: executing the command locally: SELECT sum(x) AS x, y FROM coordinator_shouldhaveshards.test_1503000 test WHERE true GROUP BY y -NOTICE: executing the command locally: SELECT sum(x) AS x, y FROM coordinator_shouldhaveshards.test_1503003 test WHERE true GROUP BY y -NOTICE: executing the command locally: SELECT count(*) AS count FROM (SELECT intermediate_result.x, intermediate_result.y FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(x integer, y integer)) cte_1 - count ---------------------------------------------------------------------- - 0 -(1 row) - -DROP INDEX test_x_unique; --- issue #4237: preventing empty placement creation on coordinator -CREATE TABLE test_append_table(a int); -SELECT create_distributed_table('test_append_table', 'a', 'append'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - --- this will fail since it will try to create an empty placement in the --- coordinator as well -SET citus.shard_replication_factor TO 3; -SELECT master_create_empty_shard('test_append_table'); -NOTICE: Creating placements for the append partitioned tables on the coordinator is not supported, skipping coordinator ... -ERROR: could only create 2 of 3 of required shard replicas --- this will create an empty shard with replicas in the two worker nodes -SET citus.shard_replication_factor TO 2; -SELECT 1 FROM master_create_empty_shard('test_append_table'); -NOTICE: Creating placements for the append partitioned tables on the coordinator is not supported, skipping coordinator ... - ?column? ---------------------------------------------------------------------- - 1 -(1 row) - --- verify groupid is not 0 for each placement -SELECT COUNT(*) FROM pg_dist_placement p, pg_dist_shard s WHERE p.shardid = s.shardid AND s.logicalrelid = 'test_append_table'::regclass AND p.groupid > 0; - count ---------------------------------------------------------------------- - 2 -(1 row) - -SET citus.shard_replication_factor TO 1; --- test partitioned index creation with long name -CREATE TABLE test_index_creation1 -( - tenant_id integer NOT NULL, - timeperiod timestamp without time zone NOT NULL, - field1 integer NOT NULL, - inserted_utc timestamp without time zone NOT NULL DEFAULT now(), - PRIMARY KEY(tenant_id, timeperiod) -) PARTITION BY RANGE (timeperiod); -CREATE TABLE test_index_creation1_p2020_09_26 -PARTITION OF test_index_creation1 FOR VALUES FROM ('2020-09-26 00:00:00') TO ('2020-09-27 00:00:00'); -CREATE TABLE test_index_creation1_p2020_09_27 -PARTITION OF test_index_creation1 FOR VALUES FROM ('2020-09-27 00:00:00') TO ('2020-09-28 00:00:00'); -select create_distributed_table('test_index_creation1', 'tenant_id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - --- should be able to create indexes with INCLUDE/WHERE -CREATE INDEX ix_test_index_creation5 ON test_index_creation1 - USING btree(tenant_id, timeperiod) - INCLUDE (field1) WHERE (tenant_id = 100); -NOTICE: executing the command locally: CREATE INDEX ix_test_index_creation5_1503042 ON coordinator_shouldhaveshards.test_index_creation1_1503042 USING btree (tenant_id ,timeperiod ) INCLUDE (field1 ) WHERE (tenant_id = 100) -NOTICE: executing the command locally: CREATE INDEX ix_test_index_creation5_1503045 ON coordinator_shouldhaveshards.test_index_creation1_1503045 USING btree (tenant_id ,timeperiod ) INCLUDE (field1 ) WHERE (tenant_id = 100) -NOTICE: executing the command locally: SELECT pg_catalog.citus_run_local_command($$SELECT worker_fix_partition_shard_index_names('coordinator_shouldhaveshards.ix_test_index_creation5_1503042'::regclass, 'coordinator_shouldhaveshards.test_index_creation1_p2020_09_26_1503048', 'test_index_creation1_p2020_09_2_tenant_id_time_6020e8f8_1503048');SELECT worker_fix_partition_shard_index_names('coordinator_shouldhaveshards.ix_test_index_creation5_1503042'::regclass, 'coordinator_shouldhaveshards.test_index_creation1_p2020_09_26_1503049', 'test_index_creation1_p2020_09_2_tenant_id_time_6020e8f8_1503049');SELECT worker_fix_partition_shard_index_names('coordinator_shouldhaveshards.ix_test_index_creation5_1503042'::regclass, 'coordinator_shouldhaveshards.test_index_creation1_p2020_09_26_1503050', 'test_index_creation1_p2020_09_2_tenant_id_time_6020e8f8_1503050');SELECT worker_fix_partition_shard_index_names('coordinator_shouldhaveshards.ix_test_index_creation5_1503042'::regclass, 'coordinator_shouldhaveshards.test_index_creation1_p2020_09_26_1503051', 'test_index_creation1_p2020_09_2_tenant_id_time_6020e8f8_1503051');SELECT worker_fix_partition_shard_index_names('coordinator_shouldhaveshards.ix_test_index_creation5_1503042'::regclass, 'coordinator_shouldhaveshards.test_index_creation1_p2020_09_26_1503052', 'test_index_creation1_p2020_09_2_tenant_id_time_6020e8f8_1503052');SELECT worker_fix_partition_shard_index_names('coordinator_shouldhaveshards.ix_test_index_creation5_1503042'::regclass, 'coordinator_shouldhaveshards.test_index_creation1_p2020_09_26_1503053', 'test_index_creation1_p2020_09_2_tenant_id_time_6020e8f8_1503053');SELECT worker_fix_partition_shard_index_names('coordinator_shouldhaveshards.ix_test_index_creation5_1503042'::regclass, 'coordinator_shouldhaveshards.test_index_creation1_p2020_09_27_1503054', 'test_index_creation1_p2020_09__tenant_id_timep_624f7e94_1503054');SELECT worker_fix_partition_shard_index_names('coordinator_shouldhaveshards.ix_test_index_creation5_1503042'::regclass, 'coordinator_shouldhaveshards.test_index_creation1_p2020_09_27_1503055', 'test_index_creation1_p2020_09__tenant_id_timep_624f7e94_1503055');SELECT worker_fix_partition_shard_index_names('coordinator_shouldhaveshards.ix_test_index_creation5_1503042'::regclass, 'coordinator_shouldhaveshards.test_index_creation1_p2020_09_27_1503056', 'test_index_creation1_p2020_09__tenant_id_timep_624f7e94_1503056');SELECT worker_fix_partition_shard_index_names('coordinator_shouldhaveshards.ix_test_index_creation5_1503042'::regclass, 'coordinator_shouldhaveshards.test_index_creation1_p2020_09_27_1503057', 'test_index_creation1_p2020_09__tenant_id_timep_624f7e94_1503057');SELECT worker_fix_partition_shard_index_names('coordinator_shouldhaveshards.ix_test_index_creation5_1503042'::regclass, 'coordinator_shouldhaveshards.test_index_creation1_p2020_09_27_1503058', 'test_index_creation1_p2020_09__tenant_id_timep_624f7e94_1503058');SELECT worker_fix_partition_shard_index_names('coordinator_shouldhaveshards.ix_test_index_creation5_1503042'::regclass, 'coordinator_shouldhaveshards.test_index_creation1_p2020_09_27_1503059', 'test_index_creation1_p2020_09__tenant_id_timep_624f7e94_1503059')$$) -NOTICE: executing the command locally: SELECT pg_catalog.citus_run_local_command($$SELECT worker_fix_partition_shard_index_names('coordinator_shouldhaveshards.ix_test_index_creation5_1503045'::regclass, 'coordinator_shouldhaveshards.test_index_creation1_p2020_09_26_1503048', 'test_index_creation1_p2020_09_2_tenant_id_time_6020e8f8_1503048');SELECT worker_fix_partition_shard_index_names('coordinator_shouldhaveshards.ix_test_index_creation5_1503045'::regclass, 'coordinator_shouldhaveshards.test_index_creation1_p2020_09_26_1503049', 'test_index_creation1_p2020_09_2_tenant_id_time_6020e8f8_1503049');SELECT worker_fix_partition_shard_index_names('coordinator_shouldhaveshards.ix_test_index_creation5_1503045'::regclass, 'coordinator_shouldhaveshards.test_index_creation1_p2020_09_26_1503050', 'test_index_creation1_p2020_09_2_tenant_id_time_6020e8f8_1503050');SELECT worker_fix_partition_shard_index_names('coordinator_shouldhaveshards.ix_test_index_creation5_1503045'::regclass, 'coordinator_shouldhaveshards.test_index_creation1_p2020_09_26_1503051', 'test_index_creation1_p2020_09_2_tenant_id_time_6020e8f8_1503051');SELECT worker_fix_partition_shard_index_names('coordinator_shouldhaveshards.ix_test_index_creation5_1503045'::regclass, 'coordinator_shouldhaveshards.test_index_creation1_p2020_09_26_1503052', 'test_index_creation1_p2020_09_2_tenant_id_time_6020e8f8_1503052');SELECT worker_fix_partition_shard_index_names('coordinator_shouldhaveshards.ix_test_index_creation5_1503045'::regclass, 'coordinator_shouldhaveshards.test_index_creation1_p2020_09_26_1503053', 'test_index_creation1_p2020_09_2_tenant_id_time_6020e8f8_1503053');SELECT worker_fix_partition_shard_index_names('coordinator_shouldhaveshards.ix_test_index_creation5_1503045'::regclass, 'coordinator_shouldhaveshards.test_index_creation1_p2020_09_27_1503054', 'test_index_creation1_p2020_09__tenant_id_timep_624f7e94_1503054');SELECT worker_fix_partition_shard_index_names('coordinator_shouldhaveshards.ix_test_index_creation5_1503045'::regclass, 'coordinator_shouldhaveshards.test_index_creation1_p2020_09_27_1503055', 'test_index_creation1_p2020_09__tenant_id_timep_624f7e94_1503055');SELECT worker_fix_partition_shard_index_names('coordinator_shouldhaveshards.ix_test_index_creation5_1503045'::regclass, 'coordinator_shouldhaveshards.test_index_creation1_p2020_09_27_1503056', 'test_index_creation1_p2020_09__tenant_id_timep_624f7e94_1503056');SELECT worker_fix_partition_shard_index_names('coordinator_shouldhaveshards.ix_test_index_creation5_1503045'::regclass, 'coordinator_shouldhaveshards.test_index_creation1_p2020_09_27_1503057', 'test_index_creation1_p2020_09__tenant_id_timep_624f7e94_1503057');SELECT worker_fix_partition_shard_index_names('coordinator_shouldhaveshards.ix_test_index_creation5_1503045'::regclass, 'coordinator_shouldhaveshards.test_index_creation1_p2020_09_27_1503058', 'test_index_creation1_p2020_09__tenant_id_timep_624f7e94_1503058');SELECT worker_fix_partition_shard_index_names('coordinator_shouldhaveshards.ix_test_index_creation5_1503045'::regclass, 'coordinator_shouldhaveshards.test_index_creation1_p2020_09_27_1503059', 'test_index_creation1_p2020_09__tenant_id_timep_624f7e94_1503059')$$) --- test if indexes are created -SELECT 1 AS created WHERE EXISTS(SELECT * FROM pg_indexes WHERE indexname LIKE '%test_index_creation%'); - created ---------------------------------------------------------------------- - 1 -(1 row) - --- test alter_distributed_table UDF -SET citus.shard_count TO 4; -CREATE TABLE adt_table (a INT, b INT); -CREATE TABLE adt_col (a INT UNIQUE, b INT); -CREATE TABLE adt_ref (a INT REFERENCES adt_col(a)); -SELECT create_distributed_table('adt_table', 'a', colocate_with:='none'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -SELECT create_distributed_table('adt_col', 'a', colocate_with:='adt_table'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -SELECT create_distributed_table('adt_ref', 'a', colocate_with:='adt_table'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO adt_table VALUES (1, 2), (3, 4), (5, 6); -NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.adt_table_1503060 AS citus_table_alias (a, b) VALUES (1,2), (5,6) -INSERT INTO adt_col VALUES (3, 4), (5, 6), (7, 8); -NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.adt_col_1503064 AS citus_table_alias (a, b) VALUES (5,6) -INSERT INTO adt_ref VALUES (3), (5); -NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.adt_ref_1503068 AS citus_table_alias (a) VALUES (5) -SELECT table_name, citus_table_type, distribution_column, shard_count FROM public.citus_tables WHERE table_name::text LIKE 'adt%'; - table_name | citus_table_type | distribution_column | shard_count ---------------------------------------------------------------------- - adt_col | distributed | a | 4 - adt_ref | distributed | a | 4 - adt_table | distributed | a | 4 -(3 rows) - -SELECT STRING_AGG(table_name::text, ', ' ORDER BY 1) AS "Colocation Groups" FROM public.citus_tables WHERE table_name::text LIKE 'adt%' GROUP BY colocation_id ORDER BY 1; - Colocation Groups ---------------------------------------------------------------------- - adt_col, adt_ref, adt_table -(1 row) - -SELECT conrelid::regclass::text AS "Referencing Table", pg_get_constraintdef(oid, true) AS "Definition" FROM pg_constraint - WHERE (conrelid::regclass::text = 'adt_col' OR confrelid::regclass::text = 'adt_col') ORDER BY 1; - Referencing Table | Definition ---------------------------------------------------------------------- - adt_col | UNIQUE (a) - adt_ref | FOREIGN KEY (a) REFERENCES adt_col(a) -(2 rows) - -SET client_min_messages TO WARNING; -SELECT alter_distributed_table('adt_table', shard_count:=6, cascade_to_colocated:=true); - alter_distributed_table ---------------------------------------------------------------------- - -(1 row) - -SET client_min_messages TO DEFAULT; -SELECT table_name, citus_table_type, distribution_column, shard_count FROM public.citus_tables WHERE table_name::text LIKE 'adt%'; - table_name | citus_table_type | distribution_column | shard_count ---------------------------------------------------------------------- - adt_col | distributed | a | 6 - adt_ref | distributed | a | 6 - adt_table | distributed | a | 6 -(3 rows) - -SELECT STRING_AGG(table_name::text, ', ' ORDER BY 1) AS "Colocation Groups" FROM public.citus_tables WHERE table_name::text LIKE 'adt%' GROUP BY colocation_id ORDER BY 1; - Colocation Groups ---------------------------------------------------------------------- - adt_col, adt_ref, adt_table -(1 row) - -SELECT conrelid::regclass::text AS "Referencing Table", pg_get_constraintdef(oid, true) AS "Definition" FROM pg_constraint - WHERE (conrelid::regclass::text = 'adt_col' OR confrelid::regclass::text = 'adt_col') ORDER BY 1; - Referencing Table | Definition ---------------------------------------------------------------------- - adt_col | UNIQUE (a) - adt_ref | FOREIGN KEY (a) REFERENCES adt_col(a) -(2 rows) - -SELECT alter_distributed_table('adt_table', distribution_column:='b', colocate_with:='none'); -NOTICE: creating a new table for coordinator_shouldhaveshards.adt_table -NOTICE: moving the data of coordinator_shouldhaveshards.adt_table -NOTICE: dropping the old coordinator_shouldhaveshards.adt_table -NOTICE: renaming the new table to coordinator_shouldhaveshards.adt_table - alter_distributed_table ---------------------------------------------------------------------- - -(1 row) - -SELECT table_name, citus_table_type, distribution_column, shard_count FROM public.citus_tables WHERE table_name::text LIKE 'adt%'; - table_name | citus_table_type | distribution_column | shard_count ---------------------------------------------------------------------- - adt_col | distributed | a | 6 - adt_ref | distributed | a | 6 - adt_table | distributed | b | 6 -(3 rows) - -SELECT STRING_AGG(table_name::text, ', ' ORDER BY 1) AS "Colocation Groups" FROM public.citus_tables WHERE table_name::text LIKE 'adt%' GROUP BY colocation_id ORDER BY 1; - Colocation Groups ---------------------------------------------------------------------- - adt_col, adt_ref - adt_table -(2 rows) - -SELECT conrelid::regclass::text AS "Referencing Table", pg_get_constraintdef(oid, true) AS "Definition" FROM pg_constraint - WHERE (conrelid::regclass::text = 'adt_col' OR confrelid::regclass::text = 'adt_col') ORDER BY 1; - Referencing Table | Definition ---------------------------------------------------------------------- - adt_col | UNIQUE (a) - adt_ref | FOREIGN KEY (a) REFERENCES adt_col(a) -(2 rows) - -SELECT * FROM adt_table ORDER BY 1; - a | b ---------------------------------------------------------------------- - 1 | 2 - 3 | 4 - 5 | 6 -(3 rows) - -SELECT * FROM adt_col ORDER BY 1; - a | b ---------------------------------------------------------------------- - 3 | 4 - 5 | 6 - 7 | 8 -(3 rows) - -SELECT * FROM adt_ref ORDER BY 1; - a ---------------------------------------------------------------------- - 3 - 5 -(2 rows) - -SET client_min_messages TO WARNING; -BEGIN; -INSERT INTO adt_table SELECT x, x+1 FROM generate_series(1, 1000) x; -SELECT alter_distributed_table('adt_table', distribution_column:='a'); - alter_distributed_table ---------------------------------------------------------------------- - -(1 row) - -SELECT COUNT(*) FROM adt_table; - count ---------------------------------------------------------------------- - 1003 -(1 row) - -END; -SELECT table_name, citus_table_type, distribution_column, shard_count FROM public.citus_tables WHERE table_name::text = 'adt_table'; - table_name | citus_table_type | distribution_column | shard_count ---------------------------------------------------------------------- - adt_table | distributed | a | 6 -(1 row) - -SET client_min_messages TO DEFAULT; --- issue 4508 table_1 and table_2 are used to test --- some edge cases around intermediate result pruning -CREATE TABLE table_1 (key int, value text); -SELECT create_distributed_table('table_1', 'key'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -CREATE TABLE table_2 (key int, value text); -SELECT create_distributed_table('table_2', 'key'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO table_1 VALUES (1, '1'), (2, '2'), (3, '3'), (4, '4'); -NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.table_1_1503102 AS citus_table_alias (key, value) VALUES (1,'1'::text) -NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.table_1_1503105 AS citus_table_alias (key, value) VALUES (2,'2'::text) -INSERT INTO table_2 VALUES (1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5'), (6, '6'); -NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.table_2_1503106 AS citus_table_alias (key, value) VALUES (1,'1'::text), (5,'5'::text) -NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.table_2_1503109 AS citus_table_alias (key, value) VALUES (2,'2'::text) -SET citus.log_intermediate_results TO ON; -SET client_min_messages to debug1; -WITH a AS (SELECT * FROM table_1 ORDER BY 1,2 DESC LIMIT 1) -SELECT count(*), -key -FROM a JOIN table_2 USING (key) -GROUP BY key -HAVING (max(table_2.value) >= (SELECT value FROM a)); -DEBUG: generating subplan XXX_1 for CTE a: SELECT key, value FROM coordinator_shouldhaveshards.table_1 ORDER BY key, value DESC LIMIT 1 -DEBUG: push down of limit count: 1 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count, a.key FROM ((SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a JOIN coordinator_shouldhaveshards.table_2 USING (key)) GROUP BY a.key HAVING (max(table_2.value) OPERATOR(pg_catalog.>=) (SELECT a_1.value FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a_1)) -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -NOTICE: executing the command locally: SELECT key, value FROM coordinator_shouldhaveshards.table_1_1503102 table_1 WHERE true ORDER BY key, value DESC LIMIT '1'::bigint -NOTICE: executing the command locally: SELECT key, value FROM coordinator_shouldhaveshards.table_1_1503105 table_1 WHERE true ORDER BY key, value DESC LIMIT '1'::bigint -NOTICE: executing the command locally: SELECT count(*) AS count, worker_column_1 AS key, max(worker_column_2) AS worker_column_3 FROM (SELECT a.key AS worker_column_1, table_2.value AS worker_column_2 FROM ((SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a JOIN coordinator_shouldhaveshards.table_2_1503106 table_2(key, value) USING (key))) worker_subquery GROUP BY worker_column_1 -NOTICE: executing the command locally: SELECT count(*) AS count, worker_column_1 AS key, max(worker_column_2) AS worker_column_3 FROM (SELECT a.key AS worker_column_1, table_2.value AS worker_column_2 FROM ((SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a JOIN coordinator_shouldhaveshards.table_2_1503109 table_2(key, value) USING (key))) worker_subquery GROUP BY worker_column_1 - count | key ---------------------------------------------------------------------- - 1 | 1 -(1 row) - -WITH a AS (SELECT * FROM table_1 ORDER BY 1,2 DESC LIMIT 1) -INSERT INTO table_1 SELECT count(*), -key -FROM a JOIN table_2 USING (key) -GROUP BY key -HAVING (max(table_2.value) >= (SELECT value FROM a)); -DEBUG: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns -DEBUG: generating subplan XXX_1 for CTE a: SELECT key, value FROM coordinator_shouldhaveshards.table_1 ORDER BY key, value DESC LIMIT 1 -DEBUG: push down of limit count: 1 -DEBUG: generating subplan XXX_2 for subquery SELECT int4(count(*)) AS auto_coerced_by_citus_0, (a.key)::text AS auto_coerced_by_citus_1 FROM ((SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a JOIN coordinator_shouldhaveshards.table_2 USING (key)) GROUP BY a.key HAVING (max(table_2.value) OPERATOR(pg_catalog.>=) (SELECT a_1.value FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a_1)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT auto_coerced_by_citus_0 AS key, auto_coerced_by_citus_1 AS value FROM (SELECT intermediate_result.auto_coerced_by_citus_0, intermediate_result.auto_coerced_by_citus_1 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(auto_coerced_by_citus_0 integer, auto_coerced_by_citus_1 text)) citus_insert_select_subquery -DEBUG: Collecting INSERT ... SELECT results on coordinator -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -NOTICE: executing the command locally: SELECT key, value FROM coordinator_shouldhaveshards.table_1_1503102 table_1 WHERE true ORDER BY key, value DESC LIMIT '1'::bigint -NOTICE: executing the command locally: SELECT key, value FROM coordinator_shouldhaveshards.table_1_1503105 table_1 WHERE true ORDER BY key, value DESC LIMIT '1'::bigint -DEBUG: Subplan XXX_2 will be written to local file -NOTICE: executing the command locally: SELECT count(*) AS auto_coerced_by_citus_0, (worker_column_1)::text AS auto_coerced_by_citus_1, worker_column_1 AS discarded_target_item_1, max(worker_column_2) AS worker_column_4 FROM (SELECT a.key AS worker_column_1, table_2.value AS worker_column_2 FROM ((SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a JOIN coordinator_shouldhaveshards.table_2_1503106 table_2(key, value) USING (key))) worker_subquery GROUP BY worker_column_1 -NOTICE: executing the command locally: SELECT count(*) AS auto_coerced_by_citus_0, (worker_column_1)::text AS auto_coerced_by_citus_1, worker_column_1 AS discarded_target_item_1, max(worker_column_2) AS worker_column_4 FROM (SELECT a.key AS worker_column_1, table_2.value AS worker_column_2 FROM ((SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a JOIN coordinator_shouldhaveshards.table_2_1503109 table_2(key, value) USING (key))) worker_subquery GROUP BY worker_column_1 -NOTICE: executing the command locally: SELECT auto_coerced_by_citus_0 AS key, auto_coerced_by_citus_1 AS value FROM (SELECT intermediate_result.auto_coerced_by_citus_0, intermediate_result.auto_coerced_by_citus_1 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(auto_coerced_by_citus_0 integer, auto_coerced_by_citus_1 text)) citus_insert_select_subquery -NOTICE: executing the copy locally for shard xxxxx -WITH stats AS ( - SELECT count(key) m FROM table_1 -), -inserts AS ( - INSERT INTO table_2 - SELECT key, count(*) - FROM table_1 - WHERE key >= (SELECT m FROM stats) - GROUP BY key - HAVING count(*) <= (SELECT m FROM stats) - LIMIT 1 - RETURNING * -) SELECT count(*) FROM inserts; -DEBUG: generating subplan XXX_1 for CTE stats: SELECT count(key) AS m FROM coordinator_shouldhaveshards.table_1 -DEBUG: generating subplan XXX_2 for CTE inserts: INSERT INTO coordinator_shouldhaveshards.table_2 (key, value) SELECT key, count(*) AS count FROM coordinator_shouldhaveshards.table_1 WHERE (key OPERATOR(pg_catalog.>=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) GROUP BY key HAVING (count(*) OPERATOR(pg_catalog.<=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) LIMIT 1 RETURNING table_2.key, table_2.value -DEBUG: cannot push down this subquery -DETAIL: Limit clause is currently unsupported when a subquery references a column from another query -DEBUG: push down of limit count: 1 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) inserts -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -NOTICE: executing the command locally: SELECT count(key) AS m FROM coordinator_shouldhaveshards.table_1_1503102 table_1 WHERE true -NOTICE: executing the command locally: SELECT count(key) AS m FROM coordinator_shouldhaveshards.table_1_1503105 table_1 WHERE true -DEBUG: Subplan XXX_2 will be written to local file -DEBUG: Collecting INSERT ... SELECT results on coordinator -NOTICE: executing the command locally: SELECT worker_column_1 AS key, (count(*))::text AS value FROM (SELECT table_1.key AS worker_column_1 FROM coordinator_shouldhaveshards.table_1_1503102 table_1 WHERE (table_1.key OPERATOR(pg_catalog.>=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats))) worker_subquery GROUP BY worker_column_1 HAVING (count(*) OPERATOR(pg_catalog.<=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) LIMIT '1'::bigint -NOTICE: executing the command locally: SELECT worker_column_1 AS key, (count(*))::text AS value FROM (SELECT table_1.key AS worker_column_1 FROM coordinator_shouldhaveshards.table_1_1503105 table_1 WHERE (table_1.key OPERATOR(pg_catalog.>=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats))) worker_subquery GROUP BY worker_column_1 HAVING (count(*) OPERATOR(pg_catalog.<=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) LIMIT '1'::bigint -NOTICE: executing the command locally: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) inserts - count ---------------------------------------------------------------------- - 0 -(1 row) - --- a helper function which return true if the coordinated --- trannsaction uses 2PC -SET citus.enable_metadata_sync TO OFF; -CREATE OR REPLACE FUNCTION coordinated_transaction_should_use_2PC() -RETURNS BOOL LANGUAGE C STRICT VOLATILE AS 'citus', -$$coordinated_transaction_should_use_2PC$$; -RESET citus.enable_metadata_sync; --- a local SELECT followed by remote SELECTs --- does not trigger 2PC -BEGIN; - SELECT y FROM test WHERE x = 1; -NOTICE: executing the command locally: SELECT y FROM coordinator_shouldhaveshards.test_1503000 test WHERE (x OPERATOR(pg_catalog.=) 1) - y ---------------------------------------------------------------------- -(0 rows) - - WITH cte_1 AS (SELECT y FROM test WHERE x = 1 LIMIT 5) SELECT count(*) FROM test; -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503000 test WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503003 test WHERE true - count ---------------------------------------------------------------------- - 0 -(1 row) - - SELECT count(*) FROM test; -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503000 test WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503003 test WHERE true - count ---------------------------------------------------------------------- - 0 -(1 row) - - WITH cte_1 as (SELECT * FROM test LIMIT 5) SELECT count(*) FROM test; -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503000 test WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503003 test WHERE true - count ---------------------------------------------------------------------- - 0 -(1 row) - - SELECT coordinated_transaction_should_use_2PC(); - coordinated_transaction_should_use_2pc ---------------------------------------------------------------------- - f -(1 row) - -COMMIT; --- remote SELECTs followed by local SELECTs --- does not trigger 2PC -BEGIN; - SELECT count(*) FROM test; -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503000 test WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503003 test WHERE true - count ---------------------------------------------------------------------- - 0 -(1 row) - - WITH cte_1 as (SELECT * FROM test LIMIT 5) SELECT count(*) FROM test; -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503000 test WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503003 test WHERE true - count ---------------------------------------------------------------------- - 0 -(1 row) - - SELECT y FROM test WHERE x = 1; -NOTICE: executing the command locally: SELECT y FROM coordinator_shouldhaveshards.test_1503000 test WHERE (x OPERATOR(pg_catalog.=) 1) - y ---------------------------------------------------------------------- -(0 rows) - - WITH cte_1 AS (SELECT y FROM test WHERE x = 1 LIMIT 5) SELECT count(*) FROM test; -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503000 test WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503003 test WHERE true - count ---------------------------------------------------------------------- - 0 -(1 row) - - SELECT coordinated_transaction_should_use_2PC(); - coordinated_transaction_should_use_2pc ---------------------------------------------------------------------- - f -(1 row) - -COMMIT; --- a local SELECT followed by a remote Modify --- triggers 2PC -BEGIN; - SELECT y FROM test WHERE x = 1; -NOTICE: executing the command locally: SELECT y FROM coordinator_shouldhaveshards.test_1503000 test WHERE (x OPERATOR(pg_catalog.=) 1) - y ---------------------------------------------------------------------- -(0 rows) - - UPDATE test SET y = y +1; -NOTICE: executing the command locally: UPDATE coordinator_shouldhaveshards.test_1503000 test SET y = (y OPERATOR(pg_catalog.+) 1) -NOTICE: executing the command locally: UPDATE coordinator_shouldhaveshards.test_1503003 test SET y = (y OPERATOR(pg_catalog.+) 1) - SELECT coordinated_transaction_should_use_2PC(); - coordinated_transaction_should_use_2pc ---------------------------------------------------------------------- - t -(1 row) - -COMMIT; --- a local modify followed by a remote SELECT --- triggers 2PC -BEGIN; - INSERT INTO test VALUES (1,1); -NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.test_1503000 (x, y) VALUES (1, 1) - SELECT count(*) FROM test; -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503000 test WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503003 test WHERE true - count ---------------------------------------------------------------------- - 1 -(1 row) - - SELECT coordinated_transaction_should_use_2PC(); - coordinated_transaction_should_use_2pc ---------------------------------------------------------------------- - t -(1 row) - -COMMIT; --- a local modify followed by a remote MODIFY --- triggers 2PC -BEGIN; - INSERT INTO test VALUES (1,1); -NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.test_1503000 (x, y) VALUES (1, 1) - UPDATE test SET y = y +1; -NOTICE: executing the command locally: UPDATE coordinator_shouldhaveshards.test_1503000 test SET y = (y OPERATOR(pg_catalog.+) 1) -NOTICE: executing the command locally: UPDATE coordinator_shouldhaveshards.test_1503003 test SET y = (y OPERATOR(pg_catalog.+) 1) - SELECT coordinated_transaction_should_use_2PC(); - coordinated_transaction_should_use_2pc ---------------------------------------------------------------------- - t -(1 row) - -COMMIT; --- a local modify followed by a remote single shard MODIFY --- triggers 2PC -BEGIN; - INSERT INTO test VALUES (1,1); -NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.test_1503000 (x, y) VALUES (1, 1) - INSERT INTO test VALUES (3,3); - SELECT coordinated_transaction_should_use_2PC(); - coordinated_transaction_should_use_2pc ---------------------------------------------------------------------- - t -(1 row) - -COMMIT; --- a remote single shard modify followed by a local single --- shard MODIFY triggers 2PC -BEGIN; - INSERT INTO test VALUES (3,3); - INSERT INTO test VALUES (1,1); -NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.test_1503000 (x, y) VALUES (1, 1) - SELECT coordinated_transaction_should_use_2PC(); - coordinated_transaction_should_use_2pc ---------------------------------------------------------------------- - t -(1 row) - -COMMIT; --- a remote single shard select followed by a local single --- shard MODIFY triggers 2PC. But, the transaction manager --- is smart enough to skip sending 2PC as the remote --- command is read only -BEGIN; - SELECT count(*) FROM test WHERE x = 3; - count ---------------------------------------------------------------------- - 2 -(1 row) - - INSERT INTO test VALUES (1,1); -NOTICE: executing the command locally: INSERT INTO coordinator_shouldhaveshards.test_1503000 (x, y) VALUES (1, 1) - SELECT coordinated_transaction_should_use_2PC(); - coordinated_transaction_should_use_2pc ---------------------------------------------------------------------- - t -(1 row) - - SET LOCAL citus.log_remote_commands TO ON; -COMMIT; -NOTICE: issuing COMMIT -DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx --- a local single shard select followed by a remote single --- shard modify does not trigger 2PC -BEGIN; - SELECT count(*) FROM test WHERE x = 1; -NOTICE: executing the command locally: SELECT count(*) AS count FROM coordinator_shouldhaveshards.test_1503000 test WHERE (x OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 5 -(1 row) - - INSERT INTO test VALUES (3,3); - SELECT coordinated_transaction_should_use_2PC(); - coordinated_transaction_should_use_2pc ---------------------------------------------------------------------- - f -(1 row) - - SET LOCAL citus.log_remote_commands TO ON; -COMMIT; -NOTICE: issuing COMMIT -DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx -RESET client_min_messages; -\set VERBOSITY terse -DROP TABLE ref_table; -NOTICE: executing the command locally: DROP TABLE IF EXISTS coordinator_shouldhaveshards.ref_table_xxxxx CASCADE -DELETE FROM test; -DROP TABLE test; -DROP TABLE dist_table; -DROP TABLE ref; -NOTICE: executing the command locally: DROP TABLE IF EXISTS coordinator_shouldhaveshards.ref_xxxxx CASCADE -DROP TABLE test_append_table; -DROP SCHEMA coordinator_shouldhaveshards CASCADE; -NOTICE: drop cascades to 20 other objects -SELECT 1 FROM master_set_node_property('localhost', :master_port, 'shouldhaveshards', false); - ?column? ---------------------------------------------------------------------- - 1 -(1 row) - diff --git a/src/test/regress/expected/cte_inline.out b/src/test/regress/expected/cte_inline.out index 7af842e29..e558df2e2 100644 --- a/src/test/regress/expected/cte_inline.out +++ b/src/test/regress/expected/cte_inline.out @@ -1,17 +1,6 @@ -- -- CTE_INLINE -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - t -(1 row) - CREATE SCHEMA cte_inline; SET search_path TO cte_inline; SET citus.next_shard_id TO 1960000; diff --git a/src/test/regress/expected/cte_inline_0.out b/src/test/regress/expected/cte_inline_0.out deleted file mode 100644 index e5afa4ee3..000000000 --- a/src/test/regress/expected/cte_inline_0.out +++ /dev/null @@ -1,1489 +0,0 @@ --- --- CTE_INLINE --- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - f -(1 row) - -CREATE SCHEMA cte_inline; -SET search_path TO cte_inline; -SET citus.next_shard_id TO 1960000; -CREATE TABLE test_table (key int, value text, other_value jsonb); -SELECT create_distributed_table ('test_table', 'key'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO test_table SELECT i % 10, 'test' || i, row_to_json(row(i, i*18, 'test' || i)) FROM generate_series (0, 100) i; -SET client_min_messages TO DEBUG; --- Citus should not inline this CTE because otherwise it cannot --- plan the query -WITH cte_1 AS (SELECT * FROM test_table) -SELECT - * -FROM - test_table LEFT JOIN cte_1 USING (value) -ORDER BY 1 DESC LIMIT 3; -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT test_table.value, test_table.key, test_table.other_value, cte_1.key, cte_1.other_value FROM (cte_inline.test_table LEFT JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1 USING (value)) ORDER BY test_table.value DESC LIMIT 3 -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 3 - value | key | other_value | key | other_value ---------------------------------------------------------------------- - test99 | 9 | {"f1": 99, "f2": 1782, "f3": "test99"} | 9 | {"f1": 99, "f2": 1782, "f3": "test99"} - test98 | 8 | {"f1": 98, "f2": 1764, "f3": "test98"} | 8 | {"f1": 98, "f2": 1764, "f3": "test98"} - test97 | 7 | {"f1": 97, "f2": 1746, "f3": "test97"} | 7 | {"f1": 97, "f2": 1746, "f3": "test97"} -(3 rows) - --- Should still not be inlined even if NOT MATERIALIZED is passed -WITH cte_1 AS NOT MATERIALIZED (SELECT * FROM test_table) -SELECT - * -FROM - test_table LEFT JOIN cte_1 USING (value) -ORDER BY 2 DESC LIMIT 1; -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT test_table.value, test_table.key, test_table.other_value, cte_1.key, cte_1.other_value FROM (cte_inline.test_table LEFT JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1 USING (value)) ORDER BY test_table.key DESC LIMIT 1 -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 1 - value | key | other_value | key | other_value ---------------------------------------------------------------------- - test9 | 9 | {"f1": 9, "f2": 162, "f3": "test9"} | 9 | {"f1": 9, "f2": 162, "f3": "test9"} -(1 row) - --- the cte can be inlined because the unsupported --- part of the query (subquery in WHERE clause) --- doesn't access the cte -WITH cte_1 AS (SELECT * FROM test_table) -SELECT - count(*) -FROM - cte_1 -WHERE - key IN ( - SELECT - (SELECT 1) - FROM - test_table WHERE key = 1 - ); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 1 -DEBUG: generating subplan XXX_1 for subquery SELECT (SELECT 1) FROM cte_inline.test_table WHERE (key OPERATOR(pg_catalog.=) 1) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) cte_1 WHERE (key OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result."?column?" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result("?column?" integer))) -DEBUG: Router planner cannot handle multi-shard select queries - count ---------------------------------------------------------------------- - 10 -(1 row) - --- a similar query as the above, and this time the planning --- fails, but it fails because the subquery in WHERE clause --- cannot be planned by Citus -WITH cte_1 AS (SELECT * FROM test_table) -SELECT - count(*) -FROM - cte_1 -WHERE - key IN ( - SELECT - key - FROM - test_table - FOR UPDATE - ); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: SELECT FOR UPDATE with table replication factor > 1 not supported for non-reference tables. -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT key, value, other_value FROM cte_inline.test_table -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: SELECT FOR UPDATE with table replication factor > 1 not supported for non-reference tables. -ERROR: could not run distributed query with FOR UPDATE/SHARE commands -HINT: Consider using an equality filter on the distributed table's partition column. --- Citus does the inlining, the planning fails --- and retries without inlining, which works --- fine later via recursive planning -WITH cte_1 AS - (SELECT * - FROM test_table) -SELECT *, (SELECT 1) -FROM - (SELECT * - FROM cte_1) AS foo -ORDER BY 2 DESC LIMIT 1; -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 1 - key | value | other_value | ?column? ---------------------------------------------------------------------- - 9 | test99 | {"f1": 99, "f2": 1782, "f3": "test99"} | 1 -(1 row) - --- a little more complicated query tree --- Citus does the inlining, the planning fails --- and retries without inlining, which works -WITH top_cte AS - (SELECT * - FROM test_table) -SELECT count(*) -FROM top_cte, - (WITH cte_1 AS - (SELECT * - FROM test_table) SELECT *, (SELECT 1) - FROM - (SELECT * - FROM cte_1) AS foo) AS bar; -DEBUG: CTE top_cte is going to be inlined via distributed planning -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value, (SELECT 1) FROM (SELECT cte_1.key, cte_1.value, cte_1.other_value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) cte_1) foo -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) top_cte, (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value, intermediate_result."?column?" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb, "?column?" integer)) bar(key, value, other_value, "?column?") -DEBUG: Router planner cannot handle multi-shard select queries - count ---------------------------------------------------------------------- - 10201 -(1 row) - --- CTE is used inside a subquery in WHERE clause --- the query wouldn't work by inlining, so Citus --- retries again via recursive planning, which --- works fine -WITH cte_1 AS - (SELECT * - FROM test_table) -SELECT count(*) -FROM test_table -WHERE KEY IN - (SELECT (SELECT 1) - FROM - (SELECT *, - random() - FROM - (SELECT * - FROM cte_1) AS foo) AS bar); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for subquery SELECT (SELECT 1) FROM (SELECT foo.key, foo.value, foo.other_value, random() AS random FROM (SELECT cte_1.key, cte_1.value, cte_1.other_value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) cte_1) foo) bar -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM cte_inline.test_table WHERE (key OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result."?column?" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result("?column?" integer))) -DEBUG: Router planner cannot handle multi-shard select queries - count ---------------------------------------------------------------------- - 10 -(1 row) - --- cte_1 is used inside another CTE, but still --- doesn't work when inlined because it is finally --- used in an unsupported query --- but still works fine because recursive planning --- kicks in -WITH cte_1 AS - (SELECT * - FROM test_table) -SELECT (SELECT 1) AS KEY FROM ( - WITH cte_2 AS (SELECT *, random() - FROM (SELECT *,random() FROM cte_1) as foo) -SELECT *, random() FROM cte_2) as bar ORDER BY 1 DESC LIMIT 3; -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for CTE cte_2: SELECT key, value, other_value, random, random() AS random FROM (SELECT cte_1.key, cte_1.value, cte_1.other_value, random() AS random FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) cte_1) foo -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT (SELECT 1) AS key FROM (SELECT cte_2.key, cte_2.value, cte_2.other_value, cte_2.random, cte_2.random_1 AS random, random() AS random FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value, intermediate_result.random, intermediate_result.random_1 AS random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb, random double precision, random_1 double precision)) cte_2(key, value, other_value, random, random_1)) bar(key, value, other_value, random, random_1, random_2) ORDER BY (SELECT 1) DESC LIMIT 3 -DEBUG: Creating router plan - key ---------------------------------------------------------------------- - 1 - 1 - 1 -(3 rows) - --- in this example, cte_2 can be inlined, because it is not used --- on any query that Citus cannot plan. However, cte_1 should not be --- inlined, because it is used with a subquery in target list -WITH cte_1 AS (SELECT * FROM test_table), - cte_2 AS (select * from test_table) -SELECT - count(*) -FROM - (SELECT *, (SELECT 1) FROM cte_1) as foo - JOIN - cte_2 - ON (true); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: CTE cte_2 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT cte_1.key, cte_1.value, cte_1.other_value, (SELECT 1) FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) cte_1) foo(key, value, other_value, "?column?") JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_2 ON (true)) -DEBUG: Router planner cannot handle multi-shard select queries - count ---------------------------------------------------------------------- - 10201 -(1 row) - --- unreferenced CTEs are just ignored --- by Citus/Postgres -WITH a AS (SELECT * FROM test_table) -SELECT - *, row_number() OVER () -FROM - test_table -WHERE - key = 1 -ORDER BY 3 DESC -LIMIT 5; -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 1 - key | value | other_value | row_number ---------------------------------------------------------------------- - 1 | test91 | {"f1": 91, "f2": 1638, "f3": "test91"} | 10 - 1 | test81 | {"f1": 81, "f2": 1458, "f3": "test81"} | 9 - 1 | test71 | {"f1": 71, "f2": 1278, "f3": "test71"} | 8 - 1 | test61 | {"f1": 61, "f2": 1098, "f3": "test61"} | 7 - 1 | test51 | {"f1": 51, "f2": 918, "f3": "test51"} | 6 -(5 rows) - --- router queries are affected by the distributed --- cte inlining -WITH a AS (SELECT * FROM test_table WHERE key = 1) -SELECT - *, (SELECT 1) -FROM - a -WHERE - key = 1 -ORDER BY 1 DESC -LIMIT 5; -DEBUG: CTE a is going to be inlined via distributed planning -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 1 - key | value | other_value | ?column? ---------------------------------------------------------------------- - 1 | test1 | {"f1": 1, "f2": 18, "f3": "test1"} | 1 - 1 | test11 | {"f1": 11, "f2": 198, "f3": "test11"} | 1 - 1 | test21 | {"f1": 21, "f2": 378, "f3": "test21"} | 1 - 1 | test31 | {"f1": 31, "f2": 558, "f3": "test31"} | 1 - 1 | test41 | {"f1": 41, "f2": 738, "f3": "test41"} | 1 -(5 rows) - --- non router queries are affected by the distributed --- cte inlining as well -WITH a AS (SELECT * FROM test_table) -SELECT - count(*) -FROM - a -WHERE - key = 1; -DEBUG: CTE a is going to be inlined via distributed planning -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 1 - count ---------------------------------------------------------------------- - 10 -(1 row) - --- explicitely using NOT MATERIALIZED should result in the same -WITH a AS NOT MATERIALIZED (SELECT * FROM test_table) -SELECT - count(*) -FROM - a -WHERE - key = 1; -DEBUG: CTE a is going to be inlined via distributed planning -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 1 - count ---------------------------------------------------------------------- - 10 -(1 row) - --- using MATERIALIZED should cause inlining not to happen -WITH a AS MATERIALIZED (SELECT * FROM test_table) -SELECT - count(*) -FROM - a -WHERE - key = 1; -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for CTE a: SELECT key, value, other_value FROM cte_inline.test_table -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) a WHERE (key OPERATOR(pg_catalog.=) 1) -DEBUG: Creating router plan - count ---------------------------------------------------------------------- - 10 -(1 row) - --- EXPLAIN should show the difference between materialized an not materialized -EXPLAIN (COSTS OFF) WITH a AS (SELECT * FROM test_table) -SELECT - count(*) -FROM - a -WHERE - key = 1; -DEBUG: CTE a is going to be inlined via distributed planning -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 1 - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus Adaptive) - Task Count: 1 - Tasks Shown: All - -> Task - Node: host=localhost port=xxxxx dbname=regression - -> Aggregate - -> Seq Scan on test_table_1960000 test_table - Filter: (key = 1) -(8 rows) - -EXPLAIN (COSTS OFF) WITH a AS MATERIALIZED (SELECT * FROM test_table) -SELECT - count(*) -FROM - a -WHERE - key = 1; -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for CTE a: SELECT key, value, other_value FROM cte_inline.test_table -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) a WHERE (key OPERATOR(pg_catalog.=) 1) -DEBUG: Creating router plan - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus Adaptive) - -> Distributed Subplan XXX_1 - -> Custom Scan (Citus Adaptive) - Task Count: 4 - Tasks Shown: One of 4 - -> Task - Node: host=localhost port=xxxxx dbname=regression - -> Seq Scan on test_table_1960000 test_table - Task Count: 1 - Tasks Shown: All - -> Task - Node: host=localhost port=xxxxx dbname=regression - -> Aggregate - -> Function Scan on read_intermediate_result intermediate_result - Filter: (key = 1) -(15 rows) - --- citus should not inline the CTE because it is used multiple times -WITH cte_1 AS (SELECT * FROM test_table) -SELECT - count(*) -FROM - cte_1 as first_entry - JOIN - cte_1 as second_entry - USING (key); -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT key, value, other_value FROM cte_inline.test_table -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) first_entry JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) second_entry USING (key)) -DEBUG: Creating router plan - count ---------------------------------------------------------------------- - 1021 -(1 row) - --- NOT MATERIALIZED should cause the query to be inlined twice -WITH cte_1 AS NOT MATERIALIZED (SELECT * FROM test_table) -SELECT - count(*) -FROM - cte_1 as first_entry - JOIN - cte_1 as second_entry - USING (key); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: join prunable for intervals [-2147483648,-1073741825] and [-1073741824,-1] -DEBUG: join prunable for intervals [-2147483648,-1073741825] and [0,1073741823] -DEBUG: join prunable for intervals [-2147483648,-1073741825] and [1073741824,2147483647] -DEBUG: join prunable for intervals [-1073741824,-1] and [-2147483648,-1073741825] -DEBUG: join prunable for intervals [-1073741824,-1] and [0,1073741823] -DEBUG: join prunable for intervals [-1073741824,-1] and [1073741824,2147483647] -DEBUG: join prunable for intervals [0,1073741823] and [-2147483648,-1073741825] -DEBUG: join prunable for intervals [0,1073741823] and [-1073741824,-1] -DEBUG: join prunable for intervals [0,1073741823] and [1073741824,2147483647] -DEBUG: join prunable for intervals [1073741824,2147483647] and [-2147483648,-1073741825] -DEBUG: join prunable for intervals [1073741824,2147483647] and [-1073741824,-1] -DEBUG: join prunable for intervals [1073741824,2147483647] and [0,1073741823] - count ---------------------------------------------------------------------- - 1021 -(1 row) - --- EXPLAIN should show the differences between MATERIALIZED and NOT MATERIALIZED -\set VERBOSITY terse -SELECT public.coordinator_plan_with_subplans($Q$ -EXPLAIN (COSTS OFF) WITH cte_1 AS (SELECT * FROM test_table) -SELECT - count(*) -FROM - cte_1 as first_entry - JOIN - cte_1 as second_entry - USING (key); -$Q$); -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT key, value, other_value FROM cte_inline.test_table -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) first_entry JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) second_entry USING (key)) -DEBUG: Creating router plan - coordinator_plan_with_subplans ---------------------------------------------------------------------- - Custom Scan (Citus Adaptive) - -> Distributed Subplan XXX_1 - -> Custom Scan (Citus Adaptive) - Task Count: 4 - Task Count: 1 -(5 rows) - -\set VERBOSITY default -EXPLAIN (COSTS OFF) WITH cte_1 AS NOT MATERIALIZED (SELECT * FROM test_table) -SELECT - count(*) -FROM - cte_1 as first_entry - JOIN - cte_1 as second_entry - USING (key); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: join prunable for intervals [-2147483648,-1073741825] and [-1073741824,-1] -DEBUG: join prunable for intervals [-2147483648,-1073741825] and [0,1073741823] -DEBUG: join prunable for intervals [-2147483648,-1073741825] and [1073741824,2147483647] -DEBUG: join prunable for intervals [-1073741824,-1] and [-2147483648,-1073741825] -DEBUG: join prunable for intervals [-1073741824,-1] and [0,1073741823] -DEBUG: join prunable for intervals [-1073741824,-1] and [1073741824,2147483647] -DEBUG: join prunable for intervals [0,1073741823] and [-2147483648,-1073741825] -DEBUG: join prunable for intervals [0,1073741823] and [-1073741824,-1] -DEBUG: join prunable for intervals [0,1073741823] and [1073741824,2147483647] -DEBUG: join prunable for intervals [1073741824,2147483647] and [-2147483648,-1073741825] -DEBUG: join prunable for intervals [1073741824,2147483647] and [-1073741824,-1] -DEBUG: join prunable for intervals [1073741824,2147483647] and [0,1073741823] - QUERY PLAN ---------------------------------------------------------------------- - Aggregate - -> Custom Scan (Citus Adaptive) - Task Count: 4 - Tasks Shown: One of 4 - -> Task - Node: host=localhost port=xxxxx dbname=regression - -> Aggregate - -> Hash Join - Hash Cond: (test_table.key = test_table_1.key) - -> Seq Scan on test_table_1960000 test_table - -> Hash - -> Seq Scan on test_table_1960000 test_table_1 -(12 rows) - --- ctes with volatile functions are not --- inlined -WITH cte_1 AS (SELECT *, random() FROM test_table) -SELECT - key, value -FROM - cte_1 -ORDER BY 2 DESC LIMIT 1; -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT key, value, other_value, random() AS random FROM cte_inline.test_table -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT key, value FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb, random double precision)) cte_1 ORDER BY value DESC LIMIT 1 -DEBUG: Creating router plan - key | value ---------------------------------------------------------------------- - 9 | test99 -(1 row) - --- even with NOT MATERIALIZED volatile functions should not be inlined -WITH cte_1 AS NOT MATERIALIZED (SELECT *, random() FROM test_table) -SELECT - count(*) -FROM - cte_1; -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT key, value, other_value, random() AS random FROM cte_inline.test_table -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb, random double precision)) cte_1 -DEBUG: Creating router plan - count ---------------------------------------------------------------------- - 101 -(1 row) - --- cte_1 should be able to inlined even if --- it is used one level below -WITH cte_1 AS (SELECT * FROM test_table) -SELECT - count(*) -FROM -( - WITH ct2 AS (SELECT * FROM cte_1) - SELECT * FROM ct2 -) as foo; -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: CTE ct2 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries - count ---------------------------------------------------------------------- - 101 -(1 row) - --- a similar query, but there is also --- one more cte, which relies on the previous --- CTE -WITH cte_1 AS (SELECT * FROM test_table) -SELECT - count(DISTINCT key) -FROM -( - WITH cte_2 AS (SELECT * FROM cte_1), - cte_3 AS (SELECT * FROM cte_2) - SELECT * FROM cte_3 -) as foo; -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: CTE cte_2 is going to be inlined via distributed planning -DEBUG: CTE cte_3 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries - count ---------------------------------------------------------------------- - 10 -(1 row) - --- inlined CTE contains a reference to outer query --- should be fine (because we pushdown the whole query) -SELECT count(*) - FROM - (SELECT * - FROM test_table) AS test_table_cte - JOIN LATERAL - (WITH bar AS (SELECT * - FROM test_table - WHERE key = test_table_cte.key) - SELECT * - FROM - bar - LEFT JOIN test_table u2 ON u2.key = bar.key) AS foo ON TRUE; -DEBUG: CTE bar is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries - count ---------------------------------------------------------------------- - 10331 -(1 row) - --- inlined CTE contains a reference to outer query --- should be fine (even if the recursive planning fails --- to recursively plan the query) -SELECT count(*) - FROM - (SELECT * - FROM test_table) AS test_table_cte - JOIN LATERAL - (WITH bar AS (SELECT * - FROM test_table - WHERE key = test_table_cte.key) - SELECT * - FROM - bar - LEFT JOIN test_table u2 ON u2.key = bar.value::int) AS foo ON TRUE; -DEBUG: CTE bar is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: skipping recursive planning for the subquery since it contains references to outer queries -DEBUG: skipping recursive planning for the subquery since it contains references to outer queries -DEBUG: skipping recursive planning for the subquery since it contains references to outer queries -DEBUG: Router planner cannot handle multi-shard select queries -ERROR: CTEs that refer to other subqueries are not supported in multi-shard queries --- inlined CTE can recursively planned later, that's the decision --- recursive planning makes --- LIMIT 5 in cte2 triggers recusrive planning, after cte inlining -WITH cte_1 AS (SELECT * FROM test_table) -SELECT - * -FROM -( - WITH ct2 AS (SELECT * FROM cte_1 ORDER BY 1, 2, 3 LIMIT 5) - SELECT * FROM ct2 -) as foo ORDER BY 1 DESC, 2 DESC, 3 DESC LIMIT 5; -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: CTE ct2 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 5 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) cte_1 ORDER BY key, value, other_value LIMIT 5 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT key, value, other_value FROM (SELECT ct2.key, ct2.value, ct2.other_value FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) ct2) foo ORDER BY key DESC, value DESC, other_value DESC LIMIT 5 -DEBUG: Creating router plan - key | value | other_value ---------------------------------------------------------------------- - 0 | test30 | {"f1": 30, "f2": 540, "f3": "test30"} - 0 | test20 | {"f1": 20, "f2": 360, "f3": "test20"} - 0 | test100 | {"f1": 100, "f2": 1800, "f3": "test100"} - 0 | test10 | {"f1": 10, "f2": 180, "f3": "test10"} - 0 | test0 | {"f1": 0, "f2": 0, "f3": "test0"} -(5 rows) - --- all nested CTEs can be inlinied -WITH cte_1 AS ( - WITH cte_1 AS ( - WITH cte_1 AS ( - WITH cte_1 AS ( - WITH cte_1 AS ( - WITH cte_1 AS ( - WITH cte_1 AS (SELECT count(*), key FROM test_table GROUP BY key) - SELECT * FROM cte_1) - SELECT * FROM cte_1 WHERE key >= 1) - SELECT * FROM cte_1 WHERE key >= 2) - SELECT * FROM cte_1 WHERE key >= 3) - SELECT * FROM cte_1 WHERE key >= 4) - SELECT * FROM cte_1 WHERE key >= 5) -SELECT * FROM cte_1 WHERE key = 1; -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 1 - count | key ---------------------------------------------------------------------- -(0 rows) - --- ctes can be inlined even if they are used --- in set operations -WITH cte_1 AS (SELECT * FROM test_table), - cte_2 AS (SELECT * FROM test_table) -SELECT count(*) FROM ( -(SELECT * FROM cte_1 EXCEPT SELECT * FROM test_table) -UNION -(SELECT * FROM cte_2)) as foo; -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: CTE cte_2 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) cte_1 -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_2 for subquery SELECT key, value, other_value FROM cte_inline.test_table -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_3 for subquery SELECT key, value, other_value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) cte_2 -DEBUG: Creating router plan -DEBUG: generating subplan XXX_4 for subquery (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb) EXCEPT SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) UNION SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) foo -DEBUG: Creating router plan - count ---------------------------------------------------------------------- - 101 -(1 row) - --- cte_1 is going to be inlined even inside another set operation -WITH cte_1 AS (SELECT * FROM test_table), - cte_2 AS (SELECT * FROM test_table ORDER BY 1 DESC LIMIT 3) -(SELECT *, (SELECT 1) FROM cte_1 EXCEPT SELECT *, 1 FROM test_table) -UNION -(SELECT *, 1 FROM cte_2) -ORDER BY 1,2; -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: CTE cte_2 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 3 -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table ORDER BY key DESC LIMIT 3 -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_2 for subquery SELECT key, value, other_value, (SELECT 1) FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) cte_1 -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_3 for subquery SELECT key, value, other_value, 1 FROM cte_inline.test_table -DEBUG: Plan XXX query after replacing subqueries and CTEs: (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value, intermediate_result."?column?" FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb, "?column?" integer) EXCEPT SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value, intermediate_result."?column?" FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb, "?column?" integer)) UNION SELECT cte_2.key, cte_2.value, cte_2.other_value, 1 FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_2 ORDER BY 1, 2 -DEBUG: Creating router plan - key | value | other_value | ?column? ---------------------------------------------------------------------- - 9 | test19 | {"f1": 19, "f2": 342, "f3": "test19"} | 1 - 9 | test29 | {"f1": 29, "f2": 522, "f3": "test29"} | 1 - 9 | test9 | {"f1": 9, "f2": 162, "f3": "test9"} | 1 -(3 rows) - --- cte_1 is safe to inline, even if because after inlining --- it'd be in a query tree where there is a query that is --- not supported by Citus unless recursively planned --- cte_2 is on another queryTree, should be fine -WITH cte_1 AS (SELECT * FROM test_table), - cte_2 AS (SELECT * FROM test_table) -(SELECT *, (SELECT key FROM cte_1) FROM test_table) -UNION -(SELECT *, 1 FROM cte_2); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: CTE cte_2 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT key, value, other_value FROM cte_inline.test_table -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_2 for CTE cte_2: SELECT key, value, other_value FROM cte_inline.test_table -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_3 for subquery SELECT key, value, other_value, (SELECT cte_1.key FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1) AS key FROM cte_inline.test_table -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value, intermediate_result.key_1 AS key FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb, key_1 integer) UNION SELECT cte_2.key, cte_2.value, cte_2.other_value, 1 FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_2 -DEBUG: Creating router plan -ERROR: more than one row returned by a subquery used as an expression -CONTEXT: while executing command on localhost:xxxxx --- after inlining CTEs, the query becomes --- subquery pushdown with set operations -WITH cte_1 AS (SELECT * FROM test_table), - cte_2 AS (SELECT * FROM test_table) -SELECT max(key) FROM -( - SELECT * FROM cte_1 - UNION - SELECT * FROM cte_2 -) as bar; -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: CTE cte_2 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries - max ---------------------------------------------------------------------- - 9 -(1 row) - --- cte LEFT JOIN subquery should only work --- when CTE is inlined, as Citus currently --- doesn't know how to handle intermediate --- results in the outer parts of outer --- queries -WITH cte AS (SELECT * FROM test_table) -SELECT - count(*) -FROM - cte LEFT JOIN test_table USING (key); -DEBUG: CTE cte is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries - count ---------------------------------------------------------------------- - 1021 -(1 row) - --- the CTEs are very simple, so postgres --- can pull-up the subqueries after inlining --- the CTEs, and the query that we send to workers --- becomes a join between two tables -WITH cte_1 AS (SELECT key FROM test_table), - cte_2 AS (SELECT key FROM test_table) -SELECT - count(*) -FROM - cte_1 JOIN cte_2 USING (key); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: CTE cte_2 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: join prunable for intervals [-2147483648,-1073741825] and [-1073741824,-1] -DEBUG: join prunable for intervals [-2147483648,-1073741825] and [0,1073741823] -DEBUG: join prunable for intervals [-2147483648,-1073741825] and [1073741824,2147483647] -DEBUG: join prunable for intervals [-1073741824,-1] and [-2147483648,-1073741825] -DEBUG: join prunable for intervals [-1073741824,-1] and [0,1073741823] -DEBUG: join prunable for intervals [-1073741824,-1] and [1073741824,2147483647] -DEBUG: join prunable for intervals [0,1073741823] and [-2147483648,-1073741825] -DEBUG: join prunable for intervals [0,1073741823] and [-1073741824,-1] -DEBUG: join prunable for intervals [0,1073741823] and [1073741824,2147483647] -DEBUG: join prunable for intervals [1073741824,2147483647] and [-2147483648,-1073741825] -DEBUG: join prunable for intervals [1073741824,2147483647] and [-1073741824,-1] -DEBUG: join prunable for intervals [1073741824,2147483647] and [0,1073741823] - count ---------------------------------------------------------------------- - 1021 -(1 row) - --- the following query is kind of interesting --- During INSERT .. SELECT via coordinator, --- Citus moves the CTEs into SELECT part, and plans/execute --- the SELECT separately. Thus, fist_table_cte can be inlined --- by Citus -- but not by Postgres -WITH fist_table_cte AS - (SELECT * FROM test_table) -INSERT INTO test_table - (key, value) - SELECT - key, value - FROM - fist_table_cte; -DEBUG: distributed INSERT ... SELECT can only select from distributed tables -DEBUG: CTE fist_table_cte is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 0 with name 'key' -DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960000 AS citus_table_alias (key, value) SELECT key, value FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1960000_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer, value text) -DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960001 AS citus_table_alias (key, value) SELECT key, value FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1960001_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer, value text) -DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960002 AS citus_table_alias (key, value) SELECT key, value FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1960002_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer, value text) -DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960003 AS citus_table_alias (key, value) SELECT key, value FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1960003_to_3}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer, value text) --- the following INSERT..SELECT is even more interesting --- the CTE becomes pushdownable -INSERT INTO test_table -WITH fist_table_cte AS - (SELECT * FROM test_table) - SELECT - key, value - FROM - fist_table_cte; -DEBUG: CTE fist_table_cte is going to be inlined via distributed planning -DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960000 AS citus_table_alias (key, value) SELECT key, value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table_1960000 test_table) fist_table_cte WHERE (key IS NOT NULL) -DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960001 AS citus_table_alias (key, value) SELECT key, value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table_1960001 test_table) fist_table_cte WHERE (key IS NOT NULL) -DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960002 AS citus_table_alias (key, value) SELECT key, value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table_1960002 test_table) fist_table_cte WHERE (key IS NOT NULL) -DEBUG: distributed statement: INSERT INTO cte_inline.test_table_1960003 AS citus_table_alias (key, value) SELECT key, value FROM (SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table_1960003 test_table) fist_table_cte WHERE (key IS NOT NULL) --- update/delete/modifying ctes --- we don't support any cte inlining in modifications --- queries and modifying CTEs -WITH cte_1 AS (SELECT * FROM test_table) - DELETE FROM test_table WHERE key NOT IN (SELECT key FROM cte_1); -DEBUG: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns -DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT key, value, other_value FROM cte_inline.test_table -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM cte_inline.test_table WHERE (NOT (key OPERATOR(pg_catalog.=) ANY (SELECT cte_1.key FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1))) -DEBUG: Creating router plan --- NOT MATERIALIZED should not CTEs that are used in a modifying query, because --- we de still don't support it -WITH cte_1 AS NOT MATERIALIZED (SELECT * FROM test_table) - DELETE FROM test_table WHERE key NOT IN (SELECT key FROM cte_1); -DEBUG: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns -DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT key, value, other_value FROM cte_inline.test_table -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM cte_inline.test_table WHERE (NOT (key OPERATOR(pg_catalog.=) ANY (SELECT cte_1.key FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1))) -DEBUG: Creating router plan --- we don't inline CTEs if they are modifying CTEs -WITH cte_1 AS (DELETE FROM test_table WHERE key % 3 = 1 RETURNING key) -SELECT * FROM cte_1 ORDER BY 1 DESC LIMIT 3; -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for CTE cte_1: DELETE FROM cte_inline.test_table WHERE ((key OPERATOR(pg_catalog.%) 3) OPERATOR(pg_catalog.=) 1) RETURNING key -DEBUG: Creating router plan -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT key FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) cte_1 ORDER BY key DESC LIMIT 3 -DEBUG: Creating router plan - key ---------------------------------------------------------------------- - 7 - 7 - 7 -(3 rows) - --- NOT MATERIALIZED should not affect modifying CTEs -WITH cte_1 AS NOT MATERIALIZED (DELETE FROM test_table WHERE key % 3 = 0 RETURNING key) -SELECT count(*) FROM cte_1; -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for CTE cte_1: DELETE FROM cte_inline.test_table WHERE ((key OPERATOR(pg_catalog.%) 3) OPERATOR(pg_catalog.=) 0) RETURNING key -DEBUG: Creating router plan -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) cte_1 -DEBUG: Creating router plan - count ---------------------------------------------------------------------- - 164 -(1 row) - --- cte with column aliases -SELECT * FROM test_table, -(WITH cte_1 (x,y) AS (SELECT * FROM test_table), - cte_2 (z,y) AS (SELECT value, other_value, key FROM test_table), - cte_3 (t,m) AS (SELECT z, y, key as cte_2_key FROM cte_2) - SELECT * FROM cte_2, cte_3) as bar -ORDER BY value, other_value, z, y, t, m, cte_2_key -LIMIT 5; -DEBUG: CTE cte_3 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for CTE cte_2: SELECT value, other_value, key FROM cte_inline.test_table -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT test_table.key, test_table.value, test_table.other_value, bar.z, bar.y, bar.key, bar.t, bar.m, bar.cte_2_key FROM cte_inline.test_table, (SELECT cte_2.z, cte_2.y, cte_2.key, cte_3.t, cte_3.m, cte_3.cte_2_key FROM (SELECT intermediate_result.value AS z, intermediate_result.other_value AS y, intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text, other_value jsonb, key integer)) cte_2, (SELECT cte_2_1.z AS t, cte_2_1.y AS m, cte_2_1.key AS cte_2_key FROM (SELECT intermediate_result.value AS z, intermediate_result.other_value AS y, intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text, other_value jsonb, key integer)) cte_2_1) cte_3) bar ORDER BY test_table.value, test_table.other_value, bar.z, bar.y, bar.t, bar.m, bar.cte_2_key LIMIT 5 -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 5 - key | value | other_value | z | y | key | t | m | cte_2_key ---------------------------------------------------------------------- - 2 | test12 | {"f1": 12, "f2": 216, "f3": "test12"} | test12 | {"f1": 12, "f2": 216, "f3": "test12"} | 2 | test12 | {"f1": 12, "f2": 216, "f3": "test12"} | 2 - 2 | test12 | {"f1": 12, "f2": 216, "f3": "test12"} | test12 | {"f1": 12, "f2": 216, "f3": "test12"} | 2 | test12 | | 2 - 2 | test12 | {"f1": 12, "f2": 216, "f3": "test12"} | test12 | {"f1": 12, "f2": 216, "f3": "test12"} | 2 | test12 | | 2 - 2 | test12 | {"f1": 12, "f2": 216, "f3": "test12"} | test12 | {"f1": 12, "f2": 216, "f3": "test12"} | 2 | test12 | | 2 - 2 | test12 | {"f1": 12, "f2": 216, "f3": "test12"} | test12 | {"f1": 12, "f2": 216, "f3": "test12"} | 2 | test15 | {"f1": 15, "f2": 270, "f3": "test15"} | 5 -(5 rows) - --- cte used in HAVING subquery just works fine --- even if it is inlined -WITH cte_1 AS (SELECT max(key) as max FROM test_table) -SELECT - key, count(*) -FROM - test_table -GROUP BY - key -HAVING - (count(*) > (SELECT max FROM cte_1)) -ORDER BY 2 DESC, 1 DESC -LIMIT 5; -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for subquery SELECT max(key) AS max FROM cte_inline.test_table -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT key, count(*) AS count FROM cte_inline.test_table GROUP BY key HAVING (count(*) OPERATOR(pg_catalog.>) (SELECT cte_1.max FROM (SELECT intermediate_result.max FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(max integer)) cte_1)) ORDER BY (count(*)) DESC, key DESC LIMIT 5 -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 5 - key | count ---------------------------------------------------------------------- - 8 | 40 - 5 | 40 - 2 | 40 -(3 rows) - --- cte used in ORDER BY just works fine --- even if it is inlined -WITH cte_1 AS (SELECT max(key) as max FROM test_table) -SELECT - key -FROM - test_table JOIN cte_1 ON (key = max) -ORDER BY - cte_1.max -LIMIT 3; -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for subquery SELECT max(key) AS max FROM cte_inline.test_table -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT test_table.key FROM (cte_inline.test_table JOIN (SELECT intermediate_result.max FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(max integer)) cte_1 ON ((test_table.key OPERATOR(pg_catalog.=) cte_1.max))) ORDER BY cte_1.max LIMIT 3 -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 3 - key ---------------------------------------------------------------------- - 8 - 8 - 8 -(3 rows) - -PREPARE inlined_cte_without_params AS - WITH cte_1 AS (SELECT count(*) FROM test_table GROUP BY key) - SELECT * FROM cte_1 ORDER BY 1 DESC LIMIT 3; -PREPARE non_inlined_cte_without_params AS - WITH cte_1 AS (SELECT * FROM test_table) - SELECT - * - FROM - test_table LEFT JOIN cte_1 USING (value) ORDER BY 1 DESC, 2 DESC, 3 DESC LIMIT 3; -PREPARE inlined_cte_has_parameter_on_non_dist_key(text) AS - WITH cte_1 AS (SELECT count(*) FROM test_table WHERE value = $1 GROUP BY key) - SELECT * FROM cte_1 ORDER BY 1 DESC LIMIT 3; -PREPARE inlined_cte_has_parameter_on_dist_key(int) AS - WITH cte_1 AS (SELECT count(*) FROM test_table WHERE key > $1 GROUP BY key) - SELECT * FROM cte_1 ORDER BY 1 DESC LIMIT 3; -PREPARE non_inlined_cte_has_parameter_on_dist_key(int) AS - WITH cte_1 AS (SELECT * FROM test_table where key > $1) - SELECT - * - FROM - test_table LEFT JOIN cte_1 USING (value) ORDER BY 1 DESC, 2 DESC, 3 DESC LIMIT 3; -PREPARE retry_planning(int) AS - WITH cte_1 AS (SELECT * FROM test_table WHERE key > $1) - SELECT json_object_agg(DISTINCT key, value) FROM cte_1 ORDER BY max(key), min(value) DESC LIMIT 3; -EXECUTE inlined_cte_without_params; -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 3 - count ---------------------------------------------------------------------- - 40 - 40 - 40 -(3 rows) - -EXECUTE inlined_cte_without_params; - count ---------------------------------------------------------------------- - 40 - 40 - 40 -(3 rows) - -EXECUTE inlined_cte_without_params; - count ---------------------------------------------------------------------- - 40 - 40 - 40 -(3 rows) - -EXECUTE inlined_cte_without_params; - count ---------------------------------------------------------------------- - 40 - 40 - 40 -(3 rows) - -EXECUTE inlined_cte_without_params; - count ---------------------------------------------------------------------- - 40 - 40 - 40 -(3 rows) - -EXECUTE inlined_cte_without_params; - count ---------------------------------------------------------------------- - 40 - 40 - 40 -(3 rows) - -EXECUTE non_inlined_cte_without_params; -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT test_table.value, test_table.key, test_table.other_value, cte_1.key, cte_1.other_value FROM (cte_inline.test_table LEFT JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1 USING (value)) ORDER BY test_table.value DESC, test_table.key DESC, test_table.other_value DESC LIMIT 3 -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 3 - value | key | other_value | key | other_value ---------------------------------------------------------------------- - test98 | 8 | | 8 | - test98 | 8 | | 8 | - test98 | 8 | | 8 | -(3 rows) - -EXECUTE non_inlined_cte_without_params; - value | key | other_value | key | other_value ---------------------------------------------------------------------- - test98 | 8 | | 8 | - test98 | 8 | | 8 | - test98 | 8 | | 8 | -(3 rows) - -EXECUTE non_inlined_cte_without_params; - value | key | other_value | key | other_value ---------------------------------------------------------------------- - test98 | 8 | | 8 | - test98 | 8 | | 8 | - test98 | 8 | | 8 | -(3 rows) - -EXECUTE non_inlined_cte_without_params; - value | key | other_value | key | other_value ---------------------------------------------------------------------- - test98 | 8 | | 8 | - test98 | 8 | | 8 | - test98 | 8 | | 8 | -(3 rows) - -EXECUTE non_inlined_cte_without_params; - value | key | other_value | key | other_value ---------------------------------------------------------------------- - test98 | 8 | | 8 | - test98 | 8 | | 8 | - test98 | 8 | | 8 | -(3 rows) - -EXECUTE non_inlined_cte_without_params; - value | key | other_value | key | other_value ---------------------------------------------------------------------- - test98 | 8 | | 8 | - test98 | 8 | | 8 | - test98 | 8 | | 8 | -(3 rows) - -EXECUTE inlined_cte_has_parameter_on_non_dist_key('test1'); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 3 - count ---------------------------------------------------------------------- -(0 rows) - -EXECUTE inlined_cte_has_parameter_on_non_dist_key('test2'); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 3 - count ---------------------------------------------------------------------- - 4 -(1 row) - -EXECUTE inlined_cte_has_parameter_on_non_dist_key('test3'); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 3 - count ---------------------------------------------------------------------- -(0 rows) - -EXECUTE inlined_cte_has_parameter_on_non_dist_key('test4'); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 3 - count ---------------------------------------------------------------------- -(0 rows) - -EXECUTE inlined_cte_has_parameter_on_non_dist_key('test5'); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 3 - count ---------------------------------------------------------------------- - 4 -(1 row) - -EXECUTE inlined_cte_has_parameter_on_non_dist_key('test6'); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 3 - count ---------------------------------------------------------------------- -(0 rows) - -EXECUTE inlined_cte_has_parameter_on_dist_key(1); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 3 - count ---------------------------------------------------------------------- - 40 - 40 - 40 -(3 rows) - -EXECUTE inlined_cte_has_parameter_on_dist_key(2); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 3 - count ---------------------------------------------------------------------- - 40 - 40 -(2 rows) - -EXECUTE inlined_cte_has_parameter_on_dist_key(3); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 3 - count ---------------------------------------------------------------------- - 40 - 40 -(2 rows) - -EXECUTE inlined_cte_has_parameter_on_dist_key(4); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 3 - count ---------------------------------------------------------------------- - 40 - 40 -(2 rows) - -EXECUTE inlined_cte_has_parameter_on_dist_key(5); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 3 - count ---------------------------------------------------------------------- - 40 -(1 row) - -EXECUTE inlined_cte_has_parameter_on_dist_key(6); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 3 - count ---------------------------------------------------------------------- - 40 -(1 row) - -EXECUTE non_inlined_cte_has_parameter_on_dist_key(1); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table WHERE (key OPERATOR(pg_catalog.>) 1) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT test_table.value, test_table.key, test_table.other_value, cte_1.key, cte_1.other_value FROM (cte_inline.test_table LEFT JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1 USING (value)) ORDER BY test_table.value DESC, test_table.key DESC, test_table.other_value DESC LIMIT 3 -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 3 - value | key | other_value | key | other_value ---------------------------------------------------------------------- - test98 | 8 | | 8 | - test98 | 8 | | 8 | - test98 | 8 | | 8 | -(3 rows) - -EXECUTE non_inlined_cte_has_parameter_on_dist_key(2); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table WHERE (key OPERATOR(pg_catalog.>) 2) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT test_table.value, test_table.key, test_table.other_value, cte_1.key, cte_1.other_value FROM (cte_inline.test_table LEFT JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1 USING (value)) ORDER BY test_table.value DESC, test_table.key DESC, test_table.other_value DESC LIMIT 3 -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 3 - value | key | other_value | key | other_value ---------------------------------------------------------------------- - test98 | 8 | | 8 | - test98 | 8 | | 8 | - test98 | 8 | | 8 | -(3 rows) - -EXECUTE non_inlined_cte_has_parameter_on_dist_key(3); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table WHERE (key OPERATOR(pg_catalog.>) 3) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT test_table.value, test_table.key, test_table.other_value, cte_1.key, cte_1.other_value FROM (cte_inline.test_table LEFT JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1 USING (value)) ORDER BY test_table.value DESC, test_table.key DESC, test_table.other_value DESC LIMIT 3 -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 3 - value | key | other_value | key | other_value ---------------------------------------------------------------------- - test98 | 8 | | 8 | - test98 | 8 | | 8 | - test98 | 8 | | 8 | -(3 rows) - -EXECUTE non_inlined_cte_has_parameter_on_dist_key(4); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table WHERE (key OPERATOR(pg_catalog.>) 4) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT test_table.value, test_table.key, test_table.other_value, cte_1.key, cte_1.other_value FROM (cte_inline.test_table LEFT JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1 USING (value)) ORDER BY test_table.value DESC, test_table.key DESC, test_table.other_value DESC LIMIT 3 -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 3 - value | key | other_value | key | other_value ---------------------------------------------------------------------- - test98 | 8 | | 8 | - test98 | 8 | | 8 | - test98 | 8 | | 8 | -(3 rows) - -EXECUTE non_inlined_cte_has_parameter_on_dist_key(5); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table WHERE (key OPERATOR(pg_catalog.>) 5) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT test_table.value, test_table.key, test_table.other_value, cte_1.key, cte_1.other_value FROM (cte_inline.test_table LEFT JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1 USING (value)) ORDER BY test_table.value DESC, test_table.key DESC, test_table.other_value DESC LIMIT 3 -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 3 - value | key | other_value | key | other_value ---------------------------------------------------------------------- - test98 | 8 | | 8 | - test98 | 8 | | 8 | - test98 | 8 | | 8 | -(3 rows) - -EXECUTE non_inlined_cte_has_parameter_on_dist_key(6); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table WHERE (key OPERATOR(pg_catalog.>) 6) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT test_table.value, test_table.key, test_table.other_value, cte_1.key, cte_1.other_value FROM (cte_inline.test_table LEFT JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_1 USING (value)) ORDER BY test_table.value DESC, test_table.key DESC, test_table.other_value DESC LIMIT 3 -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 3 - value | key | other_value | key | other_value ---------------------------------------------------------------------- - test98 | 8 | | 8 | - test98 | 8 | | 8 | - test98 | 8 | | 8 | -(3 rows) - -EXECUTE retry_planning(1); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries - json_object_agg ---------------------------------------------------------------------- - { "2" : "test12", "2" : "test2", "2" : "test22", "2" : "test32", "2" : "test42", "2" : "test52", "2" : "test62", "2" : "test72", "2" : "test82", "2" : "test92", "5" : "test15", "5" : "test25", "5" : "test35", "5" : "test45", "5" : "test5", "5" : "test55", "5" : "test65", "5" : "test75", "5" : "test85", "5" : "test95", "8" : "test18", "8" : "test28", "8" : "test38", "8" : "test48", "8" : "test58", "8" : "test68", "8" : "test78", "8" : "test8", "8" : "test88", "8" : "test98" } -(1 row) - -EXECUTE retry_planning(2); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries - json_object_agg ---------------------------------------------------------------------- - { "5" : "test15", "5" : "test25", "5" : "test35", "5" : "test45", "5" : "test5", "5" : "test55", "5" : "test65", "5" : "test75", "5" : "test85", "5" : "test95", "8" : "test18", "8" : "test28", "8" : "test38", "8" : "test48", "8" : "test58", "8" : "test68", "8" : "test78", "8" : "test8", "8" : "test88", "8" : "test98" } -(1 row) - -EXECUTE retry_planning(3); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries - json_object_agg ---------------------------------------------------------------------- - { "5" : "test15", "5" : "test25", "5" : "test35", "5" : "test45", "5" : "test5", "5" : "test55", "5" : "test65", "5" : "test75", "5" : "test85", "5" : "test95", "8" : "test18", "8" : "test28", "8" : "test38", "8" : "test48", "8" : "test58", "8" : "test68", "8" : "test78", "8" : "test8", "8" : "test88", "8" : "test98" } -(1 row) - -EXECUTE retry_planning(4); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries - json_object_agg ---------------------------------------------------------------------- - { "5" : "test15", "5" : "test25", "5" : "test35", "5" : "test45", "5" : "test5", "5" : "test55", "5" : "test65", "5" : "test75", "5" : "test85", "5" : "test95", "8" : "test18", "8" : "test28", "8" : "test38", "8" : "test48", "8" : "test58", "8" : "test68", "8" : "test78", "8" : "test8", "8" : "test88", "8" : "test98" } -(1 row) - -EXECUTE retry_planning(5); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries - json_object_agg ---------------------------------------------------------------------- - { "8" : "test18", "8" : "test28", "8" : "test38", "8" : "test48", "8" : "test58", "8" : "test68", "8" : "test78", "8" : "test8", "8" : "test88", "8" : "test98" } -(1 row) - -EXECUTE retry_planning(6); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries - json_object_agg ---------------------------------------------------------------------- - { "8" : "test18", "8" : "test28", "8" : "test38", "8" : "test48", "8" : "test58", "8" : "test68", "8" : "test78", "8" : "test8", "8" : "test88", "8" : "test98" } -(1 row) - -WITH b AS (SELECT * FROM test_table) -SELECT count(*) FROM (SELECT key as x FROM test_table OFFSET 0) as ref LEFT JOIN b ON (ref.x = b.key); -DEBUG: CTE b is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for subquery SELECT key AS x FROM cte_inline.test_table OFFSET 0 -DEBUG: recursively planning right side of the left join since the outer side is a recurring rel -DEBUG: recursively planning the distributed subquery since it is part of a distributed join node that is outer joined with a recurring rel -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_2 for subquery SELECT key, value, other_value FROM cte_inline.test_table -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.x FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(x integer)) ref LEFT JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) b ON ((ref.x OPERATOR(pg_catalog.=) b.key))) -DEBUG: Creating router plan - count ---------------------------------------------------------------------- - 4800 -(1 row) - --- this becomes a non-colocated subquery join --- because after the CTEs are inlined the joins --- become a non-colocated subquery join -WITH a AS (SELECT * FROM test_table), -b AS (SELECT * FROM test_table) -SELECT count(*) FROM a LEFT JOIN b ON (a.value = b.value); -DEBUG: CTE a is going to be inlined via distributed planning -DEBUG: CTE b is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) a LEFT JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) b ON ((a.value OPERATOR(pg_catalog.=) b.value))) -DEBUG: Router planner cannot handle multi-shard select queries - count ---------------------------------------------------------------------- - 480 -(1 row) - -WITH a AS (SELECT * FROM test_table OFFSET 0), -b AS (SELECT * FROM test_table) -SELECT min(a.key) FROM a LEFT JOIN b ON (a.value = b.value); -DEBUG: CTE a is going to be inlined via distributed planning -DEBUG: CTE b is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table OFFSET 0 -DEBUG: recursively planning right side of the left join since the outer side is a recurring rel -DEBUG: recursively planning the distributed subquery since it is part of a distributed join node that is outer joined with a recurring rel -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_2 for subquery SELECT key, value, other_value FROM cte_inline.test_table -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT min(a.key) AS min FROM ((SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) a LEFT JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) b ON ((a.value OPERATOR(pg_catalog.=) b.value))) -DEBUG: Creating router plan - min ---------------------------------------------------------------------- - 2 -(1 row) - --- after both CTEs are inlined, this becomes non-colocated subquery join -WITH cte_1 AS (SELECT * FROM test_table), -cte_2 AS (SELECT * FROM test_table) -SELECT * FROM cte_1 JOIN cte_2 ON (cte_1.value > cte_2.value) ORDER BY 1,2,3,4,5,6 DESC LIMIT 3;; -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: CTE cte_2 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for subquery SELECT key, value, other_value FROM cte_inline.test_table -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT cte_1.key, cte_1.value, cte_1.other_value, cte_2.key, cte_2.value, cte_2.other_value FROM ((SELECT test_table.key, test_table.value, test_table.other_value FROM cte_inline.test_table) cte_1 JOIN (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.other_value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, other_value jsonb)) cte_2 ON ((cte_1.value OPERATOR(pg_catalog.>) cte_2.value))) ORDER BY cte_1.key, cte_1.value, cte_1.other_value, cte_2.key, cte_2.value, cte_2.other_value DESC LIMIT 3 -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: push down of limit count: 3 - key | value | other_value | key | value | other_value ---------------------------------------------------------------------- - 2 | test2 | {"f1": 2, "f2": 36, "f3": "test2"} | 2 | test12 | - 2 | test2 | {"f1": 2, "f2": 36, "f3": "test2"} | 2 | test12 | - 2 | test2 | {"f1": 2, "f2": 36, "f3": "test2"} | 2 | test12 | -(3 rows) - --- full join is only supported when both sides are --- recursively planned -WITH cte_1 AS (SELECT value FROM test_table WHERE key > 1), - cte_2 AS (SELECT value FROM test_table WHERE key > 3) -SELECT * FROM cte_1 FULL JOIN cte_2 USING (value) ORDER BY 1 DESC LIMIT 3;; -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: CTE cte_2 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for subquery SELECT value FROM cte_inline.test_table WHERE (key OPERATOR(pg_catalog.>) 3) -DEBUG: recursively planning left side of the full join since the other side is a recurring rel -DEBUG: recursively planning the distributed subquery since it is part of a distributed join node that is outer joined with a recurring rel -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_2 for subquery SELECT value FROM cte_inline.test_table WHERE (key OPERATOR(pg_catalog.>) 1) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT value FROM ((SELECT intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(value text)) cte_1 FULL JOIN (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) cte_2 USING (value)) ORDER BY value DESC LIMIT 3 -DEBUG: Creating router plan - value ---------------------------------------------------------------------- - test98 - test98 - test98 -(3 rows) - --- an unsupported agg. for multi-shard queries --- so CTE has to be recursively planned -WITH cte_1 AS (SELECT * FROM test_table WHERE key > 1) -SELECT json_object_agg(DISTINCT key, value) FROM cte_1; -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries - json_object_agg ---------------------------------------------------------------------- - { "2" : "test12", "2" : "test2", "2" : "test22", "2" : "test32", "2" : "test42", "2" : "test52", "2" : "test62", "2" : "test72", "2" : "test82", "2" : "test92", "5" : "test15", "5" : "test25", "5" : "test35", "5" : "test45", "5" : "test5", "5" : "test55", "5" : "test65", "5" : "test75", "5" : "test85", "5" : "test95", "8" : "test18", "8" : "test28", "8" : "test38", "8" : "test48", "8" : "test58", "8" : "test68", "8" : "test78", "8" : "test8", "8" : "test88", "8" : "test98" } -(1 row) - --- both cte_1 and cte_2 are going to be inlined. --- later, cte_2 is recursively planned since it doesn't have --- GROUP BY but aggragate in a subquery. --- this is an important example of being able to recursively plan --- "some" of the CTEs -WITH cte_1 AS (SELECT value FROM test_table WHERE key > 1), - cte_2 AS (SELECT max(value) as value FROM test_table WHERE key > 3) -SELECT count(*) FROM cte_1 JOIN cte_2 USING (value); -DEBUG: CTE cte_1 is going to be inlined via distributed planning -DEBUG: CTE cte_2 is going to be inlined via distributed planning -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for subquery SELECT max(value) AS value FROM cte_inline.test_table WHERE (key OPERATOR(pg_catalog.>) 3) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT test_table.value FROM cte_inline.test_table WHERE (test_table.key OPERATOR(pg_catalog.>) 1)) cte_1 JOIN (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) cte_2 USING (value)) -DEBUG: Router planner cannot handle multi-shard select queries - count ---------------------------------------------------------------------- - 4 -(1 row) - --- prevent DROP CASCADE to give notices -SET client_min_messages TO ERROR; -DROP SCHEMA cte_inline CASCADE; diff --git a/src/test/regress/expected/detect_conn_close.out b/src/test/regress/expected/detect_conn_close.out index 60973de76..41f98ac6e 100644 --- a/src/test/regress/expected/detect_conn_close.out +++ b/src/test/regress/expected/detect_conn_close.out @@ -1,13 +1,6 @@ -- -- PG15+ test as WL_SOCKET_CLOSED exposed for PG15+ -- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif CREATE SCHEMA socket_close; SET search_path TO socket_close; CREATE OR REPLACE FUNCTION kill_all_cached_internal_conns(gpid bigint) diff --git a/src/test/regress/expected/detect_conn_close_0.out b/src/test/regress/expected/detect_conn_close_0.out deleted file mode 100644 index 27e9787c6..000000000 --- a/src/test/regress/expected/detect_conn_close_0.out +++ /dev/null @@ -1,9 +0,0 @@ --- --- PG15+ test as WL_SOCKET_CLOSED exposed for PG15+ --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q diff --git a/src/test/regress/expected/grant_on_schema_propagation.out b/src/test/regress/expected/grant_on_schema_propagation.out index 77447c2dd..fc34ab416 100644 --- a/src/test/regress/expected/grant_on_schema_propagation.out +++ b/src/test/regress/expected/grant_on_schema_propagation.out @@ -1,16 +1,6 @@ -- -- GRANT_ON_SCHEMA_PROPAGATION -- --- this test has different output for PG14 compared to PG15 --- In PG15, public schema is owned by pg_database_owner role --- Relevant PG commit: b073c3ccd06e4cb845e121387a43faa8c68a7b62 -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - t -(1 row) - -- test grants are propagated when the schema is CREATE SCHEMA dist_schema; CREATE TABLE dist_schema.dist_table (id int); diff --git a/src/test/regress/expected/grant_on_schema_propagation_0.out b/src/test/regress/expected/grant_on_schema_propagation_0.out deleted file mode 100644 index 9806a0dbd..000000000 --- a/src/test/regress/expected/grant_on_schema_propagation_0.out +++ /dev/null @@ -1,400 +0,0 @@ --- --- GRANT_ON_SCHEMA_PROPAGATION --- --- this test has different output for PG14 compared to PG15 --- In PG15, public schema is owned by pg_database_owner role --- Relevant PG commit: b073c3ccd06e4cb845e121387a43faa8c68a7b62 -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - f -(1 row) - --- test grants are propagated when the schema is -CREATE SCHEMA dist_schema; -CREATE TABLE dist_schema.dist_table (id int); -CREATE SCHEMA another_dist_schema; -CREATE TABLE another_dist_schema.dist_table (id int); -SET citus.enable_ddl_propagation TO off; -CREATE SCHEMA non_dist_schema; -SET citus.enable_ddl_propagation TO on; --- create roles on all nodes -CREATE USER role_1; -CREATE USER role_2; -CREATE USER role_3; --- do some varying grants -GRANT USAGE, CREATE ON SCHEMA dist_schema TO role_1 WITH GRANT OPTION; -GRANT USAGE ON SCHEMA dist_schema TO role_2; -SET ROLE role_1; -GRANT USAGE ON SCHEMA dist_schema TO role_3 WITH GRANT OPTION; -GRANT CREATE ON SCHEMA dist_schema TO role_3; -GRANT CREATE, USAGE ON SCHEMA dist_schema TO PUBLIC; -RESET ROLE; -GRANT USAGE ON SCHEMA dist_schema TO PUBLIC; -SELECT create_distributed_table('dist_schema.dist_table', 'id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -SELECT create_distributed_table('another_dist_schema.dist_table', 'id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -SELECT nspname, nspacl FROM pg_namespace WHERE nspname = 'dist_schema'; - nspname | nspacl ---------------------------------------------------------------------- - dist_schema | {postgres=UC/postgres,role_1=U*C*/postgres,role_2=U/postgres,role_3=U*C/role_1,=UC/role_1,=U/postgres} -(1 row) - -\c - - - :worker_1_port -SELECT nspname, nspacl FROM pg_namespace WHERE nspname = 'dist_schema'; - nspname | nspacl ---------------------------------------------------------------------- - dist_schema | {postgres=UC/postgres,role_1=U*C*/postgres,role_2=U/postgres,role_3=U*C/role_1,=UC/role_1,=U/postgres} -(1 row) - -\c - - - :master_port --- grant all permissions -GRANT ALL ON SCHEMA dist_schema, another_dist_schema, non_dist_schema TO role_1, role_2, role_3 WITH GRANT OPTION; -SELECT nspname, nspacl FROM pg_namespace WHERE nspname IN ('dist_schema', 'another_dist_schema', 'non_dist_schema') ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - another_dist_schema | {postgres=UC/postgres,role_1=U*C*/postgres,role_2=U*C*/postgres,role_3=U*C*/postgres} - dist_schema | {postgres=UC/postgres,role_1=U*C*/postgres,role_2=U*C*/postgres,role_3=U*C/role_1,=UC/role_1,=U/postgres,role_3=U*C*/postgres} - non_dist_schema | {postgres=UC/postgres,role_1=U*C*/postgres,role_2=U*C*/postgres,role_3=U*C*/postgres} -(3 rows) - -\c - - - :worker_1_port -SELECT nspname, nspacl FROM pg_namespace WHERE nspname IN ('dist_schema', 'another_dist_schema', 'non_dist_schema') ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - another_dist_schema | {postgres=UC/postgres,role_1=U*C*/postgres,role_2=U*C*/postgres,role_3=U*C*/postgres} - dist_schema | {postgres=UC/postgres,role_1=U*C*/postgres,role_2=U*C*/postgres,role_3=U*C/role_1,=UC/role_1,=U/postgres,role_3=U*C*/postgres} -(2 rows) - -\c - - - :master_port --- revoke all permissions -REVOKE ALL ON SCHEMA dist_schema, another_dist_schema, non_dist_schema FROM role_1, role_2, role_3, PUBLIC CASCADE; -SELECT nspname, nspacl FROM pg_namespace WHERE nspname IN ('dist_schema', 'another_dist_schema', 'non_dist_schema') ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - another_dist_schema | {postgres=UC/postgres} - dist_schema | {postgres=UC/postgres} - non_dist_schema | {postgres=UC/postgres} -(3 rows) - -\c - - - :worker_1_port -SELECT nspname, nspacl FROM pg_namespace WHERE nspname IN ('dist_schema', 'another_dist_schema', 'non_dist_schema') ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - another_dist_schema | {postgres=UC/postgres} - dist_schema | {postgres=UC/postgres} -(2 rows) - -\c - - - :master_port --- grant with multiple permissions, roles and schemas -GRANT USAGE, CREATE ON SCHEMA dist_schema, another_dist_schema, non_dist_schema TO role_1, role_2, role_3; -SELECT nspname, nspacl FROM pg_namespace WHERE nspname IN ('dist_schema', 'another_dist_schema', 'non_dist_schema') ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - another_dist_schema | {postgres=UC/postgres,role_1=UC/postgres,role_2=UC/postgres,role_3=UC/postgres} - dist_schema | {postgres=UC/postgres,role_1=UC/postgres,role_2=UC/postgres,role_3=UC/postgres} - non_dist_schema | {postgres=UC/postgres,role_1=UC/postgres,role_2=UC/postgres,role_3=UC/postgres} -(3 rows) - -\c - - - :worker_1_port -SELECT nspname, nspacl FROM pg_namespace WHERE nspname IN ('dist_schema', 'another_dist_schema', 'non_dist_schema') ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - another_dist_schema | {postgres=UC/postgres,role_1=UC/postgres,role_2=UC/postgres,role_3=UC/postgres} - dist_schema | {postgres=UC/postgres,role_1=UC/postgres,role_2=UC/postgres,role_3=UC/postgres} -(2 rows) - -\c - - - :master_port --- revoke with multiple permissions, roles and schemas -REVOKE USAGE, CREATE ON SCHEMA dist_schema, another_dist_schema, non_dist_schema FROM role_1, role_2; -SELECT nspname, nspacl FROM pg_namespace WHERE nspname IN ('dist_schema', 'another_dist_schema', 'non_dist_schema') ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - another_dist_schema | {postgres=UC/postgres,role_3=UC/postgres} - dist_schema | {postgres=UC/postgres,role_3=UC/postgres} - non_dist_schema | {postgres=UC/postgres,role_3=UC/postgres} -(3 rows) - -\c - - - :worker_1_port -SELECT nspname, nspacl FROM pg_namespace WHERE nspname IN ('dist_schema', 'another_dist_schema', 'non_dist_schema') ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - another_dist_schema | {postgres=UC/postgres,role_3=UC/postgres} - dist_schema | {postgres=UC/postgres,role_3=UC/postgres} -(2 rows) - -\c - - - :master_port --- grant with grant option -GRANT USAGE ON SCHEMA dist_schema TO role_1, role_3 WITH GRANT OPTION; -\c - - - :worker_1_port -SELECT nspname, nspacl FROM pg_namespace WHERE nspname IN ('dist_schema', 'another_dist_schema', 'non_dist_schema') ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - another_dist_schema | {postgres=UC/postgres,role_3=UC/postgres} - dist_schema | {postgres=UC/postgres,role_3=U*C/postgres,role_1=U*/postgres} -(2 rows) - -\c - - - :master_port --- revoke grant option for -REVOKE GRANT OPTION FOR USAGE ON SCHEMA dist_schema FROM role_3; -\c - - - :worker_1_port -SELECT nspname, nspacl FROM pg_namespace WHERE nspname IN ('dist_schema', 'another_dist_schema', 'non_dist_schema') ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - another_dist_schema | {postgres=UC/postgres,role_3=UC/postgres} - dist_schema | {postgres=UC/postgres,role_3=UC/postgres,role_1=U*/postgres} -(2 rows) - -\c - - - :master_port --- test current_user -SET citus.enable_alter_role_propagation TO ON; -ALTER ROLE role_1 SUPERUSER; -SET citus.enable_alter_role_propagation TO OFF; -SET ROLE role_1; --- this is only supported on citus enterprise where multiple users can be managed --- The output of the nspname select below will indicate if the create has been granted -GRANT CREATE ON SCHEMA dist_schema TO CURRENT_USER; -\c - - - :worker_1_port -SELECT nspname, nspacl FROM pg_namespace WHERE nspname IN ('dist_schema', 'another_dist_schema', 'non_dist_schema') ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - another_dist_schema | {postgres=UC/postgres,role_3=UC/postgres} - dist_schema | {postgres=UC/postgres,role_3=UC/postgres,role_1=U*C/postgres} -(2 rows) - -\c - - - :master_port -RESET ROLE; -SET citus.enable_alter_role_propagation TO ON; -ALTER ROLE role_1 NOSUPERUSER; -SET citus.enable_alter_role_propagation TO OFF; -DROP TABLE dist_schema.dist_table, another_dist_schema.dist_table; -DROP SCHEMA dist_schema; -DROP SCHEMA another_dist_schema; -DROP SCHEMA non_dist_schema; --- test if the grantors are propagated correctly --- first remove one of the worker nodes -SET citus.shard_replication_factor TO 1; -SELECT master_remove_node('localhost', :worker_2_port); - master_remove_node ---------------------------------------------------------------------- - -(1 row) - --- create a new schema -CREATE SCHEMA grantor_schema; --- give cascading permissions -GRANT USAGE, CREATE ON SCHEMA grantor_schema TO role_1 WITH GRANT OPTION; -GRANT CREATE ON SCHEMA grantor_schema TO PUBLIC; -SET ROLE role_1; -GRANT USAGE ON SCHEMA grantor_schema TO role_2 WITH GRANT OPTION; -GRANT CREATE ON SCHEMA grantor_schema TO role_2; -GRANT USAGE, CREATE ON SCHEMA grantor_schema TO role_3; -GRANT CREATE, USAGE ON SCHEMA grantor_schema TO PUBLIC; -SET ROLE role_2; -GRANT USAGE ON SCHEMA grantor_schema TO role_3; -RESET ROLE; --- distribute the schema -CREATE TABLE grantor_schema.grantor_table (id INT); -SELECT create_distributed_table('grantor_schema.grantor_table', 'id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - --- check if the grantors are propagated correctly -SELECT nspname, nspacl FROM pg_namespace WHERE nspname = 'grantor_schema' ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - grantor_schema | {postgres=UC/postgres,role_1=U*C*/postgres,=C/postgres,role_2=U*C/role_1,role_3=UC/role_1,=UC/role_1,role_3=U/role_2} -(1 row) - -\c - - - :worker_1_port -SELECT nspname, nspacl FROM pg_namespace WHERE nspname = 'grantor_schema' ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - grantor_schema | {postgres=UC/postgres,role_1=U*C*/postgres,=C/postgres,role_2=U*C/role_1,role_3=UC/role_1,=UC/role_1,role_3=U/role_2} -(1 row) - -\c - - - :master_port --- add the previously removed node -SELECT 1 FROM master_add_node('localhost', :worker_2_port); - ?column? ---------------------------------------------------------------------- - 1 -(1 row) - --- check if the grantors are propagated correctly -SELECT nspname, nspacl FROM pg_namespace WHERE nspname = 'grantor_schema' ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - grantor_schema | {postgres=UC/postgres,role_1=U*C*/postgres,=C/postgres,role_2=U*C/role_1,role_3=UC/role_1,=UC/role_1,role_3=U/role_2} -(1 row) - -\c - - - :worker_2_port -SELECT nspname, nspacl FROM pg_namespace WHERE nspname = 'grantor_schema' ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - grantor_schema | {postgres=UC/postgres,role_1=U*C*/postgres,=C/postgres,role_2=U*C/role_1,role_3=UC/role_1,=UC/role_1,role_3=U/role_2} -(1 row) - -\c - - - :master_port --- revoke one of the permissions -REVOKE USAGE ON SCHEMA grantor_schema FROM role_1 CASCADE; --- check if revoke worked correctly -SELECT nspname, nspacl FROM pg_namespace WHERE nspname = 'grantor_schema' ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - grantor_schema | {postgres=UC/postgres,role_1=C*/postgres,=C/postgres,role_2=C/role_1,role_3=C/role_1,=C/role_1} -(1 row) - -\c - - - :worker_1_port -SELECT nspname, nspacl FROM pg_namespace WHERE nspname = 'grantor_schema' ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - grantor_schema | {postgres=UC/postgres,role_1=C*/postgres,=C/postgres,role_2=C/role_1,role_3=C/role_1,=C/role_1} -(1 row) - -\c - - - :master_port --- test if grantor propagates correctly on already distributed schemas -GRANT USAGE ON SCHEMA grantor_schema TO role_1 WITH GRANT OPTION; -SET ROLE role_1; -GRANT USAGE ON SCHEMA grantor_schema TO role_2; -GRANT USAGE ON SCHEMA grantor_schema TO role_3 WITH GRANT OPTION; -SET ROLE role_3; -GRANT USAGE ON SCHEMA grantor_schema TO role_2; -RESET ROLE; --- check the results -SELECT nspname, nspacl FROM pg_namespace WHERE nspname = 'grantor_schema' ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - grantor_schema | {postgres=UC/postgres,role_1=U*C*/postgres,=C/postgres,role_2=UC/role_1,role_3=U*C/role_1,=C/role_1,role_2=U/role_3} -(1 row) - -\c - - - :worker_1_port -SELECT nspname, nspacl FROM pg_namespace WHERE nspname = 'grantor_schema' ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - grantor_schema | {postgres=UC/postgres,role_1=U*C*/postgres,=C/postgres,role_2=UC/role_1,role_3=U*C/role_1,=C/role_1,role_2=U/role_3} -(1 row) - -\c - - - :master_port -DROP TABLE grantor_schema.grantor_table; -DROP SCHEMA grantor_schema CASCADE; --- test distributing the schema with another user -CREATE SCHEMA dist_schema; -GRANT ALL ON SCHEMA dist_schema TO role_1 WITH GRANT OPTION; -SET ROLE role_1; -GRANT ALL ON SCHEMA dist_schema TO role_2 WITH GRANT OPTION; -CREATE TABLE dist_schema.dist_table (id int); -SELECT create_distributed_table('dist_schema.dist_table', 'id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -SELECT nspname, nspacl FROM pg_namespace WHERE nspname = 'dist_schema' ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - dist_schema | {postgres=UC/postgres,role_1=U*C*/postgres,role_2=U*C*/role_1} -(1 row) - -\c - - - :worker_1_port -SELECT nspname, nspacl FROM pg_namespace WHERE nspname = 'dist_schema' ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - dist_schema | {postgres=UC/postgres,role_1=U*C*/postgres,role_2=U*C*/role_1} -(1 row) - -\c - - - :master_port -DROP TABLE dist_schema.dist_table; -DROP SCHEMA dist_schema CASCADE; --- test grants on public schema --- first remove one of the worker nodes -SET citus.shard_replication_factor TO 1; -SELECT master_remove_node('localhost', :worker_2_port); - master_remove_node ---------------------------------------------------------------------- - -(1 row) - --- to avoid different output in PG15 -GRANT CREATE ON SCHEMA public TO public; --- distribute the public schema (it has to be distributed by now but just in case) -CREATE TABLE public_schema_table (id INT); -SELECT create_distributed_table('public_schema_table', 'id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - --- give cascading permissions -GRANT USAGE, CREATE ON SCHEMA PUBLIC TO role_1 WITH GRANT OPTION; -SET ROLE role_1; -GRANT USAGE ON SCHEMA PUBLIC TO PUBLIC; -RESET ROLE; --- check if the grants are propagated correctly -SELECT nspname, nspacl FROM pg_namespace WHERE nspname = 'public' ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - public | {postgres=UC/postgres,=UC/postgres,role_1=U*C*/postgres,=U/role_1} -(1 row) - -\c - - - :worker_1_port -SELECT nspname, nspacl FROM pg_namespace WHERE nspname = 'public' ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - public | {postgres=UC/postgres,=UC/postgres,role_1=U*C*/postgres,=U/role_1} -(1 row) - -\c - - - :master_port --- add the previously removed node -SELECT 1 FROM master_add_node('localhost', :worker_2_port); - ?column? ---------------------------------------------------------------------- - 1 -(1 row) - --- check if the grants are propagated correctly -SELECT nspname, nspacl FROM pg_namespace WHERE nspname = 'public' ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - public | {postgres=UC/postgres,=UC/postgres,role_1=U*C*/postgres,=U/role_1} -(1 row) - -\c - - - :worker_2_port -SELECT nspname, nspacl FROM pg_namespace WHERE nspname = 'public' ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - public | {postgres=UC/postgres,=UC/postgres,role_1=U*C*/postgres,=U/role_1} -(1 row) - -\c - - - :master_port --- revoke those new permissions -REVOKE CREATE, USAGE ON SCHEMA PUBLIC FROM role_1 CASCADE; --- check if the grants are propagated correctly -SELECT nspname, nspacl FROM pg_namespace WHERE nspname = 'public' ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - public | {postgres=UC/postgres,=UC/postgres} -(1 row) - -\c - - - :worker_1_port -SELECT nspname, nspacl FROM pg_namespace WHERE nspname = 'public' ORDER BY nspname; - nspname | nspacl ---------------------------------------------------------------------- - public | {postgres=UC/postgres,=UC/postgres} -(1 row) - -\c - - - :master_port -DROP TABLE public_schema_table; -DROP ROLE role_1, role_2, role_3; diff --git a/src/test/regress/expected/insert_select_repartition.out b/src/test/regress/expected/insert_select_repartition.out index 476aa8640..fbe85914f 100644 --- a/src/test/regress/expected/insert_select_repartition.out +++ b/src/test/regress/expected/insert_select_repartition.out @@ -1,17 +1,6 @@ -- -- INSERT_SELECT_REPARTITION -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - t -(1 row) - -- tests behaviour of INSERT INTO ... SELECT with repartitioning CREATE SCHEMA insert_select_repartition; SET search_path TO 'insert_select_repartition'; diff --git a/src/test/regress/expected/insert_select_repartition_0.out b/src/test/regress/expected/insert_select_repartition_0.out deleted file mode 100644 index 904bd215a..000000000 --- a/src/test/regress/expected/insert_select_repartition_0.out +++ /dev/null @@ -1,1334 +0,0 @@ --- --- INSERT_SELECT_REPARTITION --- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - f -(1 row) - --- tests behaviour of INSERT INTO ... SELECT with repartitioning -CREATE SCHEMA insert_select_repartition; -SET search_path TO 'insert_select_repartition'; -SET citus.next_shard_id TO 4213581; -SET citus.shard_replication_factor TO 1; --- 4 shards, hash distributed. --- Negate distribution column value. -SET citus.shard_count TO 4; -CREATE TABLE source_table(a int); -SELECT create_distributed_table('source_table', 'a'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO source_table SELECT * FROM generate_series(1, 10); -CREATE TABLE target_table(a int); -SELECT create_distributed_table('target_table', 'a'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -SET client_min_messages TO DEBUG2; -INSERT INTO target_table SELECT -a FROM source_table; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: Subquery contains an operator in the same position as the target table's partition column. -HINT: Ensure the target table's partition column has a corresponding simple column reference to a distributed table's partition column in the subquery. -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 0 with name 'a' -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213585 AS citus_table_alias (a) SELECT a FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213583_to_0,repartitioned_results_xxxxx_from_4213584_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213586 AS citus_table_alias (a) SELECT a FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213582_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213587 AS citus_table_alias (a) SELECT a FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213581_to_2,repartitioned_results_xxxxx_from_4213582_to_2,repartitioned_results_xxxxx_from_4213584_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213588 AS citus_table_alias (a) SELECT a FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213581_to_3}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer) -RESET client_min_messages; -SELECT * FROM target_table WHERE a=-1 OR a=-3 OR a=-7 ORDER BY a; - a ---------------------------------------------------------------------- - -7 - -3 - -1 -(3 rows) - -DROP TABLE source_table, target_table; --- --- range partitioning, composite distribution column --- -CREATE TYPE composite_key_type AS (f1 int, f2 text); --- source -CREATE TABLE source_table(f1 int, key composite_key_type, value int, mapped_key composite_key_type); -SELECT create_distributed_table('source_table', 'key', 'range'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -CALL public.create_range_partitioned_shards('source_table', '{"(0,a)","(25,a)"}','{"(24,z)","(49,z)"}'); -INSERT INTO source_table VALUES (0, (0, 'a'), 1, (0, 'a')); -INSERT INTO source_table VALUES (1, (1, 'b'), 2, (26, 'b')); -INSERT INTO source_table VALUES (2, (2, 'c'), 3, (3, 'c')); -INSERT INTO source_table VALUES (3, (4, 'd'), 4, (27, 'd')); -INSERT INTO source_table VALUES (4, (30, 'e'), 5, (30, 'e')); -INSERT INTO source_table VALUES (5, (31, 'f'), 6, (31, 'f')); -INSERT INTO source_table VALUES (6, (32, 'g'), 50, (8, 'g')); --- target -CREATE TABLE target_table(f1 int DEFAULT 0, value int, key composite_key_type PRIMARY KEY); -SELECT create_distributed_table('target_table', 'key', 'range'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -CALL public.create_range_partitioned_shards('target_table', '{"(0,a)","(25,a)"}','{"(24,z)","(49,z)"}'); -SET client_min_messages TO DEBUG2; -INSERT INTO target_table SELECT f1, value, mapped_key FROM source_table; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: The target table's partition column should correspond to a partition column in the subquery. -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 2 with name 'key' -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213591 AS citus_table_alias (f1, value, key) SELECT f1, value, key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_0,repartitioned_results_xxxxx_from_4213590_to_0}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, value integer, key insert_select_repartition.composite_key_type) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213592 AS citus_table_alias (f1, value, key) SELECT f1, value, key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_1,repartitioned_results_xxxxx_from_4213590_to_1}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, value integer, key insert_select_repartition.composite_key_type) -RESET client_min_messages; -SELECT * FROM target_table ORDER BY key; - f1 | value | key ---------------------------------------------------------------------- - 0 | 1 | (0,a) - 2 | 3 | (3,c) - 6 | 50 | (8,g) - 1 | 2 | (26,b) - 3 | 4 | (27,d) - 4 | 5 | (30,e) - 5 | 6 | (31,f) -(7 rows) - -SELECT * FROM target_table WHERE key = (26, 'b')::composite_key_type; - f1 | value | key ---------------------------------------------------------------------- - 1 | 2 | (26,b) -(1 row) - --- with explicit column names -TRUNCATE target_table; -SET client_min_messages TO DEBUG2; -INSERT INTO target_table(value, key) SELECT value, mapped_key FROM source_table; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: The target table's partition column should correspond to a partition column in the subquery. -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 2 with name 'key' -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213591 AS citus_table_alias (f1, value, key) SELECT f1, value, key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_0,repartitioned_results_xxxxx_from_4213590_to_0}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, value integer, key insert_select_repartition.composite_key_type) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213592 AS citus_table_alias (f1, value, key) SELECT f1, value, key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_1,repartitioned_results_xxxxx_from_4213590_to_1}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, value integer, key insert_select_repartition.composite_key_type) -RESET client_min_messages; -SELECT * FROM target_table ORDER BY key; - f1 | value | key ---------------------------------------------------------------------- - 0 | 1 | (0,a) - 0 | 3 | (3,c) - 0 | 50 | (8,g) - 0 | 2 | (26,b) - 0 | 4 | (27,d) - 0 | 5 | (30,e) - 0 | 6 | (31,f) -(7 rows) - --- missing value for a column -TRUNCATE target_table; -SET client_min_messages TO DEBUG2; -INSERT INTO target_table(key) SELECT mapped_key AS key_renamed FROM source_table; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: The target table's partition column should correspond to a partition column in the subquery. -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 1 with name 'key' -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213591 AS citus_table_alias (f1, key) SELECT f1, key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_0,repartitioned_results_xxxxx_from_4213590_to_0}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, key insert_select_repartition.composite_key_type) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213592 AS citus_table_alias (f1, key) SELECT f1, key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_1,repartitioned_results_xxxxx_from_4213590_to_1}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, key insert_select_repartition.composite_key_type) -RESET client_min_messages; -SELECT * FROM target_table ORDER BY key; - f1 | value | key ---------------------------------------------------------------------- - 0 | | (0,a) - 0 | | (3,c) - 0 | | (8,g) - 0 | | (26,b) - 0 | | (27,d) - 0 | | (30,e) - 0 | | (31,f) -(7 rows) - --- ON CONFLICT -SET client_min_messages TO DEBUG2; -INSERT INTO target_table(key) -SELECT mapped_key AS key_renamed FROM source_table -WHERE (mapped_key).f1 % 2 = 1 -ON CONFLICT (key) DO UPDATE SET f1=1; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: The target table's partition column should correspond to a partition column in the subquery. -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 1 with name 'key' -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213591 AS citus_table_alias (f1, key) SELECT f1, key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_0}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, key insert_select_repartition.composite_key_type) ON CONFLICT(key) DO UPDATE SET f1 = 1 -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213592 AS citus_table_alias (f1, key) SELECT f1, key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213589_to_1,repartitioned_results_xxxxx_from_4213590_to_1}'::text[], 'text'::citus_copy_format) intermediate_result(f1 integer, key insert_select_repartition.composite_key_type) ON CONFLICT(key) DO UPDATE SET f1 = 1 -RESET client_min_messages; -SELECT * FROM target_table ORDER BY key; - f1 | value | key ---------------------------------------------------------------------- - 0 | | (0,a) - 1 | | (3,c) - 0 | | (8,g) - 0 | | (26,b) - 1 | | (27,d) - 0 | | (30,e) - 1 | | (31,f) -(7 rows) - --- missing value for distribution column -INSERT INTO target_table(value) SELECT value FROM source_table; -ERROR: the partition column of table insert_select_repartition.target_table should have a value -DROP TABLE source_table, target_table; --- different column types --- verifies that we add necessary casts, otherwise even shard routing won't --- work correctly and we will see 2 values for the same primary key. -CREATE TABLE target_table(col_1 int primary key, col_2 int); -SELECT create_distributed_table('target_table','col_1'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO target_table VALUES (1,2), (2,3), (3,4), (4,5), (5,6); -CREATE TABLE source_table(col_1 numeric, col_2 numeric, col_3 numeric); -SELECT create_distributed_table('source_table','col_1'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO source_table VALUES (1,1,1), (3,3,3), (5,5,5); -SET client_min_messages TO DEBUG2; -INSERT INTO target_table -SELECT - col_1, col_2 -FROM - source_table -ON CONFLICT(col_1) DO UPDATE SET col_2 = EXCLUDED.col_2; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: The data type of the target table's partition column should exactly match the data type of the corresponding simple column reference in the subquery. -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 0 with name 'col_1' -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213593 AS citus_table_alias (col_1, col_2) SELECT col_1, col_2 FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213597_to_0,repartitioned_results_xxxxx_from_4213600_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer) ON CONFLICT(col_1) DO UPDATE SET col_2 = excluded.col_2 -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213594 AS citus_table_alias (col_1, col_2) SELECT col_1, col_2 FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213599_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer) ON CONFLICT(col_1) DO UPDATE SET col_2 = excluded.col_2 -RESET client_min_messages; -SELECT * FROM target_table ORDER BY 1; - col_1 | col_2 ---------------------------------------------------------------------- - 1 | 1 - 2 | 3 - 3 | 3 - 4 | 5 - 5 | 5 -(5 rows) - -DROP TABLE source_table, target_table; --- --- array coercion --- -SET citus.shard_count TO 3; -CREATE TABLE source_table(a int, mapped_key int, c float[]); -SELECT create_distributed_table('source_table', 'a'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO source_table VALUES (1, -1, ARRAY[1.1, 2.2, 3.3]), (2, -2, ARRAY[4.5, 5.8]), - (3, -3, ARRAY[]::float[]), (4, -4, ARRAY[3.3]); -SET citus.shard_count TO 2; -CREATE TABLE target_table(a int, b int[]); -SELECT create_distributed_table('target_table', 'a'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -SET client_min_messages TO DEBUG1; -INSERT INTO target_table SELECT mapped_key, c FROM source_table; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: The target table's partition column should correspond to a partition column in the subquery. -DEBUG: performing repartitioned INSERT ... SELECT -RESET client_min_messages; -SELECT * FROM target_table ORDER BY a; - a | b ---------------------------------------------------------------------- - -4 | {3} - -3 | {} - -2 | {4,6} - -1 | {1,2,3} -(4 rows) - --- --- worker queries can have more columns than necessary. ExpandWorkerTargetEntry() --- might add additional columns to the target list. --- -TRUNCATE target_table; -\set VERBOSITY TERSE --- first verify that the SELECT query below fetches 3 projected columns from workers -SET citus.log_remote_commands TO true; SET client_min_messages TO DEBUG; - CREATE TABLE results AS SELECT max(-a), array_agg(mapped_key) FROM source_table GROUP BY a; -DEBUG: Router planner cannot handle multi-shard select queries -NOTICE: issuing SELECT max((OPERATOR(pg_catalog.-) a)) AS max, array_agg(mapped_key) AS array_agg, a AS worker_column_3 FROM insert_select_repartition.source_table_4213601 source_table WHERE true GROUP BY a -NOTICE: issuing SELECT max((OPERATOR(pg_catalog.-) a)) AS max, array_agg(mapped_key) AS array_agg, a AS worker_column_3 FROM insert_select_repartition.source_table_4213602 source_table WHERE true GROUP BY a -NOTICE: issuing SELECT max((OPERATOR(pg_catalog.-) a)) AS max, array_agg(mapped_key) AS array_agg, a AS worker_column_3 FROM insert_select_repartition.source_table_4213603 source_table WHERE true GROUP BY a -RESET citus.log_remote_commands; RESET client_min_messages; -DROP TABLE results; --- now verify that we don't write the extra columns to the intermediate result files and --- insertion to the target works fine. -SET client_min_messages TO DEBUG1; -INSERT INTO target_table SELECT max(-a), array_agg(mapped_key) FROM source_table GROUP BY a; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DEBUG: performing repartitioned INSERT ... SELECT -RESET client_min_messages; -SELECT * FROM target_table ORDER BY a; - a | b ---------------------------------------------------------------------- - -4 | {-4} - -3 | {-3} - -2 | {-2} - -1 | {-1} -(4 rows) - --- --- repartitioned INSERT/SELECT followed/preceded by other DML in same transaction --- --- case 1. followed by DELETE -TRUNCATE target_table; -BEGIN; -INSERT INTO target_table SELECT mapped_key, c FROM source_table; -SELECT * FROM target_table ORDER BY a; - a | b ---------------------------------------------------------------------- - -4 | {3} - -3 | {} - -2 | {4,6} - -1 | {1,2,3} -(4 rows) - -DELETE FROM target_table; -END; -SELECT * FROM target_table ORDER BY a; - a | b ---------------------------------------------------------------------- -(0 rows) - --- case 2. followed by UPDATE -TRUNCATE target_table; -BEGIN; -INSERT INTO target_table SELECT mapped_key, c FROM source_table; -SELECT * FROM target_table ORDER BY a; - a | b ---------------------------------------------------------------------- - -4 | {3} - -3 | {} - -2 | {4,6} - -1 | {1,2,3} -(4 rows) - -UPDATE target_table SET b=array_append(b, a); -END; -SELECT * FROM target_table ORDER BY a; - a | b ---------------------------------------------------------------------- - -4 | {3,-4} - -3 | {-3} - -2 | {4,6,-2} - -1 | {1,2,3,-1} -(4 rows) - --- case 3. followed by multi-row INSERT -TRUNCATE target_table; -BEGIN; -INSERT INTO target_table SELECT mapped_key, c FROM source_table; -SELECT * FROM target_table ORDER BY a; - a | b ---------------------------------------------------------------------- - -4 | {3} - -3 | {} - -2 | {4,6} - -1 | {1,2,3} -(4 rows) - -INSERT INTO target_table VALUES (-5, ARRAY[10,11]), (-6, ARRAY[11,12]), (-7, ARRAY[999]); -END; -SELECT * FROM target_table ORDER BY a; - a | b ---------------------------------------------------------------------- - -7 | {999} - -6 | {11,12} - -5 | {10,11} - -4 | {3} - -3 | {} - -2 | {4,6} - -1 | {1,2,3} -(7 rows) - --- case 4. followed by distributed INSERT/SELECT -TRUNCATE target_table; -BEGIN; -INSERT INTO target_table SELECT mapped_key, c FROM source_table; -SELECT * FROM target_table ORDER BY a; - a | b ---------------------------------------------------------------------- - -4 | {3} - -3 | {} - -2 | {4,6} - -1 | {1,2,3} -(4 rows) - -INSERT INTO target_table SELECT * FROM target_table; -END; -SELECT * FROM target_table ORDER BY a; - a | b ---------------------------------------------------------------------- - -4 | {3} - -4 | {3} - -3 | {} - -3 | {} - -2 | {4,6} - -2 | {4,6} - -1 | {1,2,3} - -1 | {1,2,3} -(8 rows) - --- case 5. preceded by DELETE -TRUNCATE target_table; -BEGIN; -DELETE FROM target_table; -INSERT INTO target_table SELECT mapped_key, c FROM source_table; -END; -SELECT * FROM target_table ORDER BY a; - a | b ---------------------------------------------------------------------- - -4 | {3} - -3 | {} - -2 | {4,6} - -1 | {1,2,3} -(4 rows) - --- case 6. preceded by UPDATE -TRUNCATE target_table; -BEGIN; -UPDATE target_table SET b=array_append(b, a); -INSERT INTO target_table SELECT mapped_key, c FROM source_table; -END; -SELECT * FROM target_table ORDER BY a; - a | b ---------------------------------------------------------------------- - -4 | {3} - -3 | {} - -2 | {4,6} - -1 | {1,2,3} -(4 rows) - --- case 7. preceded by multi-row INSERT -TRUNCATE target_table; -BEGIN; -INSERT INTO target_table VALUES (-5, ARRAY[10,11]), (-6, ARRAY[11,12]), (-7, ARRAY[999]); -INSERT INTO target_table SELECT mapped_key, c FROM source_table; -END; -SELECT * FROM target_table ORDER BY a; - a | b ---------------------------------------------------------------------- - -7 | {999} - -6 | {11,12} - -5 | {10,11} - -4 | {3} - -3 | {} - -2 | {4,6} - -1 | {1,2,3} -(7 rows) - --- case 8. preceded by distributed INSERT/SELECT -TRUNCATE target_table; -INSERT INTO target_table SELECT mapped_key, c FROM source_table; -BEGIN; -INSERT INTO target_table SELECT * FROM target_table; -INSERT INTO target_table SELECT mapped_key, c FROM source_table; -END; -SELECT * FROM target_table ORDER BY a; - a | b ---------------------------------------------------------------------- - -4 | {3} - -4 | {3} - -4 | {3} - -3 | {} - -3 | {} - -3 | {} - -2 | {4,6} - -2 | {4,6} - -2 | {4,6} - -1 | {1,2,3} - -1 | {1,2,3} - -1 | {1,2,3} -(12 rows) - --- --- repartitioned INSERT/SELECT with RETURNING --- -TRUNCATE target_table; -SET client_min_messages TO DEBUG1; -WITH c AS ( - INSERT INTO target_table - SELECT mapped_key, c FROM source_table - RETURNING *) -SELECT * FROM c ORDER by a; -DEBUG: generating subplan XXX_1 for CTE c: INSERT INTO insert_select_repartition.target_table (a, b) SELECT mapped_key, c FROM insert_select_repartition.source_table RETURNING target_table.a, target_table.b -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT a, b FROM (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer[])) c ORDER BY a -DEBUG: performing repartitioned INSERT ... SELECT - a | b ---------------------------------------------------------------------- - -4 | {3} - -3 | {} - -2 | {4,6} - -1 | {1,2,3} -(4 rows) - -RESET client_min_messages; --- --- in combination with CTEs --- -TRUNCATE target_table; -SET client_min_messages TO DEBUG1; -WITH t AS ( - SELECT mapped_key, a, c FROM source_table - WHERE a > floor(random()) -) -INSERT INTO target_table -SELECT mapped_key, c FROM t NATURAL JOIN source_table; -DEBUG: volatile functions are not allowed in distributed INSERT ... SELECT queries -DEBUG: generating subplan XXX_1 for CTE t: SELECT mapped_key, a, c FROM insert_select_repartition.source_table WHERE ((a)::double precision OPERATOR(pg_catalog.>) floor(random())) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT mapped_key AS a, auto_coerced_by_citus_1 AS b FROM (SELECT t.mapped_key, (t.c)::integer[] AS auto_coerced_by_citus_1 FROM ((SELECT intermediate_result.mapped_key, intermediate_result.a, intermediate_result.c FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(mapped_key integer, a integer, c double precision[])) t JOIN insert_select_repartition.source_table USING (mapped_key, a, c))) citus_insert_select_subquery -DEBUG: performing repartitioned INSERT ... SELECT -RESET client_min_messages; -SELECT * FROM target_table ORDER BY a; - a | b ---------------------------------------------------------------------- - -4 | {3} - -3 | {} - -2 | {4,6} - -1 | {1,2,3} -(4 rows) - -DROP TABLE source_table, target_table; --- --- The case where select query has a GROUP BY ... --- -SET citus.shard_count TO 4; -CREATE TABLE source_table(a int, b int); -SELECT create_distributed_table('source_table', 'a'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -SET citus.shard_count TO 3; -CREATE TABLE target_table(a int, b int); -SELECT create_distributed_table('target_table', 'a'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO source_table SELECT floor(i/4), i*i FROM generate_series(1, 20) i; -SET client_min_messages TO DEBUG1; -INSERT INTO target_table SELECT a, max(b) FROM source_table GROUP BY a; -DEBUG: INSERT target relation and all source relations of the SELECT must be colocated in distributed INSERT ... SELECT -DEBUG: performing repartitioned INSERT ... SELECT -RESET client_min_messages; -SELECT * FROM target_table ORDER BY a; - a | b ---------------------------------------------------------------------- - 0 | 9 - 1 | 49 - 2 | 121 - 3 | 225 - 4 | 361 - 5 | 400 -(6 rows) - --- --- EXPLAIN output should specify repartitioned INSERT/SELECT --- -EXPLAIN INSERT INTO target_table SELECT a, max(b) FROM source_table GROUP BY a; - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) (cost=0.00..0.00 rows=0 width=0) - INSERT/SELECT method: repartition - -> Custom Scan (Citus Adaptive) (cost=0.00..0.00 rows=100000 width=8) - Task Count: 4 - Tasks Shown: One of 4 - -> Task - Node: host=localhost port=xxxxx dbname=regression - -> HashAggregate (cost=43.90..45.90 rows=200 width=8) - Group Key: a - -> Seq Scan on source_table_4213606 source_table (cost=0.00..32.60 rows=2260 width=8) -(10 rows) - --- --- EXPLAIN ANALYZE is currently not supported --- -EXPLAIN ANALYZE INSERT INTO target_table SELECT a, max(b) FROM source_table GROUP BY a; -ERROR: EXPLAIN ANALYZE is currently not supported for INSERT ... SELECT commands with repartitioning --- --- Duplicate names in target list --- -TRUNCATE target_table; -SET client_min_messages TO DEBUG2; -INSERT INTO target_table - SELECT max(b), max(b) FROM source_table GROUP BY a; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 0 with name 'a' -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213610 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213606_to_0,repartitioned_results_xxxxx_from_4213607_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213611 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213607_to_1,repartitioned_results_xxxxx_from_4213609_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213612 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213606_to_2,repartitioned_results_xxxxx_from_4213607_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) -RESET client_min_messages; -SELECT * FROM target_table ORDER BY a; - a | b ---------------------------------------------------------------------- - 9 | 9 - 49 | 49 - 121 | 121 - 225 | 225 - 361 | 361 - 400 | 400 -(6 rows) - --- --- Prepared INSERT/SELECT --- -TRUNCATE target_table; -PREPARE insert_plan(int, int) AS -INSERT INTO target_table - SELECT a, max(b) FROM source_table - WHERE a BETWEEN $1 AND $2 GROUP BY a; -SET client_min_messages TO DEBUG1; -EXECUTE insert_plan(0, 2); -DEBUG: INSERT target relation and all source relations of the SELECT must be colocated in distributed INSERT ... SELECT -DEBUG: performing repartitioned INSERT ... SELECT -EXECUTE insert_plan(0, 2); -DEBUG: INSERT target relation and all source relations of the SELECT must be colocated in distributed INSERT ... SELECT -DEBUG: performing repartitioned INSERT ... SELECT -EXECUTE insert_plan(0, 2); -DEBUG: INSERT target relation and all source relations of the SELECT must be colocated in distributed INSERT ... SELECT -DEBUG: performing repartitioned INSERT ... SELECT -EXECUTE insert_plan(0, 2); -DEBUG: INSERT target relation and all source relations of the SELECT must be colocated in distributed INSERT ... SELECT -DEBUG: performing repartitioned INSERT ... SELECT -EXECUTE insert_plan(0, 2); -DEBUG: INSERT target relation and all source relations of the SELECT must be colocated in distributed INSERT ... SELECT -DEBUG: performing repartitioned INSERT ... SELECT -EXECUTE insert_plan(0, 2); -DEBUG: INSERT target relation and all source relations of the SELECT must be colocated in distributed INSERT ... SELECT -DEBUG: performing repartitioned INSERT ... SELECT -EXECUTE insert_plan(2, 4); -DEBUG: INSERT target relation and all source relations of the SELECT must be colocated in distributed INSERT ... SELECT -DEBUG: performing repartitioned INSERT ... SELECT -EXECUTE insert_plan(2, 4); -DEBUG: INSERT target relation and all source relations of the SELECT must be colocated in distributed INSERT ... SELECT -DEBUG: performing repartitioned INSERT ... SELECT -EXECUTE insert_plan(2, 4); -DEBUG: INSERT target relation and all source relations of the SELECT must be colocated in distributed INSERT ... SELECT -DEBUG: performing repartitioned INSERT ... SELECT -EXECUTE insert_plan(2, 4); -DEBUG: INSERT target relation and all source relations of the SELECT must be colocated in distributed INSERT ... SELECT -DEBUG: performing repartitioned INSERT ... SELECT -EXECUTE insert_plan(2, 4); -DEBUG: INSERT target relation and all source relations of the SELECT must be colocated in distributed INSERT ... SELECT -DEBUG: performing repartitioned INSERT ... SELECT -EXECUTE insert_plan(2, 4); -DEBUG: INSERT target relation and all source relations of the SELECT must be colocated in distributed INSERT ... SELECT -DEBUG: performing repartitioned INSERT ... SELECT -RESET client_min_messages; -SELECT a, count(*), count(distinct b) distinct_values FROM target_table GROUP BY a ORDER BY a; - a | count | distinct_values ---------------------------------------------------------------------- - 0 | 6 | 1 - 1 | 6 | 1 - 2 | 12 | 1 - 3 | 6 | 1 - 4 | 6 | 1 -(5 rows) - -DEALLOCATE insert_plan; --- --- Prepared router INSERT/SELECT. We currently use pull to coordinator when the --- distributed query has a single task. --- -TRUNCATE target_table; -PREPARE insert_plan(int) AS -INSERT INTO target_table - SELECT a, max(b) FROM source_table - WHERE a=$1 GROUP BY a; -SET client_min_messages TO DEBUG1; -EXECUTE insert_plan(0); -DEBUG: INSERT target relation and all source relations of the SELECT must be colocated in distributed INSERT ... SELECT -DEBUG: Collecting INSERT ... SELECT results on coordinator -EXECUTE insert_plan(0); -DEBUG: INSERT target relation and all source relations of the SELECT must be colocated in distributed INSERT ... SELECT -DEBUG: Collecting INSERT ... SELECT results on coordinator -EXECUTE insert_plan(0); -DEBUG: INSERT target relation and all source relations of the SELECT must be colocated in distributed INSERT ... SELECT -DEBUG: Collecting INSERT ... SELECT results on coordinator -EXECUTE insert_plan(0); -DEBUG: INSERT target relation and all source relations of the SELECT must be colocated in distributed INSERT ... SELECT -DEBUG: Collecting INSERT ... SELECT results on coordinator -EXECUTE insert_plan(0); -DEBUG: INSERT target relation and all source relations of the SELECT must be colocated in distributed INSERT ... SELECT -DEBUG: Collecting INSERT ... SELECT results on coordinator -EXECUTE insert_plan(0); -DEBUG: INSERT target relation and all source relations of the SELECT must be colocated in distributed INSERT ... SELECT -DEBUG: Collecting INSERT ... SELECT results on coordinator -EXECUTE insert_plan(0); -DEBUG: INSERT target relation and all source relations of the SELECT must be colocated in distributed INSERT ... SELECT -DEBUG: Collecting INSERT ... SELECT results on coordinator -RESET client_min_messages; -SELECT a, count(*), count(distinct b) distinct_values FROM target_table GROUP BY a ORDER BY a; - a | count | distinct_values ---------------------------------------------------------------------- - 0 | 7 | 1 -(1 row) - -DEALLOCATE insert_plan; --- --- Prepared INSERT/SELECT with no parameters. --- -TRUNCATE target_table; -PREPARE insert_plan AS -INSERT INTO target_table - SELECT a, max(b) FROM source_table - WHERE a BETWEEN 1 AND 2 GROUP BY a; -SELECT public.coordinator_plan($Q$ -EXPLAIN EXECUTE insert_plan; -$Q$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) (cost=0.00..0.00 rows=0 width=0) - INSERT/SELECT method: repartition - -> Custom Scan (Citus Adaptive) (cost=0.00..0.00 rows=100000 width=8) - Task Count: 4 -(4 rows) - -SET client_min_messages TO DEBUG1; -EXECUTE insert_plan; -DEBUG: performing repartitioned INSERT ... SELECT -EXECUTE insert_plan; -DEBUG: performing repartitioned INSERT ... SELECT -EXECUTE insert_plan; -DEBUG: performing repartitioned INSERT ... SELECT -EXECUTE insert_plan; -DEBUG: performing repartitioned INSERT ... SELECT -EXECUTE insert_plan; -DEBUG: performing repartitioned INSERT ... SELECT -EXECUTE insert_plan; -DEBUG: performing repartitioned INSERT ... SELECT -EXECUTE insert_plan; -DEBUG: performing repartitioned INSERT ... SELECT -RESET client_min_messages; -SELECT a, count(*), count(distinct b) distinct_values FROM target_table GROUP BY a ORDER BY a; - a | count | distinct_values ---------------------------------------------------------------------- - 1 | 7 | 1 - 2 | 7 | 1 -(2 rows) - -DEALLOCATE insert_plan; --- --- INSERT/SELECT in CTE --- -TRUNCATE target_table; -SET client_min_messages TO DEBUG2; -SET citus.enable_non_colocated_router_query_pushdown TO ON; -WITH r AS ( - INSERT INTO target_table SELECT * FROM source_table RETURNING * -) -INSERT INTO target_table SELECT source_table.a, max(source_table.b) FROM source_table NATURAL JOIN r GROUP BY source_table.a; -DEBUG: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns -DEBUG: only SELECT, UPDATE, or DELETE common table expressions may be router planned -DEBUG: generating subplan XXX_1 for CTE r: INSERT INTO insert_select_repartition.target_table (a, b) SELECT a, b FROM insert_select_repartition.source_table RETURNING target_table.a, target_table.b -DEBUG: INSERT target relation and all source relations of the SELECT must be colocated in distributed INSERT ... SELECT -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT a, max AS b FROM (SELECT source_table.a, max(source_table.b) AS max FROM (insert_select_repartition.source_table JOIN (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) r USING (a, b)) GROUP BY source_table.a) citus_insert_select_subquery -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 0 with name 'a' -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213610 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213606_to_0,repartitioned_results_xxxxx_from_4213607_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) RETURNING citus_table_alias.a, citus_table_alias.b -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213611 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213607_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) RETURNING citus_table_alias.a, citus_table_alias.b -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213612 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213609_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) RETURNING citus_table_alias.a, citus_table_alias.b -DEBUG: partitioning SELECT query by column index 0 with name 'a' -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213610 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213606_to_0,repartitioned_results_xxxxx_from_4213607_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213611 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213607_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213612 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213609_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) -RESET citus.enable_non_colocated_router_query_pushdown; -RESET client_min_messages; -SELECT * FROM target_table ORDER BY a, b; - a | b ---------------------------------------------------------------------- - 0 | 1 - 0 | 4 - 0 | 9 - 0 | 9 - 1 | 16 - 1 | 25 - 1 | 36 - 1 | 49 - 1 | 49 - 2 | 64 - 2 | 81 - 2 | 100 - 2 | 121 - 2 | 121 - 3 | 144 - 3 | 169 - 3 | 196 - 3 | 225 - 3 | 225 - 4 | 256 - 4 | 289 - 4 | 324 - 4 | 361 - 4 | 361 - 5 | 400 - 5 | 400 -(26 rows) - -DROP TABLE source_table, target_table; --- --- Constraint failure and rollback --- -SET citus.shard_count TO 4; -CREATE TABLE source_table(a int, b int); -SELECT create_distributed_table('source_table', 'a'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO source_table SELECT i, i * i FROM generate_series(1, 10) i; -UPDATE source_table SET b = NULL where b IN (9, 4); -SET citus.shard_replication_factor TO 2; -CREATE TABLE target_table(a int, b int not null); -SELECT create_distributed_table('target_table', 'a', 'range'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -CALL public.create_range_partitioned_shards('target_table', '{0,3,6,9}','{2,5,8,50}'); -INSERT INTO target_table VALUES (11,9), (22,4); -EXPLAIN (costs off) INSERT INTO target_table SELECT * FROM source_table; - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: repartition - -> Custom Scan (Citus Adaptive) - Task Count: 4 - Tasks Shown: One of 4 - -> Task - Node: host=localhost port=xxxxx dbname=regression - -> Seq Scan on source_table_4213613 source_table -(8 rows) - -EXPLAIN (costs off) INSERT INTO target_table SELECT * FROM source_table WHERE b IS NOT NULL; - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: repartition - -> Custom Scan (Citus Adaptive) - Task Count: 4 - Tasks Shown: One of 4 - -> Task - Node: host=localhost port=xxxxx dbname=regression - -> Seq Scan on source_table_4213613 source_table - Filter: (b IS NOT NULL) -(9 rows) - -BEGIN; -SAVEPOINT s1; -INSERT INTO target_table SELECT * FROM source_table; -ERROR: null value in column "b" violates not-null constraint -ROLLBACK TO SAVEPOINT s1; -INSERT INTO target_table SELECT * FROM source_table WHERE b IS NOT NULL; -END; -SELECT * FROM target_table ORDER BY b; - a | b ---------------------------------------------------------------------- - 1 | 1 - 22 | 4 - 11 | 9 - 4 | 16 - 5 | 25 - 6 | 36 - 7 | 49 - 8 | 64 - 9 | 81 - 10 | 100 -(10 rows) - --- verify that values have been replicated to both replicas -SELECT * FROM run_command_on_placements('target_table', 'select count(*) from %s') ORDER BY shardid, nodeport; - nodename | nodeport | shardid | success | result ---------------------------------------------------------------------- - localhost | 57637 | 4213617 | t | 1 - localhost | 57638 | 4213617 | t | 1 - localhost | 57637 | 4213618 | t | 2 - localhost | 57638 | 4213618 | t | 2 - localhost | 57637 | 4213619 | t | 3 - localhost | 57638 | 4213619 | t | 3 - localhost | 57637 | 4213620 | t | 4 - localhost | 57638 | 4213620 | t | 4 -(8 rows) - --- --- Multiple casts in the SELECT query --- -TRUNCATE target_table; -SET client_min_messages TO DEBUG2; -INSERT INTO target_table SELECT 1.12, b::bigint FROM source_table WHERE b IS NOT NULL; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 0 with name 'a' -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213617 AS citus_table_alias (a, b) SELECT a, b FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213613_to_0,repartitioned_results_xxxxx_from_4213614_to_0,repartitioned_results_xxxxx_from_4213615_to_0,repartitioned_results_xxxxx_from_4213616_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer) -RESET client_min_messages; -SELECT * FROM target_table ORDER BY a, b; - a | b ---------------------------------------------------------------------- - 1 | 1 - 1 | 16 - 1 | 25 - 1 | 36 - 1 | 49 - 1 | 64 - 1 | 81 - 1 | 100 -(8 rows) - --- --- ROLLBACK after out of range error --- -TRUNCATE target_table; -BEGIN; -INSERT INTO target_table SELECT a * 10, b FROM source_table WHERE b IS NOT NULL; -ERROR: could not find shard for partition column value -END; -SELECT max(result) FROM run_command_on_placements('target_table', 'select count(*) from %s'); - max ---------------------------------------------------------------------- - 0 -(1 row) - -DROP TABLE source_table, target_table; --- --- Range partitioned target's ranges doesn't cover the whole range --- -SET citus.shard_replication_factor TO 2; -SET citus.shard_count TO 4; -CREATE TABLE source_table(a int, b int); -SELECT create_distributed_table('source_table', 'a'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO source_table SELECT i, i * i FROM generate_series(1, 10) i; -SET citus.shard_replication_factor TO 2; -CREATE TABLE target_table(b int not null, a float); -SELECT create_distributed_table('target_table', 'a', 'range'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -CALL public.create_range_partitioned_shards('target_table', '{0.0,3.5,6.5,9.5}','{2.9,5.9,8.9,50.0}'); -INSERT INTO target_table SELECT b, a+0.6 FROM source_table; -SELECT * FROM target_table ORDER BY a; - b | a ---------------------------------------------------------------------- - 1 | 1.6 - 4 | 2.6 - 9 | 3.6 - 16 | 4.6 - 25 | 5.6 - 36 | 6.6 - 49 | 7.6 - 64 | 8.6 - 81 | 9.6 - 100 | 10.6 -(10 rows) - --- verify that values have been replicated to both replicas, and that each --- replica has received correct number of rows -SELECT * FROM run_command_on_placements('target_table', 'select count(*) from %s') ORDER BY shardid, nodeport; - nodename | nodeport | shardid | success | result ---------------------------------------------------------------------- - localhost | 57637 | 4213625 | t | 2 - localhost | 57638 | 4213625 | t | 2 - localhost | 57637 | 4213626 | t | 3 - localhost | 57638 | 4213626 | t | 3 - localhost | 57637 | 4213627 | t | 3 - localhost | 57638 | 4213627 | t | 3 - localhost | 57637 | 4213628 | t | 2 - localhost | 57638 | 4213628 | t | 2 -(8 rows) - -DROP TABLE source_table, target_table; --- --- Select column names should be unique --- -SET citus.shard_replication_factor TO 1; -SET citus.shard_count TO 4; -CREATE TABLE source_table(a int, b int); -SELECT create_distributed_table('source_table', 'a'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -SET citus.shard_count TO 3; -CREATE TABLE target_table(a int, b int, c int, d int, e int, f int); -SELECT create_distributed_table('target_table', 'a'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO source_table SELECT i, i * i FROM generate_series(1, 10) i; -SET client_min_messages TO DEBUG2; -INSERT INTO target_table SELECT a AS aa, b AS aa, 1 AS aa, 2 AS aa FROM source_table; -DEBUG: INSERT target relation and all source relations of the SELECT must be colocated in distributed INSERT ... SELECT -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 0 with name 'a' -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213633 AS citus_table_alias (a, b, c, d) SELECT a, b, c, d FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213629_to_0,repartitioned_results_xxxxx_from_4213630_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer, c integer, d integer) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213634 AS citus_table_alias (a, b, c, d) SELECT a, b, c, d FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213630_to_1,repartitioned_results_xxxxx_from_4213631_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer, c integer, d integer) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213635 AS citus_table_alias (a, b, c, d) SELECT a, b, c, d FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213632_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(a integer, b integer, c integer, d integer) -RESET client_min_messages; -SELECT count(*) FROM target_table; - count ---------------------------------------------------------------------- - 10 -(1 row) - --- --- Disable repartitioned insert/select --- -TRUNCATE target_table; -SET citus.enable_repartitioned_insert_select TO OFF; -EXPLAIN (costs off) INSERT INTO target_table SELECT a AS aa, b AS aa, 1 AS aa, 2 AS aa FROM source_table; - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> Custom Scan (Citus Adaptive) - Task Count: 4 - Tasks Shown: One of 4 - -> Task - Node: host=localhost port=xxxxx dbname=regression - -> Seq Scan on source_table_4213629 source_table -(8 rows) - -SET client_min_messages TO DEBUG2; -INSERT INTO target_table SELECT a AS aa, b AS aa, 1 AS aa, 2 AS aa FROM source_table; -DEBUG: INSERT target relation and all source relations of the SELECT must be colocated in distributed INSERT ... SELECT -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Collecting INSERT ... SELECT results on coordinator -RESET client_min_messages; -SELECT count(*) FROM target_table; - count ---------------------------------------------------------------------- - 10 -(1 row) - -SET citus.enable_repartitioned_insert_select TO ON; -EXPLAIN (costs off) INSERT INTO target_table SELECT a AS aa, b AS aa, 1 AS aa, 2 AS aa FROM source_table; - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: repartition - -> Custom Scan (Citus Adaptive) - Task Count: 4 - Tasks Shown: One of 4 - -> Task - Node: host=localhost port=xxxxx dbname=regression - -> Seq Scan on source_table_4213629 source_table -(8 rows) - -DROP TABLE source_table, target_table; --- --- Don't use INSERT/SELECT repartition with repartition joins --- -create table test(x int, y int); -select create_distributed_table('test', 'x'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -set citus.enable_repartition_joins to true; -INSERT INTO test SELECT i, i FROM generate_series(1, 10) i; -EXPLAIN (costs off) INSERT INTO test(y, x) SELECT a.x, b.y FROM test a JOIN test b USING (y); - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> Custom Scan (Citus Adaptive) - Task Count: 6 - Tasks Shown: None, not supported for re-partition queries - -> MapMergeJob - Map Task Count: 3 - Merge Task Count: 6 - -> MapMergeJob - Map Task Count: 3 - Merge Task Count: 6 -(11 rows) - -SET client_min_messages TO DEBUG1; -INSERT INTO test(y, x) SELECT a.x, b.y FROM test a JOIN test b USING (y); -DEBUG: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns -DEBUG: Collecting INSERT ... SELECT results on coordinator -RESET client_min_messages; -SELECT count(*) FROM test; - count ---------------------------------------------------------------------- - 20 -(1 row) - -TRUNCATE test; -INSERT INTO test SELECT i, i FROM generate_series(1, 10) i; -EXPLAIN (costs off) INSERT INTO test SELECT a.* FROM test a JOIN test b USING (y); - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> Custom Scan (Citus Adaptive) - Task Count: 6 - Tasks Shown: None, not supported for re-partition queries - -> MapMergeJob - Map Task Count: 3 - Merge Task Count: 6 - -> MapMergeJob - Map Task Count: 3 - Merge Task Count: 6 -(11 rows) - -SET client_min_messages TO DEBUG1; -INSERT INTO test SELECT a.* FROM test a JOIN test b USING (y); -DEBUG: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns -DEBUG: Collecting INSERT ... SELECT results on coordinator -RESET client_min_messages; -SELECT count(*) FROM test; - count ---------------------------------------------------------------------- - 20 -(1 row) - --- --- In the following case we coerce some columns and move uncoerced versions to the --- end of SELECT list. The following case verifies that we rename those columns so --- we don't get "column reference is ambiguous" errors. --- -CREATE TABLE target_table( - c1 int, - c2 int, - c3 timestamp, - a int, - b int, - c int, - c4 int, - c5 int, - c6 int[], - cardinality int, - sum int, - PRIMARY KEY (c1, c2, c3, c4, c5, c6) -); -SET citus.shard_count TO 5; -SELECT create_distributed_table('target_table', 'c1'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -CREATE TABLE source_table( - c1 int, - c2 int, - c3 date, - c4 int, - cardinality int, - sum int -); -SET citus.shard_count TO 4; -SELECT create_distributed_table('source_table', 'c1'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -CREATE OR REPLACE FUNCTION dist_func(a int, b int) RETURNS int[] -AS $$ -BEGIN - RETURN array_fill(a, ARRAY[b]); -END; -$$ -LANGUAGE plpgsql STABLE; -SELECT create_distributed_function('dist_func(int, int)'); -NOTICE: procedure insert_select_repartition.dist_func is already distributed - create_distributed_function ---------------------------------------------------------------------- - -(1 row) - -SET client_min_messages TO DEBUG; -SET citus.enable_unique_job_ids TO off; -INSERT INTO source_table VALUES (1,2, '2020-02-02', 3, 4, 5); -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 1 -INSERT INTO source_table VALUES (1,2, '2020-02-02', 3, 4, 5); -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 1 -INSERT INTO source_table VALUES (3,4, '2020-02-02', 3, 4, 5); -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 3 -INSERT INTO target_table AS enriched(c1, c2, c3, c4, c5, c6, cardinality, sum) -SELECT c1, c2, c3, c4, -1::float AS c5, - dist_func(c1, 4) c6, - sum(cardinality), - sum(sum) -FROM source_table -GROUP BY c1, c2, c3, c4, c6 -ON CONFLICT(c1, c2, c3, c4, c5, c6) -DO UPDATE SET - cardinality = enriched.cardinality + excluded.cardinality, - sum = enriched.sum + excluded.sum; -DEBUG: INSERT target relation and all source relations of the SELECT must be colocated in distributed INSERT ... SELECT -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 0 with name 'c1' -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213639 AS enriched (c1, c2, c3, c4, c5, c6, cardinality, sum) SELECT c1, c2, c3, c4, c5, c6, cardinality, sum FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213644_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(c1 integer, c2 integer, c3 timestamp without time zone, c4 integer, c5 integer, c6 integer[], cardinality integer, sum integer) ON CONFLICT(c1, c2, c3, c4, c5, c6) DO UPDATE SET cardinality = (enriched.cardinality OPERATOR(pg_catalog.+) excluded.cardinality), sum = (enriched.sum OPERATOR(pg_catalog.+) excluded.sum) -DEBUG: distributed statement: INSERT INTO insert_select_repartition.target_table_4213641 AS enriched (c1, c2, c3, c4, c5, c6, cardinality, sum) SELECT c1, c2, c3, c4, c5, c6, cardinality, sum FROM read_intermediate_results('{repartitioned_results_xxxxx_from_4213645_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(c1 integer, c2 integer, c3 timestamp without time zone, c4 integer, c5 integer, c6 integer[], cardinality integer, sum integer) ON CONFLICT(c1, c2, c3, c4, c5, c6) DO UPDATE SET cardinality = (enriched.cardinality OPERATOR(pg_catalog.+) excluded.cardinality), sum = (enriched.sum OPERATOR(pg_catalog.+) excluded.sum) -RESET client_min_messages; -EXPLAIN (COSTS OFF) INSERT INTO target_table AS enriched(c1, c2, c3, c4, c5, c6, cardinality, sum) -SELECT c1, c2, c3, c4, -1::float AS c5, - dist_func(c1, 4) c6, - sum(cardinality), - sum(sum) -FROM source_table -GROUP BY c1, c2, c3, c4, c6 -ON CONFLICT(c1, c2, c3, c4, c5, c6) -DO UPDATE SET - cardinality = enriched.cardinality + excluded.cardinality, - sum = enriched.sum + excluded.sum; - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: repartition - -> Custom Scan (Citus Adaptive) - Task Count: 4 - Tasks Shown: One of 4 - -> Task - Node: host=localhost port=xxxxx dbname=regression - -> HashAggregate - Group Key: c1, c2, c3, c4, insert_select_repartition.dist_func(c1, 4) - -> Seq Scan on source_table_4213644 source_table -(10 rows) - --- verify that we don't report repartitioned insert/select for tables --- with sequences. See https://github.com/citusdata/citus/issues/3936 -create table table_with_sequences (x int, y int, z bigserial); -insert into table_with_sequences values (1,1); -select create_distributed_table('table_with_sequences','x'); -NOTICE: Copying data from local table... -NOTICE: copying the data has completed - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -explain (costs off) insert into table_with_sequences select y, x from table_with_sequences; - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> Custom Scan (Citus Adaptive) - Task Count: 4 - Tasks Shown: One of 4 - -> Task - Node: host=localhost port=xxxxx dbname=regression - -> Seq Scan on table_with_sequences_4213648 table_with_sequences -(8 rows) - --- verify that we don't report repartitioned insert/select for tables --- with user-defined sequences. -CREATE SEQUENCE user_defined_sequence; -create table table_with_user_sequences (x int, y int, z bigint default nextval('user_defined_sequence')); -insert into table_with_user_sequences values (1,1); -select create_distributed_table('table_with_user_sequences','x'); -NOTICE: Copying data from local table... -NOTICE: copying the data has completed - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -explain (costs off) insert into table_with_user_sequences select y, x from table_with_user_sequences; - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> Custom Scan (Citus Adaptive) - Task Count: 4 - Tasks Shown: One of 4 - -> Task - Node: host=localhost port=xxxxx dbname=regression - -> Seq Scan on table_with_user_sequences_4213652 table_with_user_sequences -(8 rows) - -CREATE TABLE dist_table_1(id int); -SELECT create_distributed_table('dist_table_1','id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -CREATE TABLE dist_table_2(id int); -SELECT create_distributed_table('dist_table_2','id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - --- verify that insert select with union can be repartitioned. We cannot push down the query --- since UNION clause has no FROM clause at top level query. -SELECT public.coordinator_plan($$ - EXPLAIN (COSTS FALSE) INSERT INTO dist_table_1(id) SELECT id FROM dist_table_1 UNION SELECT id FROM dist_table_2; -$$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: repartition - -> Custom Scan (Citus Adaptive) - Task Count: 4 -(4 rows) - --- clean-up -SET client_min_messages TO WARNING; -DROP SCHEMA insert_select_repartition CASCADE; diff --git a/src/test/regress/expected/intermediate_result_pruning.out b/src/test/regress/expected/intermediate_result_pruning.out index 5262ebc79..6caeab91b 100644 --- a/src/test/regress/expected/intermediate_result_pruning.out +++ b/src/test/regress/expected/intermediate_result_pruning.out @@ -1,17 +1,6 @@ -- -- INTERMEDIATE_RESULT_PRUNING -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - t -(1 row) - CREATE SCHEMA intermediate_result_pruning; SET search_path TO intermediate_result_pruning; SET citus.log_intermediate_results TO TRUE; diff --git a/src/test/regress/expected/intermediate_result_pruning_0.out b/src/test/regress/expected/intermediate_result_pruning_0.out deleted file mode 100644 index ae1247545..000000000 --- a/src/test/regress/expected/intermediate_result_pruning_0.out +++ /dev/null @@ -1,1077 +0,0 @@ --- --- INTERMEDIATE_RESULT_PRUNING --- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - f -(1 row) - -CREATE SCHEMA intermediate_result_pruning; -SET search_path TO intermediate_result_pruning; -SET citus.log_intermediate_results TO TRUE; -SET citus.shard_count TO 4; -SET citus.next_shard_id TO 1480000; -SET citus.shard_replication_factor = 1; -CREATE TABLE table_1 (key int, value text); -SELECT create_distributed_table('table_1', 'key'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -CREATE TABLE table_2 (key int, value text); -SELECT create_distributed_table('table_2', 'key'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -CREATE TABLE table_3 (key int, value text); -SELECT create_distributed_table('table_3', 'key'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -CREATE TABLE ref_table (key int, value text); -SELECT create_reference_table('ref_table'); - create_reference_table ---------------------------------------------------------------------- - -(1 row) - --- load some data -INSERT INTO table_1 VALUES (1, '1'), (2, '2'), (3, '3'), (4, '4'); -INSERT INTO table_2 VALUES (3, '3'), (4, '4'), (5, '5'), (6, '6'); -INSERT INTO table_3 VALUES (3, '3'), (4, '4'), (5, '5'), (6, '6'); -INSERT INTO ref_table VALUES (1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5'), (6, '6'); --- see which workers are hit for intermediate results -SET client_min_messages TO DEBUG1; --- a very basic case, where the intermediate result --- should go to both workers -WITH some_values_1 AS MATERIALIZED - (SELECT key FROM table_1 WHERE value IN ('3', '4')) -SELECT - count(*) -FROM - some_values_1 JOIN table_2 USING (key); -DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx - count ---------------------------------------------------------------------- - 2 -(1 row) - --- a very basic case, where the intermediate result --- should only go to one worker because the final query is a router --- we use random() to prevent postgres inline the CTE(s) -WITH some_values_1 AS MATERIALIZED - (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')) -SELECT - count(*) -FROM - some_values_1 JOIN table_2 USING (key) WHERE table_2.key = 1; -DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (table_2.key OPERATOR(pg_catalog.=) 1) -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx - count ---------------------------------------------------------------------- - 0 -(1 row) - --- a similar query, but with a reference table now --- given that reference tables are replicated to all nodes --- we have to broadcast to all nodes -WITH some_values_1 AS MATERIALIZED - (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')) -SELECT - count(*) -FROM - some_values_1 JOIN ref_table USING (key); -DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.ref_table USING (key)) -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx - count ---------------------------------------------------------------------- - 2 -(1 row) - --- a similar query as above, but this time use the CTE inside --- another CTE -WITH some_values_1 AS MATERIALIZED - (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), - some_values_2 AS MATERIALIZED - (SELECT key, random() FROM some_values_1) -SELECT - count(*) -FROM - some_values_2 JOIN table_2 USING (key) WHERE table_2.key = 1; -DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) -DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT key, random() AS random FROM (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (table_2.key OPERATOR(pg_catalog.=) 1) -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx - count ---------------------------------------------------------------------- - 0 -(1 row) - --- the second CTE does a join with a distributed table --- and the final query is a router query -WITH some_values_1 AS MATERIALIZED - (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), - some_values_2 AS MATERIALIZED - (SELECT key, random() FROM some_values_1 JOIN table_2 USING (key)) -SELECT - count(*) -FROM - some_values_2 JOIN table_2 USING (key) WHERE table_2.key = 3; -DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) -DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT some_values_1.key, random() AS random FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (table_2.key OPERATOR(pg_catalog.=) 3) -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx - count ---------------------------------------------------------------------- - 1 -(1 row) - --- the first CTE is used both within second CTE and the final query --- the second CTE does a join with a distributed table --- and the final query is a router query -WITH some_values_1 AS MATERIALIZED - (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), - some_values_2 AS MATERIALIZED - (SELECT key, random() FROM some_values_1 JOIN table_2 USING (key)) -SELECT - count(*) -FROM - (some_values_2 JOIN table_2 USING (key)) JOIN some_values_1 USING (key) WHERE table_2.key = 3; -DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) -DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT some_values_1.key, random() AS random FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 JOIN intermediate_result_pruning.table_2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 USING (key)) WHERE (table_2.key OPERATOR(pg_catalog.=) 3) -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx - count ---------------------------------------------------------------------- - 1 -(1 row) - --- the first CTE is used both within second CTE and the final query --- the second CTE does a join with a distributed table but a router query on a worker --- and the final query is another router query on another worker -WITH some_values_1 AS MATERIALIZED - (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), - some_values_2 AS MATERIALIZED - (SELECT key, random() FROM some_values_1 JOIN table_2 USING (key) WHERE table_2.key = 1) -SELECT - count(*) -FROM - (some_values_2 JOIN table_2 USING (key)) JOIN some_values_1 USING (key) WHERE table_2.key = 3; -DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) -DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT some_values_1.key, random() AS random FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (table_2.key OPERATOR(pg_catalog.=) 1) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 JOIN intermediate_result_pruning.table_2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 USING (key)) WHERE (table_2.key OPERATOR(pg_catalog.=) 3) -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx - count ---------------------------------------------------------------------- - 0 -(1 row) - --- the first CTE is used both within second CTE and the final query --- the second CTE does a join with a distributed table but a router query on a worker --- and the final query is a router query on the same worker, so the first result is only --- broadcasted to a single node -WITH some_values_1 AS MATERIALIZED - (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), - some_values_2 AS MATERIALIZED - (SELECT key, random() FROM some_values_1 JOIN table_2 USING (key) WHERE table_2.key = 1) -SELECT - count(*) -FROM - (some_values_2 JOIN table_2 USING (key)) JOIN some_values_1 USING (key) WHERE table_2.key = 1; -DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) -DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT some_values_1.key, random() AS random FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (table_2.key OPERATOR(pg_catalog.=) 1) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 JOIN intermediate_result_pruning.table_2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 USING (key)) WHERE (table_2.key OPERATOR(pg_catalog.=) 1) -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx - count ---------------------------------------------------------------------- - 0 -(1 row) - --- the same query with the above, but the final query is hitting all shards -WITH some_values_1 AS MATERIALIZED - (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), - some_values_2 AS MATERIALIZED - (SELECT key, random() FROM some_values_1 JOIN table_2 USING (key)) -SELECT - count(*) -FROM - (some_values_2 JOIN table_2 USING (key)) JOIN some_values_1 USING (key) WHERE table_2.key != 3; -DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) -DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT some_values_1.key, random() AS random FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 JOIN intermediate_result_pruning.table_2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 USING (key)) WHERE (table_2.key OPERATOR(pg_catalog.<>) 3) -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx - count ---------------------------------------------------------------------- - 1 -(1 row) - --- even if we add a filter on the first query and make it a router query, --- the first intermediate result still hits all workers because of the final --- join is hitting all workers -WITH some_values_1 AS MATERIALIZED - (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), - some_values_2 AS MATERIALIZED - (SELECT key, random() FROM some_values_1 JOIN table_2 USING (key) WHERE table_2.key = 3) -SELECT - count(*) -FROM - (some_values_2 JOIN table_2 USING (key)) JOIN some_values_1 USING (key) WHERE table_2.key != 3; -DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) -DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT some_values_1.key, random() AS random FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (table_2.key OPERATOR(pg_catalog.=) 3) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 JOIN intermediate_result_pruning.table_2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 USING (key)) WHERE (table_2.key OPERATOR(pg_catalog.<>) 3) -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx - count ---------------------------------------------------------------------- - 0 -(1 row) - --- the reference table is joined with a distributed table and an intermediate --- result, but the distributed table hits all shards, so the intermediate --- result is sent to all nodes -WITH some_values_1 AS MATERIALIZED - (SELECT key, random() FROM ref_table WHERE value IN ('3', '4')) -SELECT - count(*) -FROM - (some_values_1 JOIN ref_table USING (key)) JOIN table_2 USING (key); -DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.ref_table WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.ref_table USING (key)) JOIN intermediate_result_pruning.table_2 USING (key)) -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx - count ---------------------------------------------------------------------- - 2 -(1 row) - --- similar query as above, but this time the whole query is a router --- query, so no intermediate results -WITH some_values_1 AS MATERIALIZED - (SELECT key, random() FROM ref_table WHERE value IN ('3', '4')) -SELECT - count(*) -FROM - (some_values_1 JOIN ref_table USING (key)) JOIN table_2 USING (key) WHERE table_2.key = 1; - count ---------------------------------------------------------------------- - 0 -(1 row) - --- now, the second CTE has a single shard join with a distributed table --- so the first CTE should only be broadcasted to that node --- since the final query doesn't have a join, it should simply be broadcasted --- to one node -WITH some_values_1 AS MATERIALIZED - (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), - some_values_2 AS MATERIALIZED - (SELECT key, random() FROM some_values_1 JOIN table_2 USING (key) WHERE key = 1) -SELECT - count(*) -FROM - some_values_2; -DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) -DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT some_values_1.key, random() AS random FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (some_values_1.key OPERATOR(pg_catalog.=) 1) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be written to local file - count ---------------------------------------------------------------------- - 0 -(1 row) - --- the same query inlined inside a CTE, and the final query has a --- join with a distributed table -WITH top_cte as MATERIALIZED ( - WITH some_values_1 AS MATERIALIZED - (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), - some_values_2 AS MATERIALIZED - (SELECT key, random() FROM some_values_1 JOIN table_2 USING (key) WHERE key = 1) - SELECT - DISTINCT key - FROM - some_values_2 -) -SELECT - count(*) -FROM - top_cte JOIN table_2 USING (key); -DEBUG: generating subplan XXX_1 for CTE top_cte: WITH some_values_1 AS MATERIALIZED (SELECT table_1.key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (table_1.value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text]))), some_values_2 AS MATERIALIZED (SELECT some_values_1.key, random() AS random FROM (some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (some_values_1.key OPERATOR(pg_catalog.=) 1)) SELECT DISTINCT key FROM some_values_2 -DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) -DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT some_values_1.key, random() AS random FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (some_values_1.key OPERATOR(pg_catalog.=) 1) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT DISTINCT key FROM (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) top_cte JOIN intermediate_result_pruning.table_2 USING (key)) -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be written to local file - count ---------------------------------------------------------------------- - 0 -(1 row) - --- very much the same query, but this time the top query is also a router query --- on a single worker, so all intermediate results only hit a single node -WITH top_cte as MATERIALIZED ( - WITH some_values_1 AS MATERIALIZED - (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), - some_values_2 AS MATERIALIZED - (SELECT key, random() FROM some_values_1 JOIN table_2 USING (key) WHERE key = 1) - SELECT - DISTINCT key - FROM - some_values_2 -) -SELECT - count(*) -FROM - top_cte JOIN table_2 USING (key) WHERE table_2.key = 2; -DEBUG: generating subplan XXX_1 for CTE top_cte: WITH some_values_1 AS MATERIALIZED (SELECT table_1.key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (table_1.value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text]))), some_values_2 AS MATERIALIZED (SELECT some_values_1.key, random() AS random FROM (some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (some_values_1.key OPERATOR(pg_catalog.=) 1)) SELECT DISTINCT key FROM some_values_2 -DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) -DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT some_values_1.key, random() AS random FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (some_values_1.key OPERATOR(pg_catalog.=) 1) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT DISTINCT key FROM (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) top_cte JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (table_2.key OPERATOR(pg_catalog.=) 2) -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be written to local file - count ---------------------------------------------------------------------- - 0 -(1 row) - --- some_values_1 is first used by a single shard-query, and than with a multi-shard --- CTE, finally a cartesian product join -WITH some_values_1 AS MATERIALIZED - (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), - some_values_2 AS MATERIALIZED - (SELECT key, random() FROM some_values_1 JOIN table_2 USING (key) WHERE key = 1), - some_values_3 AS MATERIALIZED - (SELECT key FROM (some_values_2 JOIN table_2 USING (key)) JOIN some_values_1 USING (key)) -SELECT * FROM some_values_3 JOIN ref_table ON (true); -DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) -DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT some_values_1.key, random() AS random FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 JOIN intermediate_result_pruning.table_2 USING (key)) WHERE (some_values_1.key OPERATOR(pg_catalog.=) 1) -DEBUG: generating subplan XXX_3 for CTE some_values_3: SELECT some_values_2.key FROM (((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 JOIN intermediate_result_pruning.table_2 USING (key)) JOIN (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 USING (key)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT some_values_3.key, ref_table.key, ref_table.value FROM ((SELECT intermediate_result.key FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) some_values_3 JOIN intermediate_result_pruning.ref_table ON (true)) -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_3 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_3 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_3 will be sent to localhost:xxxxx - key | key | value ---------------------------------------------------------------------- -(0 rows) - --- join on intermediate results, so should only --- go to a single node -WITH some_values_1 AS MATERIALIZED - (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), - some_values_2 AS MATERIALIZED - (SELECT key, random() FROM table_2 WHERE value IN ('3', '4')) -SELECT count(*) FROM some_values_2 JOIN some_values_1 USING (key); -DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) -DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT key, random() AS random FROM intermediate_result_pruning.table_2 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 JOIN (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 USING (key)) -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_2 will be written to local file - count ---------------------------------------------------------------------- - 2 -(1 row) - --- same query with WHERE false make sure that we're not broken --- for such edge cases -WITH some_values_1 AS MATERIALIZED - (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), - some_values_2 AS MATERIALIZED - (SELECT key, random() FROM table_2 WHERE value IN ('3', '4')) -SELECT count(*) FROM some_values_2 JOIN some_values_1 USING (key) WHERE false; -DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) -DEBUG: generating subplan XXX_2 for CTE some_values_2: SELECT key, random() AS random FROM intermediate_result_pruning.table_2 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_2 JOIN (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 USING (key)) WHERE false -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_2 will be written to local file - count ---------------------------------------------------------------------- - 0 -(1 row) - --- do not use some_values_2 at all, so only 2 intermediate results are --- broadcasted -WITH some_values_1 AS MATERIALIZED - (SELECT key, random() FROM table_1 WHERE value IN ('3', '4')), - some_values_2 AS MATERIALIZED - (SELECT key, random() FROM some_values_1), - some_values_3 AS MATERIALIZED - (SELECT key, random() FROM some_values_1) -SELECT - count(*) -FROM - some_values_3; -DEBUG: generating subplan XXX_1 for CTE some_values_1: SELECT key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (value OPERATOR(pg_catalog.=) ANY (ARRAY['3'::text, '4'::text])) -DEBUG: generating subplan XXX_2 for CTE some_values_3: SELECT key, random() AS random FROM (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_1 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) some_values_3 -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_2 will be written to local file - count ---------------------------------------------------------------------- - 2 -(1 row) - --- lets have some deeper intermediate results --- the inner most two results and the final query (which contains only intermediate results) --- hitting single worker, others hitting all workers --- (see below query where all intermediate results hit a single node) -SELECT count(*) FROM -( - SELECT avg(min::int) FROM - ( - SELECT min(table_1.value) FROM - ( - SELECT avg(value::int) as avg_ev_type FROM - ( - SELECT max(value) as mx_val_1 FROM - ( - SELECT avg(value::int) as avg FROM - ( - SELECT cnt FROM - ( - SELECT count(*) as cnt, value - FROM table_1 - WHERE key = 1 - GROUP BY value - ) as level_1, table_1 - WHERE table_1.key = level_1.cnt AND key = 3 - ) as level_2, table_2 - WHERE table_2.key = level_2.cnt AND key = 5 - GROUP BY level_2.cnt - ) as level_3, table_1 - WHERE value::numeric = level_3.avg AND key = 6 - GROUP BY level_3.avg - ) as level_4, table_2 - WHERE level_4.mx_val_1::int = table_2.key - GROUP BY level_4.mx_val_1 - ) as level_5, table_1 - WHERE level_5.avg_ev_type = table_1.key AND key > 111 - GROUP BY level_5.avg_ev_type - ) as level_6, table_1 WHERE table_1.key::int = level_6.min::int - GROUP BY table_1.value -) as bar; -DEBUG: generating subplan XXX_1 for subquery SELECT count(*) AS cnt, value FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.=) 1) GROUP BY value -DEBUG: generating subplan XXX_2 for subquery SELECT avg((table_2.value)::integer) AS avg FROM (SELECT level_1.cnt FROM (SELECT intermediate_result.cnt, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(cnt bigint, value text)) level_1, intermediate_result_pruning.table_1 WHERE ((table_1.key OPERATOR(pg_catalog.=) level_1.cnt) AND (table_1.key OPERATOR(pg_catalog.=) 3))) level_2, intermediate_result_pruning.table_2 WHERE ((table_2.key OPERATOR(pg_catalog.=) level_2.cnt) AND (table_2.key OPERATOR(pg_catalog.=) 5)) GROUP BY level_2.cnt -DEBUG: generating subplan XXX_3 for subquery SELECT max(table_1.value) AS mx_val_1 FROM (SELECT intermediate_result.avg FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(avg numeric)) level_3, intermediate_result_pruning.table_1 WHERE (((table_1.value)::numeric OPERATOR(pg_catalog.=) level_3.avg) AND (table_1.key OPERATOR(pg_catalog.=) 6)) GROUP BY level_3.avg -DEBUG: generating subplan XXX_4 for subquery SELECT avg((table_2.value)::integer) AS avg_ev_type FROM (SELECT intermediate_result.mx_val_1 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(mx_val_1 text)) level_4, intermediate_result_pruning.table_2 WHERE ((level_4.mx_val_1)::integer OPERATOR(pg_catalog.=) table_2.key) GROUP BY level_4.mx_val_1 -DEBUG: generating subplan XXX_5 for subquery SELECT min(table_1.value) AS min FROM (SELECT intermediate_result.avg_ev_type FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(avg_ev_type numeric)) level_5, intermediate_result_pruning.table_1 WHERE ((level_5.avg_ev_type OPERATOR(pg_catalog.=) (table_1.key)::numeric) AND (table_1.key OPERATOR(pg_catalog.>) 111)) GROUP BY level_5.avg_ev_type -DEBUG: generating subplan XXX_6 for subquery SELECT avg((level_6.min)::integer) AS avg FROM (SELECT intermediate_result.min FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(min text)) level_6, intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) (level_6.min)::integer) GROUP BY table_1.value -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.avg FROM read_intermediate_result('XXX_6'::text, 'binary'::citus_copy_format) intermediate_result(avg numeric)) bar -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_3 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_3 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_4 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_4 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_5 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_5 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_6 will be written to local file - count ---------------------------------------------------------------------- - 0 -(1 row) - --- the same query where all intermediate results hits one --- worker because each and every query is a router query -- but on different nodes -SELECT count(*) FROM -( - SELECT avg(min::int) FROM - ( - SELECT min(table_1.value) FROM - ( - SELECT avg(value::int) as avg_ev_type FROM - ( - SELECT max(value) as mx_val_1 FROM - ( - SELECT avg(value::int) as avg FROM - ( - SELECT cnt FROM - ( - SELECT count(*) as cnt, value - FROM table_1 - WHERE key = 1 - GROUP BY value - ) as level_1, table_1 - WHERE table_1.key = level_1.cnt AND key = 3 - ) as level_2, table_2 - WHERE table_2.key = level_2.cnt AND key = 5 - GROUP BY level_2.cnt - ) as level_3, table_1 - WHERE value::numeric = level_3.avg AND key = 6 - GROUP BY level_3.avg - ) as level_4, table_2 - WHERE level_4.mx_val_1::int = table_2.key AND table_2.key = 1 - GROUP BY level_4.mx_val_1 - ) as level_5, table_1 - WHERE level_5.avg_ev_type = table_1.key AND key = 111 - GROUP BY level_5.avg_ev_type - ) as level_6, table_1 - WHERE table_1.key::int = level_6.min::int AND table_1.key = 4 - GROUP BY table_1.value -) as bar; -DEBUG: generating subplan XXX_1 for subquery SELECT count(*) AS cnt, value FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.=) 1) GROUP BY value -DEBUG: generating subplan XXX_2 for subquery SELECT avg((table_2.value)::integer) AS avg FROM (SELECT level_1.cnt FROM (SELECT intermediate_result.cnt, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(cnt bigint, value text)) level_1, intermediate_result_pruning.table_1 WHERE ((table_1.key OPERATOR(pg_catalog.=) level_1.cnt) AND (table_1.key OPERATOR(pg_catalog.=) 3))) level_2, intermediate_result_pruning.table_2 WHERE ((table_2.key OPERATOR(pg_catalog.=) level_2.cnt) AND (table_2.key OPERATOR(pg_catalog.=) 5)) GROUP BY level_2.cnt -DEBUG: generating subplan XXX_3 for subquery SELECT max(table_1.value) AS mx_val_1 FROM (SELECT intermediate_result.avg FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(avg numeric)) level_3, intermediate_result_pruning.table_1 WHERE (((table_1.value)::numeric OPERATOR(pg_catalog.=) level_3.avg) AND (table_1.key OPERATOR(pg_catalog.=) 6)) GROUP BY level_3.avg -DEBUG: generating subplan XXX_4 for subquery SELECT avg((table_2.value)::integer) AS avg_ev_type FROM (SELECT intermediate_result.mx_val_1 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(mx_val_1 text)) level_4, intermediate_result_pruning.table_2 WHERE (((level_4.mx_val_1)::integer OPERATOR(pg_catalog.=) table_2.key) AND (table_2.key OPERATOR(pg_catalog.=) 1)) GROUP BY level_4.mx_val_1 -DEBUG: generating subplan XXX_5 for subquery SELECT min(table_1.value) AS min FROM (SELECT intermediate_result.avg_ev_type FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(avg_ev_type numeric)) level_5, intermediate_result_pruning.table_1 WHERE ((level_5.avg_ev_type OPERATOR(pg_catalog.=) (table_1.key)::numeric) AND (table_1.key OPERATOR(pg_catalog.=) 111)) GROUP BY level_5.avg_ev_type -DEBUG: generating subplan XXX_6 for subquery SELECT avg((level_6.min)::integer) AS avg FROM (SELECT intermediate_result.min FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result(min text)) level_6, intermediate_result_pruning.table_1 WHERE ((table_1.key OPERATOR(pg_catalog.=) (level_6.min)::integer) AND (table_1.key OPERATOR(pg_catalog.=) 4)) GROUP BY table_1.value -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.avg FROM read_intermediate_result('XXX_6'::text, 'binary'::citus_copy_format) intermediate_result(avg numeric)) bar -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_3 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_4 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_5 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_6 will be written to local file - count ---------------------------------------------------------------------- - 0 -(1 row) - --- sanity checks for set operations --- the intermediate results should just hit a single worker -(SELECT key FROM table_1 WHERE key = 1) -INTERSECT -(SELECT key FROM table_1 WHERE key = 2); -DEBUG: generating subplan XXX_1 for subquery SELECT key FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.=) 1) -DEBUG: generating subplan XXX_2 for subquery SELECT key FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.=) 2) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer) INTERSECT SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer) -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_2 will be written to local file - key ---------------------------------------------------------------------- -(0 rows) - --- the intermediate results should just hit a single worker -WITH cte_1 AS MATERIALIZED -( - (SELECT key FROM table_1 WHERE key = 1) - INTERSECT - (SELECT key FROM table_1 WHERE key = 2) -), -cte_2 AS MATERIALIZED -( - (SELECT key FROM table_1 WHERE key = 3) - INTERSECT - (SELECT key FROM table_1 WHERE key = 4) -) -SELECT * FROM cte_1 - UNION -SELECT * FROM cte_2; -DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 1) INTERSECT SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 2) -DEBUG: generating subplan XXX_1 for subquery SELECT key FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.=) 1) -DEBUG: generating subplan XXX_2 for subquery SELECT key FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.=) 2) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer) INTERSECT SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer) -DEBUG: generating subplan XXX_2 for CTE cte_2: SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 3) INTERSECT SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 4) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT cte_1.key FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) cte_1 UNION SELECT cte_2.key FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) cte_2 -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_2 will be written to local file -DEBUG: Subplan XXX_2 will be written to local file - key ---------------------------------------------------------------------- -(0 rows) - --- one final test with SET operations, where --- we join the results with distributed tables --- so cte_1 should hit all workers, but still the --- others should hit single worker each -WITH cte_1 AS MATERIALIZED -( - (SELECT key FROM table_1 WHERE key = 1) - INTERSECT - (SELECT key FROM table_1 WHERE key = 2) -), -cte_2 AS MATERIALIZED -( - SELECT count(*) FROM table_1 JOIN cte_1 USING (key) -) -SELECT * FROM cte_2; -DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 1) INTERSECT SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 2) -DEBUG: generating subplan XXX_1 for subquery SELECT key FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.=) 1) -DEBUG: generating subplan XXX_2 for subquery SELECT key FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.=) 2) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer) INTERSECT SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer) -DEBUG: generating subplan XXX_2 for CTE cte_2: SELECT count(*) AS count FROM (intermediate_result_pruning.table_1 JOIN (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) cte_1 USING (key)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count FROM (SELECT intermediate_result.count FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(count bigint)) cte_2 -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_2 will be written to local file -DEBUG: Subplan XXX_2 will be written to local file - count ---------------------------------------------------------------------- - 0 -(1 row) - --- sanity checks for non-colocated subquery joins --- the recursively planned subquery (bar) should hit all --- nodes -SELECT - count(*) -FROM - (SELECT key, random() FROM table_1) as foo, - (SELECT key, random() FROM table_2) as bar -WHERE - foo.key != bar.key; -DEBUG: generating subplan XXX_1 for subquery SELECT key, random() AS random FROM intermediate_result_pruning.table_2 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT table_1.key, random() AS random FROM intermediate_result_pruning.table_1) foo, (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) bar WHERE (foo.key OPERATOR(pg_catalog.<>) bar.key) -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx - count ---------------------------------------------------------------------- - 14 -(1 row) - --- the recursively planned subquery (bar) should hit one --- node because foo goes to a single node -SELECT - count(*) -FROM - (SELECT key, random() FROM table_1 WHERE key = 1) as foo, - (SELECT key, random() FROM table_2) as bar -WHERE - foo.key != bar.key; -DEBUG: generating subplan XXX_1 for subquery SELECT key, random() AS random FROM intermediate_result_pruning.table_2 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT table_1.key, random() AS random FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 1)) foo, (SELECT intermediate_result.key, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, random double precision)) bar WHERE (foo.key OPERATOR(pg_catalog.<>) bar.key) -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx - count ---------------------------------------------------------------------- - 4 -(1 row) - --- sanity checks for modification queries --- select_data goes to a single node, because it is used in another subquery --- raw_data is also the final router query, so hits a single shard --- however, the subquery in WHERE clause of the DELETE query is broadcasted to all --- nodes -BEGIN; -WITH select_data AS MATERIALIZED ( - SELECT * FROM table_1 -), -raw_data AS MATERIALIZED ( - DELETE FROM table_2 WHERE key >= (SELECT min(key) FROM select_data WHERE key > 1) RETURNING * -) -SELECT * FROM raw_data; -DEBUG: generating subplan XXX_1 for CTE select_data: SELECT key, value FROM intermediate_result_pruning.table_1 -DEBUG: generating subplan XXX_2 for CTE raw_data: DELETE FROM intermediate_result_pruning.table_2 WHERE (key OPERATOR(pg_catalog.>=) (SELECT min(select_data.key) AS min FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) select_data WHERE (select_data.key OPERATOR(pg_catalog.>) 1))) RETURNING key, value -DEBUG: generating subplan XXX_1 for subquery SELECT min(key) AS min FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) select_data WHERE (key OPERATOR(pg_catalog.>) 1) -DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM intermediate_result_pruning.table_2 WHERE (key OPERATOR(pg_catalog.>=) (SELECT intermediate_result.min FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(min integer))) RETURNING key, value -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT key, value FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) raw_data -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_2 will be written to local file -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx - key | value ---------------------------------------------------------------------- - 3 | 3 - 4 | 4 - 5 | 5 - 6 | 6 -(4 rows) - -ROLLBACK; --- select_data goes to a single node, because it is used in another subquery --- raw_data is also the final router query, so hits a single shard --- however, the subquery in WHERE clause of the DELETE query is broadcasted to all --- nodes -BEGIN; -WITH select_data AS MATERIALIZED ( - SELECT * FROM table_1 -), -raw_data AS MATERIALIZED ( - DELETE FROM table_2 WHERE value::int >= (SELECT min(key) FROM select_data WHERE key > 1 + random()) RETURNING * -) -SELECT * FROM raw_data; -DEBUG: generating subplan XXX_1 for CTE select_data: SELECT key, value FROM intermediate_result_pruning.table_1 -DEBUG: generating subplan XXX_2 for CTE raw_data: DELETE FROM intermediate_result_pruning.table_2 WHERE ((value)::integer OPERATOR(pg_catalog.>=) (SELECT min(select_data.key) AS min FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) select_data WHERE ((select_data.key)::double precision OPERATOR(pg_catalog.>) ((1)::double precision OPERATOR(pg_catalog.+) random())))) RETURNING key, value -DEBUG: generating subplan XXX_1 for subquery SELECT min(key) AS min FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) select_data WHERE ((key)::double precision OPERATOR(pg_catalog.>) ((1)::double precision OPERATOR(pg_catalog.+) random())) -DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM intermediate_result_pruning.table_2 WHERE ((value)::integer OPERATOR(pg_catalog.>=) (SELECT intermediate_result.min FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(min integer))) RETURNING key, value -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT key, value FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) raw_data -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_2 will be written to local file -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx - key | value ---------------------------------------------------------------------- - 3 | 3 - 4 | 4 - 5 | 5 - 6 | 6 -(4 rows) - -ROLLBACK; --- now, we need only two intermediate results as the subquery in WHERE clause is --- router plannable -BEGIN; -WITH select_data AS MATERIALIZED ( - SELECT * FROM table_1 -), -raw_data AS MATERIALIZED ( - DELETE FROM table_2 WHERE value::int >= (SELECT min(key) FROM table_1 WHERE key > random()) AND key = 6 RETURNING * -) -SELECT * FROM raw_data; -DEBUG: generating subplan XXX_1 for CTE raw_data: DELETE FROM intermediate_result_pruning.table_2 WHERE (((value)::integer OPERATOR(pg_catalog.>=) (SELECT min(table_1.key) AS min FROM intermediate_result_pruning.table_1 WHERE ((table_1.key)::double precision OPERATOR(pg_catalog.>) random()))) AND (key OPERATOR(pg_catalog.=) 6)) RETURNING key, value -DEBUG: generating subplan XXX_1 for subquery SELECT min(key) AS min FROM intermediate_result_pruning.table_1 WHERE ((key)::double precision OPERATOR(pg_catalog.>) random()) -DEBUG: Plan XXX query after replacing subqueries and CTEs: DELETE FROM intermediate_result_pruning.table_2 WHERE (((value)::integer OPERATOR(pg_catalog.>=) (SELECT intermediate_result.min FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(min integer))) AND (key OPERATOR(pg_catalog.=) 6)) RETURNING key, value -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT key, value FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) raw_data -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx - key | value ---------------------------------------------------------------------- - 6 | 6 -(1 row) - -ROLLBACK; --- test with INSERT SELECT via coordinator --- INSERT .. SELECT via coordinator that doesn't have any intermediate results --- We use offset 1 to make sure the result needs to be pulled to the coordinator, offset 0 would be optimized away -INSERT INTO table_1 - SELECT * FROM table_2 OFFSET 1; -DEBUG: cannot push down this subquery -DETAIL: Offset clause is currently unsupported when a subquery references a column from another query -DEBUG: Collecting INSERT ... SELECT results on coordinator --- INSERT .. SELECT via coordinator which has intermediate result, --- and can be pruned to a single worker because the final query is on --- single shard via filter in key -INSERT INTO table_1 - SELECT * FROM table_2 where value IN (SELECT value FROM table_1 WHERE random() > 1) AND key = 1; -DEBUG: volatile functions are not allowed in distributed INSERT ... SELECT queries -DEBUG: generating subplan XXX_1 for subquery SELECT value FROM intermediate_result_pruning.table_1 WHERE (random() OPERATOR(pg_catalog.>) (1)::double precision) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT key, value FROM intermediate_result_pruning.table_2 WHERE ((value OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text))) AND (key OPERATOR(pg_catalog.=) 1)) -DEBUG: Collecting INSERT ... SELECT results on coordinator -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx --- a similar query, with more complex subquery -INSERT INTO table_1 - SELECT * FROM table_2 where key = 1 AND - value::int IN - (WITH cte_1 AS MATERIALIZED - ( - (SELECT key FROM table_1 WHERE key = 1) - INTERSECT - (SELECT key FROM table_1 WHERE key = 2) - ), - cte_2 AS MATERIALIZED - ( - (SELECT key FROM table_1 WHERE key = 3) - INTERSECT - (SELECT key FROM table_1 WHERE key = 4) - ) - SELECT * FROM cte_1 - UNION - SELECT * FROM cte_2); -DEBUG: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns -DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 1) INTERSECT SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 2) -DEBUG: generating subplan XXX_1 for subquery SELECT key FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.=) 1) -DEBUG: generating subplan XXX_2 for subquery SELECT key FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.=) 2) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer) INTERSECT SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer) -DEBUG: generating subplan XXX_2 for CTE cte_2: SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 3) INTERSECT SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 4) -DEBUG: generating subplan XXX_3 for subquery SELECT cte_1.key FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) cte_1 UNION SELECT cte_2.key FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) cte_2 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT key, value FROM intermediate_result_pruning.table_2 WHERE ((key OPERATOR(pg_catalog.=) 1) AND ((value)::integer OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.key FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(key integer)))) -DEBUG: Collecting INSERT ... SELECT results on coordinator -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_2 will be written to local file -DEBUG: Subplan XXX_2 will be written to local file -DEBUG: Subplan XXX_3 will be sent to localhost:xxxxx --- same query, cte is on the FROM clause --- and this time the final query (and top-level intermediate result) --- hits all the shards because table_2.key != 1 -INSERT INTO table_1 - SELECT table_2.* FROM table_2, - (WITH cte_1 AS MATERIALIZED - ( - (SELECT key FROM table_1 WHERE key = 1) - INTERSECT - (SELECT key FROM table_1 WHERE key = 2) - ), - cte_2 AS MATERIALIZED - ( - (SELECT key FROM table_1 WHERE key = 3) - INTERSECT - (SELECT key FROM table_1 WHERE key = 4) - ) - SELECT * FROM cte_1 - UNION - SELECT * FROM cte_2 - ) foo - where table_2.key != 1 AND - foo.key = table_2.value::int; -DEBUG: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns -DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 1) INTERSECT SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 2) -DEBUG: generating subplan XXX_1 for subquery SELECT key FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.=) 1) -DEBUG: generating subplan XXX_2 for subquery SELECT key FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.=) 2) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer) INTERSECT SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer) -DEBUG: generating subplan XXX_2 for CTE cte_2: SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 3) INTERSECT SELECT table_1.key FROM intermediate_result_pruning.table_1 WHERE (table_1.key OPERATOR(pg_catalog.=) 4) -DEBUG: generating subplan XXX_3 for subquery SELECT cte_1.key FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) cte_1 UNION SELECT cte_2.key FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) cte_2 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT table_2.key, table_2.value FROM intermediate_result_pruning.table_2, (SELECT intermediate_result.key FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) foo WHERE ((table_2.key OPERATOR(pg_catalog.<>) 1) AND (foo.key OPERATOR(pg_catalog.=) (table_2.value)::integer)) -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_2 will be written to local file -DEBUG: Subplan XXX_2 will be written to local file -DEBUG: Subplan XXX_3 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_3 will be sent to localhost:xxxxx --- append partitioned/heap-type --- do not print out 'building index pg_toast_xxxxx_index' messages -SET client_min_messages TO DEFAULT; -CREATE TABLE range_partitioned(range_column text, data int); -SET client_min_messages TO DEBUG1; -SELECT create_distributed_table('range_partitioned', 'range_column', 'range'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -SELECT master_create_empty_shard('range_partitioned'); - master_create_empty_shard ---------------------------------------------------------------------- - 1480013 -(1 row) - -SELECT master_create_empty_shard('range_partitioned'); - master_create_empty_shard ---------------------------------------------------------------------- - 1480014 -(1 row) - -SELECT master_create_empty_shard('range_partitioned'); - master_create_empty_shard ---------------------------------------------------------------------- - 1480015 -(1 row) - -SELECT master_create_empty_shard('range_partitioned'); - master_create_empty_shard ---------------------------------------------------------------------- - 1480016 -(1 row) - -SELECT master_create_empty_shard('range_partitioned'); - master_create_empty_shard ---------------------------------------------------------------------- - 1480017 -(1 row) - -UPDATE pg_dist_shard SET shardminvalue = 'A', shardmaxvalue = 'D' WHERE shardid = 1480013; -UPDATE pg_dist_shard SET shardminvalue = 'D', shardmaxvalue = 'G' WHERE shardid = 1480014; -UPDATE pg_dist_shard SET shardminvalue = 'G', shardmaxvalue = 'K' WHERE shardid = 1480015; -UPDATE pg_dist_shard SET shardminvalue = 'K', shardmaxvalue = 'O' WHERE shardid = 1480016; -UPDATE pg_dist_shard SET shardminvalue = 'O', shardmaxvalue = 'Z' WHERE shardid = 1480017; --- final query goes to a single shard -SELECT - count(*) -FROM - range_partitioned -WHERE - range_column = 'A' AND - data IN (SELECT data FROM range_partitioned); -DEBUG: generating subplan XXX_1 for subquery SELECT data FROM intermediate_result_pruning.range_partitioned -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM intermediate_result_pruning.range_partitioned WHERE ((range_column OPERATOR(pg_catalog.=) 'A'::text) AND (data OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.data FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(data integer)))) -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx - count ---------------------------------------------------------------------- - 0 -(1 row) - --- final query goes to three shards, so multiple workers -SELECT - count(*) -FROM - range_partitioned -WHERE - range_column >= 'A' AND range_column <= 'K' AND - data IN (SELECT data FROM range_partitioned); -DEBUG: generating subplan XXX_1 for subquery SELECT data FROM intermediate_result_pruning.range_partitioned -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM intermediate_result_pruning.range_partitioned WHERE ((range_column OPERATOR(pg_catalog.>=) 'A'::text) AND (range_column OPERATOR(pg_catalog.<=) 'K'::text) AND (data OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.data FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(data integer)))) -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx - count ---------------------------------------------------------------------- - 0 -(1 row) - --- two shards, both of which are on the first node -WITH some_data AS ( - SELECT data FROM range_partitioned -) -SELECT - count(*) -FROM - range_partitioned -WHERE - range_column IN ('A', 'E') AND - range_partitioned.data IN (SELECT data FROM some_data); -DEBUG: CTE some_data is going to be inlined via distributed planning -DEBUG: generating subplan XXX_1 for subquery SELECT data FROM (SELECT range_partitioned.data FROM intermediate_result_pruning.range_partitioned) some_data -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM intermediate_result_pruning.range_partitioned WHERE ((range_column OPERATOR(pg_catalog.=) ANY (ARRAY['A'::text, 'E'::text])) AND (data OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.data FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(data integer)))) -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx - count ---------------------------------------------------------------------- - 0 -(1 row) - --- test case for issue #3556 -CREATE TABLE accounts (id text PRIMARY KEY); -DEBUG: CREATE TABLE / PRIMARY KEY will create implicit index "accounts_pkey" for table "accounts" -CREATE TABLE stats (account_id text PRIMARY KEY, spent int); -DEBUG: CREATE TABLE / PRIMARY KEY will create implicit index "stats_pkey" for table "stats" -SELECT create_distributed_table('accounts', 'id', colocate_with => 'none'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -SELECT create_distributed_table('stats', 'account_id', colocate_with => 'accounts'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO accounts (id) VALUES ('foo'); -INSERT INTO stats (account_id, spent) VALUES ('foo', 100); -SELECT * -FROM -( - WITH accounts_cte AS MATERIALIZED ( - SELECT id AS account_id - FROM accounts - ), - joined_stats_cte_1 AS MATERIALIZED ( - SELECT spent, account_id - FROM stats - INNER JOIN accounts_cte USING (account_id) - ), - joined_stats_cte_2 AS MATERIALIZED ( - SELECT spent, account_id - FROM joined_stats_cte_1 - INNER JOIN accounts_cte USING (account_id) - ) - SELECT SUM(spent) OVER (PARTITION BY coalesce(account_id, NULL)) - FROM accounts_cte - INNER JOIN joined_stats_cte_2 USING (account_id) -) inner_query; -DEBUG: generating subplan XXX_1 for CTE accounts_cte: SELECT id AS account_id FROM intermediate_result_pruning.accounts -DEBUG: generating subplan XXX_2 for CTE joined_stats_cte_1: SELECT stats.spent, stats.account_id FROM (intermediate_result_pruning.stats JOIN (SELECT intermediate_result.account_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(account_id text)) accounts_cte USING (account_id)) -DEBUG: generating subplan XXX_3 for CTE joined_stats_cte_2: SELECT joined_stats_cte_1.spent, joined_stats_cte_1.account_id FROM ((SELECT intermediate_result.spent, intermediate_result.account_id FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(spent integer, account_id text)) joined_stats_cte_1 JOIN (SELECT intermediate_result.account_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(account_id text)) accounts_cte USING (account_id)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT sum FROM (SELECT sum(joined_stats_cte_2.spent) OVER (PARTITION BY COALESCE(accounts_cte.account_id, NULL::text)) AS sum FROM ((SELECT intermediate_result.account_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(account_id text)) accounts_cte JOIN (SELECT intermediate_result.spent, intermediate_result.account_id FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(spent integer, account_id text)) joined_stats_cte_2 USING (account_id))) inner_query -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be written to local file -DEBUG: Subplan XXX_3 will be written to local file - sum ---------------------------------------------------------------------- - 100 -(1 row) - --- confirm that the pruning works well when using round-robin as well -SET citus.task_assignment_policy to 'round-robin'; -SELECT * -FROM -( - WITH accounts_cte AS MATERIALIZED ( - SELECT id AS account_id - FROM accounts - ), - joined_stats_cte_1 AS MATERIALIZED ( - SELECT spent, account_id - FROM stats - INNER JOIN accounts_cte USING (account_id) - ), - joined_stats_cte_2 AS MATERIALIZED ( - SELECT spent, account_id - FROM joined_stats_cte_1 - INNER JOIN accounts_cte USING (account_id) - ) - SELECT SUM(spent) OVER (PARTITION BY coalesce(account_id, NULL)) - FROM accounts_cte - INNER JOIN joined_stats_cte_2 USING (account_id) -) inner_query; -DEBUG: generating subplan XXX_1 for CTE accounts_cte: SELECT id AS account_id FROM intermediate_result_pruning.accounts -DEBUG: generating subplan XXX_2 for CTE joined_stats_cte_1: SELECT stats.spent, stats.account_id FROM (intermediate_result_pruning.stats JOIN (SELECT intermediate_result.account_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(account_id text)) accounts_cte USING (account_id)) -DEBUG: generating subplan XXX_3 for CTE joined_stats_cte_2: SELECT joined_stats_cte_1.spent, joined_stats_cte_1.account_id FROM ((SELECT intermediate_result.spent, intermediate_result.account_id FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(spent integer, account_id text)) joined_stats_cte_1 JOIN (SELECT intermediate_result.account_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(account_id text)) accounts_cte USING (account_id)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT sum FROM (SELECT sum(joined_stats_cte_2.spent) OVER (PARTITION BY COALESCE(accounts_cte.account_id, NULL::text)) AS sum FROM ((SELECT intermediate_result.account_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(account_id text)) accounts_cte JOIN (SELECT intermediate_result.spent, intermediate_result.account_id FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(spent integer, account_id text)) joined_stats_cte_2 USING (account_id))) inner_query -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_3 will be sent to localhost:xxxxx - sum ---------------------------------------------------------------------- - 100 -(1 row) - -RESET citus.task_assignment_policy; --- Insert..select is planned differently, make sure we have results everywhere. --- We put the insert..select in a CTE here to prevent the CTE from being moved --- into the select, which would follow the regular code path for select. -WITH stats AS MATERIALIZED ( - SELECT count(key) m FROM table_3 -), -inserts AS MATERIALIZED ( - INSERT INTO table_2 - SELECT key, count(*) - FROM table_1 - WHERE key > (SELECT m FROM stats) - GROUP BY key - HAVING count(*) < (SELECT m FROM stats) - LIMIT 1 - RETURNING * -) SELECT count(*) FROM inserts; -DEBUG: generating subplan XXX_1 for CTE stats: SELECT count(key) AS m FROM intermediate_result_pruning.table_3 -DEBUG: generating subplan XXX_2 for CTE inserts: INSERT INTO intermediate_result_pruning.table_2 (key, value) SELECT key, count(*) AS count FROM intermediate_result_pruning.table_1 WHERE (key OPERATOR(pg_catalog.>) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) GROUP BY key HAVING (count(*) OPERATOR(pg_catalog.<) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) LIMIT 1 RETURNING table_2.key, table_2.value -DEBUG: cannot push down this subquery -DETAIL: Limit clause is currently unsupported when a subquery references a column from another query -DEBUG: push down of limit count: 1 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) inserts -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be written to local file -DEBUG: Collecting INSERT ... SELECT results on coordinator - count ---------------------------------------------------------------------- - 1 -(1 row) - -SET citus.task_assignment_policy to DEFAULT; -SET client_min_messages TO DEFAULT; -DROP TABLE table_1, table_2, table_3, ref_table, accounts, stats, range_partitioned; -DROP SCHEMA intermediate_result_pruning; diff --git a/src/test/regress/expected/issue_5248.out b/src/test/regress/expected/issue_5248.out index db1ae26c7..d5946089f 100644 --- a/src/test/regress/expected/issue_5248.out +++ b/src/test/regress/expected/issue_5248.out @@ -1,19 +1,11 @@ -- -- ISSUE_5248 -- --- This test file has an alternative output because of the change in the --- backup modes of Postgres. Specifically, there is a renaming --- issue: pg_stop_backup PRE PG15 vs pg_backup_stop PG15+ --- The alternative output can be deleted when we drop support for PG14 --- CREATE SCHEMA issue_5248; SET search_path TO issue_5248; SET citus.shard_count TO 4; SET citus.shard_replication_factor TO 1; SET citus.next_shard_id TO 3013000; -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset create table countries( id serial primary key , name text @@ -219,12 +211,8 @@ FROM ( ( SELECT utc_offset FROM pg_catalog.pg_timezone_names limit 1 offset 4) limit 91) AS subq_3 -\if :server_version_ge_15 WHERE pg_catalog.pg_backup_stop() > cast(NULL AS record) limit 100; ERROR: cannot push down subquery on the target list DETAIL: Subqueries in the SELECT part of the query can only be pushed down if they happen before aggregates and window functions -\else -WHERE pg_catalog.pg_stop_backup() > cast(NULL AS pg_lsn) limit 100; -\endif SET client_min_messages TO WARNING; DROP SCHEMA issue_5248 CASCADE; diff --git a/src/test/regress/expected/issue_5248_0.out b/src/test/regress/expected/issue_5248_0.out deleted file mode 100644 index d7fe8020c..000000000 --- a/src/test/regress/expected/issue_5248_0.out +++ /dev/null @@ -1,230 +0,0 @@ --- --- ISSUE_5248 --- --- This test file has an alternative output because of the change in the --- backup modes of Postgres. Specifically, there is a renaming --- issue: pg_stop_backup PRE PG15 vs pg_backup_stop PG15+ --- The alternative output can be deleted when we drop support for PG14 --- -CREATE SCHEMA issue_5248; -SET search_path TO issue_5248; -SET citus.shard_count TO 4; -SET citus.shard_replication_factor TO 1; -SET citus.next_shard_id TO 3013000; -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -create table countries( - id serial primary key - , name text - , code varchar(2) collate "C" unique -); -insert into countries(name, code) select 'country-'||i, i::text from generate_series(10,99) i; -select create_reference_table('countries'); -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_5248.countries$$) - create_reference_table ---------------------------------------------------------------------- - -(1 row) - -create table orgs ( - id bigserial primary key - , name text - , created_at timestamptz default now() -); -select create_distributed_table('orgs', 'id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -create table users ( - id bigserial - , org_id bigint references orgs(id) - , name text - , created_at timestamptz default now() - , country_id int -- references countries(id) - , score bigint generated always as (id + country_id) stored - , primary key (org_id, id) -); -select create_distributed_table('users', 'org_id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -alter table users add constraint fk_user_country foreign key (country_id) references countries(id); -create table orders ( - id bigserial - , org_id bigint references orgs(id) - , user_id bigint - , price int - , info jsonb - , primary key (org_id, id) - , foreign key (org_id, user_id) references users(org_id, id) -); -select create_distributed_table('orders', 'org_id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -create table events ( - id bigserial not null - , user_id bigint not null - , org_id bigint not null - , event_time timestamp not null default now() - , event_type int not null default 0 - , payload jsonb - , primary key (user_id, id) -); -create index event_time_idx on events using BRIN (event_time); -create index event_json_idx on events using gin(payload); -select create_distributed_table('events', 'user_id'); -- on purpose don't colocate on correctly on org_id - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -create table local_data( - id bigserial primary key - , val int default ( (random()*100)::int ) -); -insert into orgs(id, name) select i,'org-'||i from generate_series(1,10) i; -insert into users(id, name, org_id, country_id) select i,'user-'||i, i+1, (i%90)+1 from generate_series(1,5) i; -insert into orders(id, org_id, user_id, price) select i, ((i+1))+1 , i+1, i/100 from generate_series(1,2) i; -insert into events(id, org_id, user_id, event_type) select i, ((i+1))+1 , i+1, i/100 from generate_series(1,10) i; -insert into local_data(id) select generate_series(1,10); -/* - * Test that we don't get a crash. See #5248. - */ -SELECT subq_3.c15 AS c0, - subq_3.c0 AS c1, - subq_3.c15 AS c2, - subq_0.c1 AS c3, - pg_catalog.String_agg( Cast( - ( - SELECT tgargs - FROM pg_catalog.pg_trigger limit 1 offset 1) AS BYTEA), Cast( - ( - SELECT minimum_value - FROM columnar.chunk limit 1 offset 5) AS BYTEA)) OVER (partition BY subq_3.c10 ORDER BY subq_3.c12,subq_0.c2) AS c4, - subq_0.c1 AS c5 -FROM ( - SELECT ref_1.address AS c0, - ref_1.error AS c1, - sample_0.NAME AS c2, - sample_2.trftosql AS c3 - FROM pg_catalog.pg_statio_all_sequences AS ref_0 - INNER JOIN pg_catalog.pg_hba_file_rules AS ref_1 - ON (( - SELECT pg_catalog.Max(aggnumdirectargs) - FROM pg_catalog.pg_aggregate) <= ref_0.blks_hit) - INNER JOIN countries AS sample_0 TABLESAMPLE system (6.4) - INNER JOIN local_data AS sample_1 TABLESAMPLE bernoulli (8) - ON (( - true) - OR ( - sample_0.NAME IS NOT NULL)) - INNER JOIN pg_catalog.pg_transform AS sample_2 TABLESAMPLE bernoulli (1.2) - INNER JOIN pg_catalog.pg_language AS ref_2 - ON (( - SELECT shard_cost_function - FROM pg_catalog.pg_dist_rebalance_strategy limit 1 offset 1) IS NULL) - RIGHT JOIN pg_catalog.pg_index AS sample_3 TABLESAMPLE system (0.3) - ON (( - cast(NULL AS bpchar) ~<=~ cast(NULL AS bpchar)) - OR (( - EXISTS - ( - SELECT sample_3.indnkeyatts AS c0, - sample_2.trflang AS c1, - sample_2.trftype AS c2 - FROM pg_catalog.pg_statistic_ext AS sample_4 TABLESAMPLE bernoulli (8.6) - WHERE sample_2.trftype IS NOT NULL)) - AND ( - false))) - ON ( - EXISTS - ( - SELECT sample_0.id AS c0, - sample_3.indisprimary AS c1 - FROM orgs AS sample_5 TABLESAMPLE system (5.3) - WHERE false)) - ON ( - cast(NULL AS float8) > - ( - SELECT pg_catalog.avg(enumsortorder) - FROM pg_catalog.pg_enum) ) - WHERE cast(COALESCE( - CASE - WHEN ref_1.auth_method ~>=~ ref_1.auth_method THEN cast(NULL AS path) - ELSE cast(NULL AS path) - END , cast(NULL AS path)) AS path) = cast(NULL AS path)) AS subq_0, - lateral - ( - SELECT - ( - SELECT pg_catalog.stddev(total_time) - FROM pg_catalog.pg_stat_user_functions) AS c0, - subq_0.c1 AS c1, - subq_2.c0 AS c2, - subq_0.c2 AS c3, - subq_0.c0 AS c4, - cast(COALESCE(subq_2.c0, subq_2.c0) AS text) AS c5, - subq_2.c0 AS c6, - subq_2.c1 AS c7, - subq_2.c1 AS c8, - subq_2.c1 AS c9, - subq_0.c3 AS c10, - pg_catalog.pg_stat_get_db_temp_files( cast( - ( - SELECT objoid - FROM pg_catalog.pg_description limit 1 offset 1) AS oid)) AS c11, - subq_0.c3 AS c12, - subq_2.c1 AS c13, - subq_0.c0 AS c14, - subq_0.c3 AS c15, - subq_0.c3 AS c16, - subq_0.c1 AS c17, - subq_0.c2 AS c18 - FROM ( - SELECT subq_1.c2 AS c0, - subq_0.c3 AS c1 - FROM information_schema.element_types AS ref_3, - lateral - ( - SELECT subq_0.c1 AS c0, - sample_6.info AS c1, - subq_0.c2 AS c2, - subq_0.c3 AS c3, - sample_6.user_id AS c5, - ref_3.collation_name AS c6 - FROM orders AS sample_6 TABLESAMPLE system (3.8) - WHERE sample_6.price = sample_6.org_id limit 58) AS subq_1 - WHERE ( - subq_1.c2 <= subq_0.c2) - AND ( - cast(NULL AS line) ?-| cast(NULL AS line)) limit 59) AS subq_2 - WHERE cast(COALESCE(pg_catalog.age( cast( - ( - SELECT pg_catalog.max(event_time) - FROM events) AS "timestamp")), - ( - SELECT write_lag - FROM pg_catalog.pg_stat_replication limit 1 offset 3) ) AS "interval") > - ( - SELECT utc_offset - FROM pg_catalog.pg_timezone_names limit 1 offset 4) limit 91) AS subq_3 -\if :server_version_ge_15 -WHERE pg_catalog.pg_backup_stop() > cast(NULL AS record) limit 100; -\else -WHERE pg_catalog.pg_stop_backup() > cast(NULL AS pg_lsn) limit 100; -ERROR: cannot push down subquery on the target list -DETAIL: Subqueries in the SELECT part of the query can only be pushed down if they happen before aggregates and window functions -\endif -SET client_min_messages TO WARNING; -DROP SCHEMA issue_5248 CASCADE; diff --git a/src/test/regress/expected/local_shard_execution.out b/src/test/regress/expected/local_shard_execution.out index 58293a2d6..2b1fa3c0b 100644 --- a/src/test/regress/expected/local_shard_execution.out +++ b/src/test/regress/expected/local_shard_execution.out @@ -1,17 +1,6 @@ -- -- LOCAL_SHARD_EXECUTION -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - t -(1 row) - CREATE SCHEMA local_shard_execution; SET search_path TO local_shard_execution; SET citus.shard_count TO 4; diff --git a/src/test/regress/expected/local_shard_execution_0.out b/src/test/regress/expected/local_shard_execution_0.out deleted file mode 100644 index 948941aad..000000000 --- a/src/test/regress/expected/local_shard_execution_0.out +++ /dev/null @@ -1,3302 +0,0 @@ --- --- LOCAL_SHARD_EXECUTION --- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - f -(1 row) - -CREATE SCHEMA local_shard_execution; -SET search_path TO local_shard_execution; -SET citus.shard_count TO 4; -SET citus.shard_replication_factor TO 1; -SET citus.next_shard_id TO 1470000; -CREATE TABLE reference_table (key int PRIMARY KEY); -SELECT create_reference_table('reference_table'); - create_reference_table ---------------------------------------------------------------------- - -(1 row) - -CREATE TABLE distributed_table (key int PRIMARY KEY , value text, age bigint CHECK (age > 10), FOREIGN KEY (key) REFERENCES reference_table(key) ON DELETE CASCADE); -SELECT create_distributed_table('distributed_table','key'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -CREATE TABLE second_distributed_table (key int PRIMARY KEY , value text, FOREIGN KEY (key) REFERENCES distributed_table(key) ON DELETE CASCADE); -SELECT create_distributed_table('second_distributed_table','key'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - --- ingest some data to enable some tests with data -INSERT INTO reference_table VALUES (1); -INSERT INTO distributed_table VALUES (1, '1', 20); -INSERT INTO second_distributed_table VALUES (1, '1'); --- a simple test for -CREATE TABLE collections_list ( - key bigserial, - ser bigserial, - ts timestamptz, - collection_id integer, - value numeric, - PRIMARY KEY(key, collection_id) -) PARTITION BY LIST (collection_id ); -SELECT create_distributed_table('collections_list', 'key'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -CREATE TABLE collections_list_0 - PARTITION OF collections_list (key, ser, ts, collection_id, value) - FOR VALUES IN ( 0 ); --- create a volatile function that returns the local node id -CREATE OR REPLACE FUNCTION get_local_node_id_volatile() -RETURNS INT AS $$ -DECLARE localGroupId int; -BEGIN - SELECT groupid INTO localGroupId FROM pg_dist_local_group; - RETURN localGroupId; -END; $$ language plpgsql VOLATILE; -SELECT create_distributed_function('get_local_node_id_volatile()'); -NOTICE: procedure local_shard_execution.get_local_node_id_volatile is already distributed -DETAIL: Citus distributes procedures with CREATE [PROCEDURE|FUNCTION|AGGREGATE] commands - create_distributed_function ---------------------------------------------------------------------- - -(1 row) - --- test case for issue #3556 -CREATE TABLE accounts (id text PRIMARY KEY); -CREATE TABLE stats (account_id text PRIMARY KEY, spent int); -SELECT create_distributed_table('accounts', 'id', colocate_with => 'none'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -SELECT create_distributed_table('stats', 'account_id', colocate_with => 'accounts'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO accounts (id) VALUES ('foo'); -INSERT INTO stats (account_id, spent) VALUES ('foo', 100); -CREATE TABLE abcd(a int, b int, c int, d int); -SELECT create_distributed_table('abcd', 'b'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO abcd VALUES (1,2,3,4); -INSERT INTO abcd VALUES (2,3,4,5); -INSERT INTO abcd VALUES (3,4,5,6); -ALTER TABLE abcd DROP COLUMN a; --- connection worker and get ready for the tests -\c - - - :worker_1_port -SET search_path TO local_shard_execution; -SET citus.enable_unique_job_ids TO off; --- returns true of the distribution key filter --- on the distributed tables (e.g., WHERE key = 1), we'll hit a shard --- placement which is local to this not -SET citus.enable_metadata_sync TO OFF; -CREATE OR REPLACE FUNCTION shard_of_distribution_column_is_local(dist_key int) RETURNS bool AS $$ - - DECLARE shard_is_local BOOLEAN := FALSE; - - BEGIN - - WITH local_shard_ids AS (SELECT get_shard_id_for_distribution_column('local_shard_execution.distributed_table', dist_key)), - all_local_shard_ids_on_node AS (SELECT shardid FROM pg_dist_placement WHERE groupid IN (SELECT groupid FROM pg_dist_local_group)) - SELECT - true INTO shard_is_local - FROM - local_shard_ids - WHERE - get_shard_id_for_distribution_column IN (SELECT * FROM all_local_shard_ids_on_node); - - IF shard_is_local IS NULL THEN - shard_is_local = FALSE; - END IF; - - RETURN shard_is_local; - END; -$$ LANGUAGE plpgsql; -RESET citus.enable_metadata_sync; --- test case for issue #3556 -SET citus.log_intermediate_results TO TRUE; -SET client_min_messages TO DEBUG1; -SELECT * -FROM -( - WITH accounts_cte AS ( - SELECT id AS account_id - FROM accounts - ), - joined_stats_cte_1 AS ( - SELECT spent, account_id - FROM stats - INNER JOIN accounts_cte USING (account_id) - ), - joined_stats_cte_2 AS ( - SELECT spent, account_id - FROM joined_stats_cte_1 - INNER JOIN accounts_cte USING (account_id) - ) - SELECT SUM(spent) OVER (PARTITION BY coalesce(account_id, NULL)) - FROM accounts_cte - INNER JOIN joined_stats_cte_2 USING (account_id) -) inner_query; -DEBUG: CTE joined_stats_cte_1 is going to be inlined via distributed planning -DEBUG: CTE joined_stats_cte_2 is going to be inlined via distributed planning -DEBUG: generating subplan XXX_1 for CTE accounts_cte: SELECT id AS account_id FROM local_shard_execution.accounts -DEBUG: generating subplan XXX_2 for subquery SELECT sum(joined_stats_cte_2.spent) OVER (PARTITION BY COALESCE(accounts_cte.account_id, NULL::text)) AS sum FROM ((SELECT intermediate_result.account_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(account_id text)) accounts_cte JOIN (SELECT joined_stats_cte_1.spent, joined_stats_cte_1.account_id FROM ((SELECT stats.spent, stats.account_id FROM (local_shard_execution.stats JOIN (SELECT intermediate_result.account_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(account_id text)) accounts_cte_2 USING (account_id))) joined_stats_cte_1 JOIN (SELECT intermediate_result.account_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(account_id text)) accounts_cte_1 USING (account_id))) joined_stats_cte_2 USING (account_id)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT sum FROM (SELECT intermediate_result.sum FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(sum bigint)) inner_query -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be written to local file - sum ---------------------------------------------------------------------- - 100 -(1 row) - -SET citus.log_intermediate_results TO DEFAULT; -SET client_min_messages TO DEFAULT; --- pick some example values that reside on the shards locally and remote --- distribution key values of 1,6, 500 and 701 are LOCAL to shards, --- we'll use these values in the tests -SELECT shard_of_distribution_column_is_local(1); - shard_of_distribution_column_is_local ---------------------------------------------------------------------- - t -(1 row) - -SELECT shard_of_distribution_column_is_local(6); - shard_of_distribution_column_is_local ---------------------------------------------------------------------- - t -(1 row) - -SELECT shard_of_distribution_column_is_local(500); - shard_of_distribution_column_is_local ---------------------------------------------------------------------- - t -(1 row) - -SELECT shard_of_distribution_column_is_local(701); - shard_of_distribution_column_is_local ---------------------------------------------------------------------- - t -(1 row) - --- distribution key values of 11 and 12 are REMOTE to shards -SELECT shard_of_distribution_column_is_local(11); - shard_of_distribution_column_is_local ---------------------------------------------------------------------- - f -(1 row) - -SELECT shard_of_distribution_column_is_local(12); - shard_of_distribution_column_is_local ---------------------------------------------------------------------- - f -(1 row) - ---- enable logging to see which tasks are executed locally -SET citus.log_local_commands TO ON; --- first, make sure that local execution works fine --- with simple queries that are not in transcation blocks -SELECT count(*) FROM distributed_table WHERE key = 1; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - --- multiple tasks both of which are local should NOT use local execution --- because local execution means executing the tasks locally, so the executor --- favors parallel execution even if everyting is local to node -SELECT count(*) FROM distributed_table WHERE key IN (1,6); - count ---------------------------------------------------------------------- - 1 -(1 row) - --- queries that hit any remote shards should NOT use local execution -SELECT count(*) FROM distributed_table WHERE key IN (1,11); - count ---------------------------------------------------------------------- - 1 -(1 row) - -SELECT count(*) FROM distributed_table; - count ---------------------------------------------------------------------- - 1 -(1 row) - --- modifications also follow the same rules -INSERT INTO reference_table VALUES (1) ON CONFLICT DO NOTHING; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 AS citus_table_alias (key) VALUES (1) ON CONFLICT DO NOTHING -INSERT INTO distributed_table VALUES (1, '1', 21) ON CONFLICT DO NOTHING; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '1'::text, 21) ON CONFLICT DO NOTHING --- local query -DELETE FROM distributed_table WHERE key = 1 AND age = 21; -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((key OPERATOR(pg_catalog.=) 1) AND (age OPERATOR(pg_catalog.=) 21)) --- hitting multiple shards, so should be a distributed execution -DELETE FROM distributed_table WHERE age = 21; --- although both shards are local, the executor choose the parallel execution --- over the wire because as noted above local execution is sequential -DELETE FROM second_distributed_table WHERE key IN (1,6); --- similarly, any multi-shard query just follows distributed execution -DELETE FROM second_distributed_table; --- load some more data for the following tests -INSERT INTO second_distributed_table VALUES (1, '1'); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.second_distributed_table_1470005 (key, value) VALUES (1, '1'::text) --- INSERT .. SELECT hitting a single single (co-located) shard(s) should --- be executed locally -INSERT INTO distributed_table -SELECT - distributed_table.* -FROM - distributed_table, second_distributed_table -WHERE - distributed_table.key = 1 and distributed_table.key=second_distributed_table.key -ON CONFLICT(key) DO UPDATE SET value = '22' -RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution.distributed_table_1470001 distributed_table, local_shard_execution.second_distributed_table_1470005 second_distributed_table WHERE (((distributed_table.key OPERATOR(pg_catalog.=) 1) AND (distributed_table.key OPERATOR(pg_catalog.=) second_distributed_table.key)) AND (distributed_table.key IS NOT NULL)) ON CONFLICT(key) DO UPDATE SET value = '22'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age - key | value | age ---------------------------------------------------------------------- - 1 | 22 | 20 -(1 row) - --- INSERT .. SELECT hitting multi-shards should go thourgh distributed execution -INSERT INTO distributed_table -SELECT - distributed_table.* -FROM - distributed_table, second_distributed_table -WHERE - distributed_table.key != 1 and distributed_table.key=second_distributed_table.key -ON CONFLICT(key) DO UPDATE SET value = '22' -RETURNING *; - key | value | age ---------------------------------------------------------------------- -(0 rows) - --- INSERT..SELECT via coordinator consists of two steps, select + COPY --- that's why it is disallowed to use local execution even if the SELECT --- can be executed locally -INSERT INTO distributed_table SELECT sum(key), value FROM distributed_table WHERE key = 1 GROUP BY value ON CONFLICT DO NOTHING; -NOTICE: executing the command locally: SELECT int4(sum(key)) AS key, value FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) GROUP BY value -NOTICE: executing the copy locally for colocated file with shard xxxxx -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value) SELECT key, value FROM read_intermediate_result('insert_select_XXX_1470001'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text) ON CONFLICT DO NOTHING -INSERT INTO distributed_table SELECT 1, '1',15 FROM distributed_table WHERE key = 2 LIMIT 1 ON CONFLICT DO NOTHING; --- sanity check: multi-shard INSERT..SELECT pushdown goes through distributed execution -INSERT INTO distributed_table SELECT * FROM distributed_table ON CONFLICT DO NOTHING; --- Ensure tuple data in explain analyze output is the same on all PG versions -SET citus.enable_binary_protocol = TRUE; --- EXPLAIN for local execution just works fine --- though going through distributed execution -EXPLAIN (COSTS OFF) SELECT * FROM distributed_table WHERE key = 1 AND age = 20; - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus Adaptive) - Task Count: 1 - Tasks Shown: All - -> Task - Node: host=localhost port=xxxxx dbname=regression - -> Index Scan using distributed_table_pkey_1470001 on distributed_table_1470001 distributed_table - Index Cond: (key = 1) - Filter: (age = 20) -(8 rows) - -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) SELECT * FROM distributed_table WHERE key = 1 AND age = 20; - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus Adaptive) (actual rows=1 loops=1) - Task Count: 1 - Tuple data received from nodes: 14 bytes - Tasks Shown: All - -> Task - Tuple data received from node: 14 bytes - Node: host=localhost port=xxxxx dbname=regression - -> Index Scan using distributed_table_pkey_1470001 on distributed_table_1470001 distributed_table (actual rows=1 loops=1) - Index Cond: (key = 1) - Filter: (age = 20) -(10 rows) - -EXPLAIN (ANALYZE ON, COSTS OFF, SUMMARY OFF, TIMING OFF) -WITH r AS ( SELECT GREATEST(random(), 2) z,* FROM distributed_table) -SELECT 1 FROM r WHERE z < 3; - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus Adaptive) (actual rows=1 loops=1) - -> Distributed Subplan XXX_1 - Intermediate Data Size: 40 bytes - Result destination: Write locally - -> Custom Scan (Citus Adaptive) (actual rows=1 loops=1) - Task Count: 4 - Tuple data received from nodes: 22 bytes - Tasks Shown: One of 4 - -> Task - Tuple data received from node: 22 bytes - Node: host=localhost port=xxxxx dbname=regression - -> Seq Scan on distributed_table_1470001 distributed_table (actual rows=1 loops=1) - Task Count: 1 - Tuple data received from nodes: 4 bytes - Tasks Shown: All - -> Task - Tuple data received from node: 4 bytes - Node: host=localhost port=xxxxx dbname=regression - -> Function Scan on read_intermediate_result intermediate_result (actual rows=1 loops=1) - Filter: (z < '3'::double precision) -(20 rows) - -EXPLAIN (COSTS OFF) DELETE FROM distributed_table WHERE key = 1 AND age = 20; - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus Adaptive) - Task Count: 1 - Tasks Shown: All - -> Task - Node: host=localhost port=xxxxx dbname=regression - -> Delete on distributed_table_1470001 distributed_table - -> Index Scan using distributed_table_pkey_1470001 on distributed_table_1470001 distributed_table - Index Cond: (key = 1) - Filter: (age = 20) -(9 rows) - -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) DELETE FROM distributed_table WHERE key = 1 AND age = 20; - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus Adaptive) (actual rows=0 loops=1) - Task Count: 1 - Tasks Shown: All - -> Task - Node: host=localhost port=xxxxx dbname=regression - -> Delete on distributed_table_1470001 distributed_table (actual rows=0 loops=1) - -> Index Scan using distributed_table_pkey_1470001 on distributed_table_1470001 distributed_table (actual rows=1 loops=1) - Index Cond: (key = 1) - Filter: (age = 20) - Trigger for constraint second_distributed_table_key_fkey_1470005: calls=1 -(10 rows) - --- show that EXPLAIN ANALYZE deleted the row and cascades deletes -SELECT * FROM distributed_table WHERE key = 1 AND age = 20 ORDER BY 1,2,3; -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((key OPERATOR(pg_catalog.=) 1) AND (age OPERATOR(pg_catalog.=) 20)) ORDER BY key, value, age - key | value | age ---------------------------------------------------------------------- -(0 rows) - -SELECT * FROM second_distributed_table WHERE key = 1 ORDER BY 1,2; -NOTICE: executing the command locally: SELECT key, value FROM local_shard_execution.second_distributed_table_1470005 second_distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value - key | value ---------------------------------------------------------------------- -(0 rows) - --- Put rows back for other tests -INSERT INTO distributed_table VALUES (1, '22', 20); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 (key, value, age) VALUES (1, '22'::text, 20) -INSERT INTO second_distributed_table VALUES (1, '1'); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.second_distributed_table_1470005 (key, value) VALUES (1, '1'::text) -SET citus.enable_ddl_propagation TO OFF; -CREATE VIEW abcd_view AS SELECT * FROM abcd; -RESET citus.enable_ddl_propagation; -SELECT * FROM abcd first join abcd second on first.b = second.b ORDER BY 1,2,3,4; - b | c | d | b | c | d ---------------------------------------------------------------------- - 2 | 3 | 4 | 2 | 3 | 4 - 3 | 4 | 5 | 3 | 4 | 5 - 4 | 5 | 6 | 4 | 5 | 6 -(3 rows) - -BEGIN; -SELECT * FROM abcd first join abcd second on first.b = second.b ORDER BY 1,2,3,4; -NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.b, second.c, second.d FROM (local_shard_execution.abcd_1470025 first JOIN local_shard_execution.abcd_1470025 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) WHERE true -NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.b, second.c, second.d FROM (local_shard_execution.abcd_1470027 first JOIN local_shard_execution.abcd_1470027 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) WHERE true - b | c | d | b | c | d ---------------------------------------------------------------------- - 2 | 3 | 4 | 2 | 3 | 4 - 3 | 4 | 5 | 3 | 4 | 5 - 4 | 5 | 6 | 4 | 5 | 6 -(3 rows) - -END; -BEGIN; -SELECT * FROM abcd_view first join abcd_view second on first.b = second.b ORDER BY 1,2,3,4; -NOTICE: executing the command locally: SELECT abcd.b, abcd.c, abcd.d, abcd_1.b, abcd_1.c, abcd_1.d FROM (local_shard_execution.abcd_1470025 abcd JOIN local_shard_execution.abcd_1470025 abcd_1 ON ((abcd.b OPERATOR(pg_catalog.=) abcd_1.b))) WHERE true -NOTICE: executing the command locally: SELECT abcd.b, abcd.c, abcd.d, abcd_1.b, abcd_1.c, abcd_1.d FROM (local_shard_execution.abcd_1470027 abcd JOIN local_shard_execution.abcd_1470027 abcd_1 ON ((abcd.b OPERATOR(pg_catalog.=) abcd_1.b))) WHERE true - b | c | d | b | c | d ---------------------------------------------------------------------- - 2 | 3 | 4 | 2 | 3 | 4 - 3 | 4 | 5 | 3 | 4 | 5 - 4 | 5 | 6 | 4 | 5 | 6 -(3 rows) - -END; -BEGIN; -SELECT * FROM abcd first full join abcd second on first.b = second.b ORDER BY 1,2,3,4; -NOTICE: executing the command locally: SELECT worker_column_1 AS b, worker_column_2 AS c, worker_column_3 AS d, worker_column_4 AS b, worker_column_5 AS c, worker_column_6 AS d FROM (SELECT first.b AS worker_column_1, first.c AS worker_column_2, first.d AS worker_column_3, second.b AS worker_column_4, second.c AS worker_column_5, second.d AS worker_column_6 FROM (local_shard_execution.abcd_1470025 first FULL JOIN local_shard_execution.abcd_1470025 second ON ((first.b OPERATOR(pg_catalog.=) second.b)))) worker_subquery -NOTICE: executing the command locally: SELECT worker_column_1 AS b, worker_column_2 AS c, worker_column_3 AS d, worker_column_4 AS b, worker_column_5 AS c, worker_column_6 AS d FROM (SELECT first.b AS worker_column_1, first.c AS worker_column_2, first.d AS worker_column_3, second.b AS worker_column_4, second.c AS worker_column_5, second.d AS worker_column_6 FROM (local_shard_execution.abcd_1470027 first FULL JOIN local_shard_execution.abcd_1470027 second ON ((first.b OPERATOR(pg_catalog.=) second.b)))) worker_subquery - b | c | d | b | c | d ---------------------------------------------------------------------- - 2 | 3 | 4 | 2 | 3 | 4 - 3 | 4 | 5 | 3 | 4 | 5 - 4 | 5 | 6 | 4 | 5 | 6 -(3 rows) - -END; -BEGIN; -SELECT * FROM abcd first join abcd second USING(b) ORDER BY 1,2,3,4; -NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.c, second.d FROM (local_shard_execution.abcd_1470025 first JOIN local_shard_execution.abcd_1470025 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) WHERE true -NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.c, second.d FROM (local_shard_execution.abcd_1470027 first JOIN local_shard_execution.abcd_1470027 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) WHERE true - b | c | d | c | d ---------------------------------------------------------------------- - 2 | 3 | 4 | 3 | 4 - 3 | 4 | 5 | 4 | 5 - 4 | 5 | 6 | 5 | 6 -(3 rows) - -END; -BEGIN; -SELECT * FROM abcd first join abcd second USING(b) join abcd third on first.b=third.b ORDER BY 1,2,3,4; -NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.c, second.d, third.b, third.c, third.d FROM ((local_shard_execution.abcd_1470025 first JOIN local_shard_execution.abcd_1470025 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) JOIN local_shard_execution.abcd_1470025 third ON ((first.b OPERATOR(pg_catalog.=) third.b))) WHERE true -NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.c, second.d, third.b, third.c, third.d FROM ((local_shard_execution.abcd_1470027 first JOIN local_shard_execution.abcd_1470027 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) JOIN local_shard_execution.abcd_1470027 third ON ((first.b OPERATOR(pg_catalog.=) third.b))) WHERE true - b | c | d | c | d | b | c | d ---------------------------------------------------------------------- - 2 | 3 | 4 | 3 | 4 | 2 | 3 | 4 - 3 | 4 | 5 | 4 | 5 | 3 | 4 | 5 - 4 | 5 | 6 | 5 | 6 | 4 | 5 | 6 -(3 rows) - -END; --- copy always happens via distributed execution irrespective of the --- shards that are accessed -COPY reference_table FROM STDIN; -COPY distributed_table FROM STDIN WITH CSV; -COPY second_distributed_table FROM STDIN WITH CSV; --- the behaviour in transaction blocks is the following: - -- (a) Unless the first query is a local query, always use distributed execution. - -- (b) If the executor has used local execution, it has to use local execution - -- for the remaining of the transaction block. If that's not possible, the - -- executor has to error out --- rollback should be able to rollback local execution -BEGIN; - INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age - key | value | age ---------------------------------------------------------------------- - 1 | 29 | 20 -(1 row) - - SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3; -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age - key | value | age ---------------------------------------------------------------------- - 1 | 29 | 20 -(1 row) - -ROLLBACK; --- make sure that the value is rollbacked -SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3; -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age - key | value | age ---------------------------------------------------------------------- - 1 | 22 | 20 -(1 row) - --- rollback should be able to rollback both the local and distributed executions -BEGIN; - INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age - key | value | age ---------------------------------------------------------------------- - 1 | 29 | 20 -(1 row) - - DELETE FROM distributed_table; -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table - -- DELETE should cascade, and we should not see any rows - SELECT count(*) FROM second_distributed_table; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.second_distributed_table_1470005 second_distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.second_distributed_table_1470007 second_distributed_table WHERE true - count ---------------------------------------------------------------------- - 0 -(1 row) - -ROLLBACK; --- make sure that everything is rollbacked -SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3; -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age - key | value | age ---------------------------------------------------------------------- - 1 | 22 | 20 -(1 row) - -SELECT count(*) FROM second_distributed_table; - count ---------------------------------------------------------------------- - 2 -(1 row) - -SELECT * FROM second_distributed_table ORDER BY 1; - key | value ---------------------------------------------------------------------- - 1 | 1 - 6 | '6' -(2 rows) - --- very simple examples, an SELECTs should see the modifications --- that has done before -BEGIN; - -- INSERT is executed locally - INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '23' RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '23'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age - key | value | age ---------------------------------------------------------------------- - 1 | 23 | 20 -(1 row) - - -- since the INSERT is executed locally, the SELECT should also be - -- executed locally and see the changes - SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3; -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age - key | value | age ---------------------------------------------------------------------- - 1 | 23 | 20 -(1 row) - - -- multi-shard SELECTs are now forced to use local execution on - -- the shards that reside on this node - SELECT * FROM distributed_table WHERE value = '23' ORDER BY 1,2,3; -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) - key | value | age ---------------------------------------------------------------------- - 1 | 23 | 20 -(1 row) - - -- similarly, multi-shard modifications should use local exection - -- on the shards that reside on this node - DELETE FROM distributed_table WHERE value = '23'; -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) - -- make sure that the value is deleted - SELECT * FROM distributed_table WHERE value = '23' ORDER BY 1,2,3; -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) - key | value | age ---------------------------------------------------------------------- -(0 rows) - -COMMIT; --- make sure that we've committed everything -SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3; -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age - key | value | age ---------------------------------------------------------------------- -(0 rows) - --- if we start with a distributed execution, we should keep --- using that and never switch back to local execution -BEGIN; - DELETE FROM distributed_table WHERE value = '11'; -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (value OPERATOR(pg_catalog.=) '11'::text) -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (value OPERATOR(pg_catalog.=) '11'::text) - -- although this command could have been executed - -- locally, it is not going to be executed locally - SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3; -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age - key | value | age ---------------------------------------------------------------------- -(0 rows) - - -- but we can still execute parallel queries, even if - -- they are utility commands - TRUNCATE distributed_table CASCADE; -NOTICE: truncate cascades to table "second_distributed_table" -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.distributed_table_xxxxx CASCADE -NOTICE: truncate cascades to table "second_distributed_table_xxxxx" -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.distributed_table_xxxxx CASCADE -NOTICE: truncate cascades to table "second_distributed_table_xxxxx" -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.second_distributed_table_xxxxx CASCADE -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.second_distributed_table_xxxxx CASCADE - -- TRUNCATE cascaded into second_distributed_table - SELECT count(*) FROM second_distributed_table; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.second_distributed_table_1470005 second_distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.second_distributed_table_1470007 second_distributed_table WHERE true - count ---------------------------------------------------------------------- - 0 -(1 row) - -ROLLBACK; --- load some data so that foreign keys won't complain with the next tests -INSERT INTO reference_table SELECT i FROM generate_series(500, 600) i; -NOTICE: executing the copy locally for shard xxxxx --- show that cascading foreign keys just works fine with local execution -BEGIN; - INSERT INTO reference_table VALUES (701); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 (key) VALUES (701) - INSERT INTO distributed_table VALUES (701, '701', 701); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 (key, value, age) VALUES (701, '701'::text, 701) - INSERT INTO second_distributed_table VALUES (701, '701'); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.second_distributed_table_1470005 (key, value) VALUES (701, '701'::text) - DELETE FROM reference_table WHERE key = 701; -NOTICE: executing the command locally: DELETE FROM local_shard_execution.reference_table_1470000 reference_table WHERE (key OPERATOR(pg_catalog.=) 701) - SELECT count(*) FROM distributed_table WHERE key = 701; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 701) - count ---------------------------------------------------------------------- - 0 -(1 row) - - SELECT count(*) FROM second_distributed_table WHERE key = 701; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.second_distributed_table_1470005 second_distributed_table WHERE (key OPERATOR(pg_catalog.=) 701) - count ---------------------------------------------------------------------- - 0 -(1 row) - - -- multi-shard commands should also see the changes - SELECT count(*) FROM distributed_table WHERE key > 700; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.>) 700) -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.>) 700) - count ---------------------------------------------------------------------- - 0 -(1 row) - - -- we can still do multi-shard commands - DELETE FROM distributed_table; -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table -ROLLBACK; --- multiple queries hitting different shards can be executed locally -BEGIN; - SELECT count(*) FROM distributed_table WHERE key = 1; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 0 -(1 row) - - SELECT count(*) FROM distributed_table WHERE key = 6; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6) - count ---------------------------------------------------------------------- - 1 -(1 row) - - SELECT count(*) FROM distributed_table WHERE key = 500; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) - count ---------------------------------------------------------------------- - 0 -(1 row) - -ROLLBACK; --- a local query followed by TRUNCATE command can be executed locally -BEGIN; - SELECT count(*) FROM distributed_table WHERE key = 1; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 0 -(1 row) - - TRUNCATE distributed_table CASCADE; -NOTICE: truncate cascades to table "second_distributed_table" -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.distributed_table_xxxxx CASCADE -NOTICE: truncate cascades to table "second_distributed_table_xxxxx" -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.distributed_table_xxxxx CASCADE -NOTICE: truncate cascades to table "second_distributed_table_xxxxx" -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.second_distributed_table_xxxxx CASCADE -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.second_distributed_table_xxxxx CASCADE -ROLLBACK; --- a local query is followed by an INSERT..SELECT via the coordinator -BEGIN; - SELECT count(*) FROM distributed_table WHERE key = 1; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 0 -(1 row) - - INSERT INTO distributed_table (key) SELECT i FROM generate_series(1,1) i; -NOTICE: executing the copy locally for shard xxxxx -ROLLBACK; -BEGIN; -SET citus.enable_repartition_joins TO ON; -SELECT count(*) FROM distributed_table; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE true - count ---------------------------------------------------------------------- - 2 -(1 row) - -SELECT count(*) FROM distributed_table d1 join distributed_table d2 using(age); -NOTICE: executing the command locally: SELECT partition_index, 'repartition_70_1' || '_' || partition_index::text , rows_written FROM pg_catalog.worker_partition_query_result('repartition_70_1','SELECT age AS column1 FROM local_shard_execution.distributed_table_1470001 d1 WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true,true,true) WHERE rows_written > 0 -NOTICE: executing the command locally: SELECT partition_index, 'repartition_70_3' || '_' || partition_index::text , rows_written FROM pg_catalog.worker_partition_query_result('repartition_70_3','SELECT age AS column1 FROM local_shard_execution.distributed_table_1470003 d1 WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true,true,true) WHERE rows_written > 0 -NOTICE: executing the command locally: SELECT partition_index, 'repartition_71_1' || '_' || partition_index::text , rows_written FROM pg_catalog.worker_partition_query_result('repartition_71_1','SELECT age AS column1 FROM local_shard_execution.distributed_table_1470001 d2 WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true,true,true) WHERE rows_written > 0 -NOTICE: executing the command locally: SELECT partition_index, 'repartition_71_3' || '_' || partition_index::text , rows_written FROM pg_catalog.worker_partition_query_result('repartition_71_3','SELECT age AS column1 FROM local_shard_execution.distributed_table_1470003 d2 WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true,true,true) WHERE rows_written > 0 -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_1_0']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_2_0']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_3_0']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_4_0']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_71_1_0']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_71_2_0']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_71_3_0']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_71_4_0']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_1_1']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_2_1']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_3_1']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_4_1']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_71_1_1']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_71_2_1']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_71_3_1']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_71_4_1']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_1_2']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_2_2']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_3_2']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_4_2']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_71_1_2']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_71_2_2']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_71_3_2']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_71_4_2']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_1_3']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_2_3']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_3_3']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_4_3']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_71_1_3']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_71_2_3']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_71_3_3']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_71_4_3']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT count(*) AS count FROM (read_intermediate_results('{repartition_70_1_0,repartition_70_2_0,repartition_70_3_0,repartition_70_4_0}'::text[], 'binary'::citus_copy_format) intermediate_result(column1 bigint) JOIN read_intermediate_results('{repartition_71_1_0,repartition_71_2_0,repartition_71_3_0,repartition_71_4_0}'::text[], 'binary'::citus_copy_format) intermediate_result_1(column1 bigint) ON ((intermediate_result.column1 OPERATOR(pg_catalog.=) intermediate_result_1.column1))) WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM (read_intermediate_results('{repartition_70_1_1,repartition_70_2_1,repartition_70_3_1,repartition_70_4_1}'::text[], 'binary'::citus_copy_format) intermediate_result(column1 bigint) JOIN read_intermediate_results('{repartition_71_1_1,repartition_71_2_1,repartition_71_3_1,repartition_71_4_1}'::text[], 'binary'::citus_copy_format) intermediate_result_1(column1 bigint) ON ((intermediate_result.column1 OPERATOR(pg_catalog.=) intermediate_result_1.column1))) WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM (read_intermediate_results('{repartition_70_1_2,repartition_70_2_2,repartition_70_3_2,repartition_70_4_2}'::text[], 'binary'::citus_copy_format) intermediate_result(column1 bigint) JOIN read_intermediate_results('{repartition_71_1_2,repartition_71_2_2,repartition_71_3_2,repartition_71_4_2}'::text[], 'binary'::citus_copy_format) intermediate_result_1(column1 bigint) ON ((intermediate_result.column1 OPERATOR(pg_catalog.=) intermediate_result_1.column1))) WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM (read_intermediate_results('{repartition_70_1_3,repartition_70_2_3,repartition_70_3_3,repartition_70_4_3}'::text[], 'binary'::citus_copy_format) intermediate_result(column1 bigint) JOIN read_intermediate_results('{repartition_71_1_3,repartition_71_2_3,repartition_71_3_3,repartition_71_4_3}'::text[], 'binary'::citus_copy_format) intermediate_result_1(column1 bigint) ON ((intermediate_result.column1 OPERATOR(pg_catalog.=) intermediate_result_1.column1))) WHERE true - count ---------------------------------------------------------------------- - 2 -(1 row) - -ROLLBACK; --- a local query is followed by an INSERT..SELECT with re-partitioning -BEGIN; - SELECT count(*) FROM distributed_table WHERE key = 6; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6) - count ---------------------------------------------------------------------- - 1 -(1 row) - - INSERT INTO reference_table (key) SELECT -key FROM distributed_table; -NOTICE: executing the command locally: SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE true -NOTICE: executing the command locally: SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE true -NOTICE: executing the copy locally for shard xxxxx - INSERT INTO distributed_table (key) SELECT -key FROM distributed_table; -NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_1470001_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_1470001_to','SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true) WHERE rows_written > 0 -NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_1470003_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_1470003_to','SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true) WHERE rows_written > 0 -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key) SELECT key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1470003_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer) - SELECT count(*) FROM distributed_table WHERE key = -6; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) '-6'::integer) - count ---------------------------------------------------------------------- - 1 -(1 row) - -ROLLBACK; -INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age - key | value | age ---------------------------------------------------------------------- - 1 | 11 | 21 -(1 row) - -BEGIN; - DELETE FROM distributed_table WHERE key = 1; -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - EXPLAIN ANALYZE DELETE FROM distributed_table WHERE key = 1; -ERROR: cannot execute command because a local execution has accessed a placement in the transaction -DETAIL: Some parallel commands cannot be executed if a previous command has already been executed locally -HINT: Try re-running the transaction with "SET LOCAL citus.enable_local_execution TO OFF;" -ROLLBACK; -BEGIN; - INSERT INTO distributed_table VALUES (11, '111',29) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *; - key | value | age ---------------------------------------------------------------------- - 11 | 29 | 121 -(1 row) - - -- this is already disallowed on the nodes, adding it in case we - -- support DDLs from the worker nodes in the future - ALTER TABLE distributed_table ADD COLUMN x INT; -ERROR: operation is not allowed on this node -HINT: Connect to the coordinator and run it again. -ROLLBACK; -BEGIN; - INSERT INTO distributed_table VALUES (11, '111',29) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *; - key | value | age ---------------------------------------------------------------------- - 11 | 29 | 121 -(1 row) - - -- this is already disallowed because VACUUM cannot be executed in tx block - -- adding in case this is supported some day - VACUUM second_distributed_table; -ERROR: VACUUM cannot run inside a transaction block -ROLLBACK; --- make sure that functions can use local execution -SET citus.enable_metadata_sync TO OFF; -CREATE OR REPLACE PROCEDURE only_local_execution() AS $$ - DECLARE cnt INT; - BEGIN - INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'; - SELECT count(*) INTO cnt FROM distributed_table WHERE key = 1; - DELETE FROM distributed_table WHERE key = 1; - END; -$$ LANGUAGE plpgsql; -CALL only_local_execution(); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text -CONTEXT: SQL statement "INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'" -PL/pgSQL function only_local_execution() line XX at SQL statement -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) -CONTEXT: SQL statement "SELECT count(*) FROM distributed_table WHERE key = 1" -PL/pgSQL function only_local_execution() line XX at SQL statement -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) -CONTEXT: SQL statement "DELETE FROM distributed_table WHERE key = 1" -PL/pgSQL function only_local_execution() line XX at SQL statement --- insert a row that we need in the next tests -INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text --- make sure that functions can use local execution -CREATE OR REPLACE PROCEDURE only_local_execution_with_function_evaluation() AS $$ - DECLARE nodeId INT; - BEGIN - -- fast path router - SELECT get_local_node_id_volatile() INTO nodeId FROM distributed_table WHERE key = 1; - IF nodeId <= 0 THEN - RAISE NOTICE 'unexpected node id'; - END IF; - - -- regular router - SELECT get_local_node_id_volatile() INTO nodeId FROM distributed_table d1 JOIN distributed_table d2 USING (key) WHERE d1.key = 1; - IF nodeId <= 0 THEN - RAISE NOTICE 'unexpected node id'; - END IF; - END; -$$ LANGUAGE plpgsql; -CALL only_local_execution_with_function_evaluation(); -NOTICE: executing the command locally: SELECT local_shard_execution.get_local_node_id_volatile() AS get_local_node_id_volatile FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) -CONTEXT: SQL statement "SELECT get_local_node_id_volatile() FROM distributed_table WHERE key = 1" -PL/pgSQL function only_local_execution_with_function_evaluation() line XX at SQL statement -NOTICE: executing the command locally: SELECT local_shard_execution.get_local_node_id_volatile() AS get_local_node_id_volatile FROM (local_shard_execution.distributed_table_1470001 d1(key, value, age) JOIN local_shard_execution.distributed_table_1470001 d2(key, value, age) USING (key)) WHERE (d1.key OPERATOR(pg_catalog.=) 1) -CONTEXT: SQL statement "SELECT get_local_node_id_volatile() FROM distributed_table d1 JOIN distributed_table d2 USING (key) WHERE d1.key = 1" -PL/pgSQL function only_local_execution_with_function_evaluation() line XX at SQL statement -CREATE OR REPLACE PROCEDURE only_local_execution_with_params(int) AS $$ - DECLARE cnt INT; - BEGIN - INSERT INTO distributed_table VALUES ($1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'; - SELECT count(*) INTO cnt FROM distributed_table WHERE key = $1; - DELETE FROM distributed_table WHERE key = $1; - END; -$$ LANGUAGE plpgsql; -CALL only_local_execution_with_params(1); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '29'::text -CONTEXT: SQL statement "INSERT INTO distributed_table VALUES ($1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'" -PL/pgSQL function only_local_execution_with_params(integer) line XX at SQL statement -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) -CONTEXT: SQL statement "SELECT count(*) FROM distributed_table WHERE key = $1" -PL/pgSQL function only_local_execution_with_params(integer) line XX at SQL statement -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) -CONTEXT: SQL statement "DELETE FROM distributed_table WHERE key = $1" -PL/pgSQL function only_local_execution_with_params(integer) line XX at SQL statement -CREATE OR REPLACE PROCEDURE only_local_execution_with_function_evaluation_param(int) AS $$ - DECLARE nodeId INT; - BEGIN - -- fast path router - SELECT get_local_node_id_volatile() INTO nodeId FROM distributed_table WHERE key = $1; - IF nodeId <= 0 THEN - RAISE NOTICE 'unexpected node id'; - END IF; - - -- regular router - SELECT get_local_node_id_volatile() INTO nodeId FROM distributed_table d1 JOIN distributed_table d2 USING (key) WHERE d1.key = $1; - IF nodeId <= 0 THEN - RAISE NOTICE 'unexpected node id'; - END IF; - END; -$$ LANGUAGE plpgsql; -CALL only_local_execution_with_function_evaluation_param(1); -NOTICE: executing the command locally: SELECT local_shard_execution.get_local_node_id_volatile() AS get_local_node_id_volatile FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) -CONTEXT: SQL statement "SELECT get_local_node_id_volatile() FROM distributed_table WHERE key = $1" -PL/pgSQL function only_local_execution_with_function_evaluation_param(integer) line XX at SQL statement -NOTICE: executing the command locally: SELECT local_shard_execution.get_local_node_id_volatile() AS get_local_node_id_volatile FROM (local_shard_execution.distributed_table_1470001 d1(key, value, age) JOIN local_shard_execution.distributed_table_1470001 d2(key, value, age) USING (key)) WHERE (d1.key OPERATOR(pg_catalog.=) $1) -CONTEXT: SQL statement "SELECT get_local_node_id_volatile() FROM distributed_table d1 JOIN distributed_table d2 USING (key) WHERE d1.key = $1" -PL/pgSQL function only_local_execution_with_function_evaluation_param(integer) line XX at SQL statement -CREATE OR REPLACE PROCEDURE local_execution_followed_by_dist() AS $$ - DECLARE cnt INT; - BEGIN - INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'; - SELECT count(*) INTO cnt FROM distributed_table WHERE key = 1; - DELETE FROM distributed_table; - SELECT count(*) INTO cnt FROM distributed_table; - END; -$$ LANGUAGE plpgsql; -RESET citus.enable_metadata_sync; -CALL local_execution_followed_by_dist(); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text -CONTEXT: SQL statement "INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'" -PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) -CONTEXT: SQL statement "SELECT count(*) FROM distributed_table WHERE key = 1" -PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table -CONTEXT: SQL statement "DELETE FROM distributed_table" -PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table -CONTEXT: SQL statement "DELETE FROM distributed_table" -PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE true -CONTEXT: SQL statement "SELECT count(*) FROM distributed_table" -PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE true -CONTEXT: SQL statement "SELECT count(*) FROM distributed_table" -PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement --- test CTEs, including modifying CTEs -WITH local_insert AS (INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *), -distributed_local_mixed AS (SELECT * FROM reference_table WHERE key IN (SELECT key FROM local_insert)) -SELECT * FROM local_insert, distributed_local_mixed; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age -NOTICE: executing the command locally: SELECT key FROM local_shard_execution.reference_table_1470000 reference_table WHERE (key OPERATOR(pg_catalog.=) ANY (SELECT local_insert.key FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) local_insert)) -NOTICE: executing the command locally: SELECT local_insert.key, local_insert.value, local_insert.age, distributed_local_mixed.key FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) local_insert, (SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) distributed_local_mixed - key | value | age | key ---------------------------------------------------------------------- - 1 | 11 | 21 | 1 -(1 row) - --- since we start with parallel execution, we do not switch back to local execution in the --- latter CTEs -WITH distributed_local_mixed AS (SELECT * FROM distributed_table), -local_insert AS (INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *) -SELECT * FROM local_insert, distributed_local_mixed ORDER BY 1,2,3,4,5; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age -NOTICE: executing the command locally: SELECT worker_column_1 AS key, worker_column_2 AS value, worker_column_3 AS age, worker_column_4 AS key, worker_column_5 AS value, worker_column_6 AS age FROM (SELECT local_insert.key AS worker_column_1, local_insert.value AS worker_column_2, local_insert.age AS worker_column_3, distributed_local_mixed.key AS worker_column_4, distributed_local_mixed.value AS worker_column_5, distributed_local_mixed.age AS worker_column_6 FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) local_insert, (SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution.distributed_table_1470001 distributed_table) distributed_local_mixed) worker_subquery -NOTICE: executing the command locally: SELECT worker_column_1 AS key, worker_column_2 AS value, worker_column_3 AS age, worker_column_4 AS key, worker_column_5 AS value, worker_column_6 AS age FROM (SELECT local_insert.key AS worker_column_1, local_insert.value AS worker_column_2, local_insert.age AS worker_column_3, distributed_local_mixed.key AS worker_column_4, distributed_local_mixed.value AS worker_column_5, distributed_local_mixed.age AS worker_column_6 FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) local_insert, (SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution.distributed_table_1470003 distributed_table) distributed_local_mixed) worker_subquery - key | value | age | key | value | age ---------------------------------------------------------------------- - 1 | 29 | 21 | 1 | 11 | 21 -(1 row) - --- router CTE pushdown -WITH all_data AS (SELECT * FROM distributed_table WHERE key = 1) -SELECT - count(*) -FROM - distributed_table, all_data -WHERE - distributed_table.key = all_data.key AND distributed_table.key = 1; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table, (SELECT distributed_table_1.key, distributed_table_1.value, distributed_table_1.age FROM local_shard_execution.distributed_table_1470001 distributed_table_1 WHERE (distributed_table_1.key OPERATOR(pg_catalog.=) 1)) all_data WHERE ((distributed_table.key OPERATOR(pg_catalog.=) all_data.key) AND (distributed_table.key OPERATOR(pg_catalog.=) 1)) - count ---------------------------------------------------------------------- - 1 -(1 row) - -INSERT INTO reference_table VALUES (2); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 (key) VALUES (2) -INSERT INTO distributed_table VALUES (2, '29', 29); -INSERT INTO second_distributed_table VALUES (2, '29'); --- single shard that is not a local query followed by a local query -WITH all_data AS (SELECT * FROM second_distributed_table WHERE key = 2) -SELECT - distributed_table.key -FROM - distributed_table, all_data -WHERE - distributed_table.value = all_data.value AND distributed_table.key = 1 -ORDER BY - 1 DESC; -NOTICE: executing the command locally: SELECT distributed_table.key FROM local_shard_execution.distributed_table_1470001 distributed_table, (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) all_data WHERE ((distributed_table.value OPERATOR(pg_catalog.=) all_data.value) AND (distributed_table.key OPERATOR(pg_catalog.=) 1)) ORDER BY distributed_table.key DESC - key ---------------------------------------------------------------------- - 1 -(1 row) - --- multi-shard CTE is followed by a query which could be executed locally, but --- since the query started with a parallel query, it doesn't use local execution --- note that if we allow Postgres to inline the CTE (e.g., not have the EXISTS --- subquery), then it'd pushdown the filters and the query becomes single-shard, --- locally executable query -WITH all_data AS (SELECT * FROM distributed_table) -SELECT - count(*) -FROM - distributed_table, all_data -WHERE - distributed_table.key = all_data.key AND distributed_table.key = 1 - AND EXISTS (SELECT * FROM all_data); -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE true -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table, (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) all_data WHERE ((distributed_table.key OPERATOR(pg_catalog.=) all_data.key) AND (distributed_table.key OPERATOR(pg_catalog.=) 1) AND (EXISTS (SELECT all_data_1.key, all_data_1.value, all_data_1.age FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) all_data_1))) - count ---------------------------------------------------------------------- - 1 -(1 row) - --- in pg12, the following CTE can be inlined, still the query becomes --- a subquery that needs to be recursively planned and a parallel --- query, so do not use local execution -WITH all_data AS (SELECT age FROM distributed_table) -SELECT - count(*) -FROM - distributed_table, all_data -WHERE - distributed_table.key = all_data.age AND distributed_table.key = 1; -NOTICE: executing the command locally: SELECT age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE true -NOTICE: executing the command locally: SELECT age FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table, (SELECT intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(age bigint)) all_data WHERE ((distributed_table.key OPERATOR(pg_catalog.=) all_data.age) AND (distributed_table.key OPERATOR(pg_catalog.=) 1)) - count ---------------------------------------------------------------------- - 0 -(1 row) - --- get ready for the next commands -TRUNCATE reference_table, distributed_table, second_distributed_table; -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.reference_table_xxxxx CASCADE -NOTICE: truncate cascades to table "distributed_table_xxxxx" -NOTICE: truncate cascades to table "distributed_table_xxxxx" -NOTICE: truncate cascades to table "second_distributed_table_xxxxx" -NOTICE: truncate cascades to table "second_distributed_table_xxxxx" -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.distributed_table_xxxxx CASCADE -NOTICE: truncate cascades to table "second_distributed_table_xxxxx" -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.distributed_table_xxxxx CASCADE -NOTICE: truncate cascades to table "second_distributed_table_xxxxx" -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.second_distributed_table_xxxxx CASCADE -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.second_distributed_table_xxxxx CASCADE --- local execution of returning of reference tables -INSERT INTO reference_table VALUES (1),(2),(3),(4),(5),(6) RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 AS citus_table_alias (key) VALUES (1), (2), (3), (4), (5), (6) RETURNING citus_table_alias.key - key ---------------------------------------------------------------------- - 1 - 2 - 3 - 4 - 5 - 6 -(6 rows) - --- local execution of multi-row INSERTs -INSERT INTO distributed_table VALUES (1, '11',21), (5,'55',22) ON CONFLICT(key) DO UPDATE SET value = (EXCLUDED.value::int + 1)::text RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'11'::text,'21'::bigint), (5,'55'::text,'22'::bigint) ON CONFLICT(key) DO UPDATE SET value = (((excluded.value)::integer OPERATOR(pg_catalog.+) 1))::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age - key | value | age ---------------------------------------------------------------------- - 1 | 11 | 21 - 5 | 55 | 22 -(2 rows) - --- distributed execution of multi-rows INSERTs, where executor --- is smart enough to execute local tasks via local execution -INSERT INTO distributed_table VALUES (1, '11',21), (2,'22',22), (3,'33',33), (4,'44',44),(5,'55',55) ON CONFLICT(key) DO UPDATE SET value = (EXCLUDED.value::int + 1)::text RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'11'::text,'21'::bigint), (5,'55'::text,'55'::bigint) ON CONFLICT(key) DO UPDATE SET value = (((excluded.value)::integer OPERATOR(pg_catalog.+) 1))::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age - key | value | age ---------------------------------------------------------------------- - 1 | 12 | 21 - 2 | 22 | 22 - 3 | 33 | 33 - 4 | 44 | 44 - 5 | 56 | 22 -(5 rows) - -PREPARE local_prepare_no_param AS SELECT count(*) FROM distributed_table WHERE key = 1; -PREPARE local_prepare_no_param_subquery AS -SELECT DISTINCT trim(value) FROM ( - SELECT value FROM distributed_table - WHERE - key IN (1, 6, 500, 701) - AND (select 2) > random() - order by 1 - limit 2 - ) t; -PREPARE local_prepare_param (int) AS SELECT count(*) FROM distributed_table WHERE key = $1; -PREPARE remote_prepare_param (int) AS SELECT count(*) FROM distributed_table WHERE key != $1; -BEGIN; - -- 8 local execution without params - EXECUTE local_prepare_no_param; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - - EXECUTE local_prepare_no_param; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - - EXECUTE local_prepare_no_param; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - - EXECUTE local_prepare_no_param; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - - EXECUTE local_prepare_no_param; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - - EXECUTE local_prepare_no_param; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - - EXECUTE local_prepare_no_param; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - - EXECUTE local_prepare_no_param; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - - -- 8 local execution without params and some subqueries - EXECUTE local_prepare_no_param_subquery; -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT DISTINCT TRIM(BOTH FROM value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t - btrim ---------------------------------------------------------------------- - 12 -(1 row) - - EXECUTE local_prepare_no_param_subquery; -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT DISTINCT TRIM(BOTH FROM value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t - btrim ---------------------------------------------------------------------- - 12 -(1 row) - - EXECUTE local_prepare_no_param_subquery; -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT DISTINCT TRIM(BOTH FROM value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t - btrim ---------------------------------------------------------------------- - 12 -(1 row) - - EXECUTE local_prepare_no_param_subquery; -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT DISTINCT TRIM(BOTH FROM value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t - btrim ---------------------------------------------------------------------- - 12 -(1 row) - - EXECUTE local_prepare_no_param_subquery; -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT DISTINCT TRIM(BOTH FROM value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t - btrim ---------------------------------------------------------------------- - 12 -(1 row) - - EXECUTE local_prepare_no_param_subquery; -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT DISTINCT TRIM(BOTH FROM value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t - btrim ---------------------------------------------------------------------- - 12 -(1 row) - - EXECUTE local_prepare_no_param_subquery; -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT DISTINCT TRIM(BOTH FROM value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t - btrim ---------------------------------------------------------------------- - 12 -(1 row) - - EXECUTE local_prepare_no_param_subquery; -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT DISTINCT TRIM(BOTH FROM value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t - btrim ---------------------------------------------------------------------- - 12 -(1 row) - - -- 8 local executions with params - EXECUTE local_prepare_param(1); -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - - EXECUTE local_prepare_param(5); -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 5) - count ---------------------------------------------------------------------- - 1 -(1 row) - - EXECUTE local_prepare_param(6); -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6) - count ---------------------------------------------------------------------- - 0 -(1 row) - - EXECUTE local_prepare_param(1); -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - - EXECUTE local_prepare_param(5); -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 5) - count ---------------------------------------------------------------------- - 1 -(1 row) - - EXECUTE local_prepare_param(6); -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6) - count ---------------------------------------------------------------------- - 0 -(1 row) - - EXECUTE local_prepare_param(6); -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6) - count ---------------------------------------------------------------------- - 0 -(1 row) - - EXECUTE local_prepare_param(6); -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6) - count ---------------------------------------------------------------------- - 0 -(1 row) - - -- followed by a non-local execution - EXECUTE remote_prepare_param(1); -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 1) -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 1) - count ---------------------------------------------------------------------- - 4 -(1 row) - -COMMIT; -PREPARE local_insert_prepare_no_param AS INSERT INTO distributed_table VALUES (1+0*random(), '11',21::int) ON CONFLICT(key) DO UPDATE SET value = '29' || '28' RETURNING *, key + 1, value || '30', age * 15; -PREPARE local_insert_prepare_param (int) AS INSERT INTO distributed_table VALUES ($1+0*random(), '11',21::int) ON CONFLICT(key) DO UPDATE SET value = '29' || '28' RETURNING *, key + 1, value || '30', age * 15; -BEGIN; - -- 8 local execution without params - EXECUTE local_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 1 | 2928 | 21 | 2 | 292830 | 315 -(1 row) - - EXECUTE local_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 1 | 2928 | 21 | 2 | 292830 | 315 -(1 row) - - EXECUTE local_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 1 | 2928 | 21 | 2 | 292830 | 315 -(1 row) - - EXECUTE local_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 1 | 2928 | 21 | 2 | 292830 | 315 -(1 row) - - EXECUTE local_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 1 | 2928 | 21 | 2 | 292830 | 315 -(1 row) - - EXECUTE local_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 1 | 2928 | 21 | 2 | 292830 | 315 -(1 row) - - EXECUTE local_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 1 | 2928 | 21 | 2 | 292830 | 315 -(1 row) - - EXECUTE local_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 1 | 2928 | 21 | 2 | 292830 | 315 -(1 row) - - -- 8 local executions with params - EXECUTE local_insert_prepare_param(1); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 1 | 2928 | 21 | 2 | 292830 | 315 -(1 row) - - EXECUTE local_insert_prepare_param(5); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 5 | 2928 | 22 | 6 | 292830 | 330 -(1 row) - - EXECUTE local_insert_prepare_param(6); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 6 | 11 | 21 | 7 | 1130 | 315 -(1 row) - - EXECUTE local_insert_prepare_param(1); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 1 | 2928 | 21 | 2 | 292830 | 315 -(1 row) - - EXECUTE local_insert_prepare_param(5); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 5 | 2928 | 22 | 6 | 292830 | 330 -(1 row) - - EXECUTE local_insert_prepare_param(6); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 6 | 2928 | 21 | 7 | 292830 | 315 -(1 row) - - EXECUTE local_insert_prepare_param(6); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 6 | 2928 | 21 | 7 | 292830 | 315 -(1 row) - - EXECUTE local_insert_prepare_param(6); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 6 | 2928 | 21 | 7 | 292830 | 315 -(1 row) - - -- followed by a non-local execution - EXECUTE remote_prepare_param(2); -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 2) -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 2) - count ---------------------------------------------------------------------- - 5 -(1 row) - -COMMIT; -PREPARE local_multi_row_insert_prepare_no_param AS - INSERT INTO distributed_table VALUES (1,'55', 21), (5,'15',33) ON CONFLICT (key) WHERE key > 3 and key < 4 DO UPDATE SET value = '88' || EXCLUDED.value; -PREPARE local_multi_row_insert_prepare_no_param_multi_shard AS - INSERT INTO distributed_table VALUES (6,'55', 21), (5,'15',33) ON CONFLICT (key) WHERE key > 3 AND key < 4 DO UPDATE SET value = '88' || EXCLUDED.value;; -PREPARE local_multi_row_insert_prepare_params(int,int) AS - INSERT INTO distributed_table VALUES ($1,'55', 21), ($2,'15',33) ON CONFLICT (key) WHERE key > 3 and key < 4 DO UPDATE SET value = '88' || EXCLUDED.value;; -INSERT INTO reference_table VALUES (11); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 (key) VALUES (11) -BEGIN; - EXECUTE local_multi_row_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_params(1,6); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_params(1,5); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_params(6,5); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_params(5,1); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'55'::text,'21'::bigint), (1,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_params(5,6); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_params(5,1); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'55'::text,'21'::bigint), (1,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_params(1,6); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_params(1,5); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - -- one task is remote - EXECUTE local_multi_row_insert_prepare_params(5,11); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -ROLLBACK; --- make sure that we still get results if we switch off local execution -PREPARE ref_count_prepare AS SELECT count(*) FROM reference_table; -EXECUTE ref_count_prepare; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.reference_table_1470000 reference_table - count ---------------------------------------------------------------------- - 7 -(1 row) - -EXECUTE ref_count_prepare; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.reference_table_1470000 reference_table - count ---------------------------------------------------------------------- - 7 -(1 row) - -EXECUTE ref_count_prepare; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.reference_table_1470000 reference_table - count ---------------------------------------------------------------------- - 7 -(1 row) - -EXECUTE ref_count_prepare; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.reference_table_1470000 reference_table - count ---------------------------------------------------------------------- - 7 -(1 row) - -EXECUTE ref_count_prepare; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.reference_table_1470000 reference_table - count ---------------------------------------------------------------------- - 7 -(1 row) - -SET citus.enable_local_execution TO off; -EXECUTE ref_count_prepare; - count ---------------------------------------------------------------------- - 7 -(1 row) - -RESET citus.enable_local_execution; --- failures of local execution should rollback both the --- local execution and remote executions --- fail on a local execution -BEGIN; - INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '100' RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '100'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age - key | value | age ---------------------------------------------------------------------- - 1 | 100 | 21 -(1 row) - - UPDATE distributed_table SET value = '200'; -NOTICE: executing the command locally: UPDATE local_shard_execution.distributed_table_1470001 distributed_table SET value = '200'::text -NOTICE: executing the command locally: UPDATE local_shard_execution.distributed_table_1470003 distributed_table SET value = '200'::text - INSERT INTO distributed_table VALUES (1, '100',21) ON CONFLICT(key) DO UPDATE SET value = (1 / (100.0 - EXCLUDED.value::int))::text RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '100'::text, 21) ON CONFLICT(key) DO UPDATE SET value = (((1)::numeric OPERATOR(pg_catalog./) (100.0 OPERATOR(pg_catalog.-) ((excluded.value)::integer)::numeric)))::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age -ERROR: division by zero -ROLLBACK; --- we've rollbacked everything -SELECT count(*) FROM distributed_table WHERE value = '200'; - count ---------------------------------------------------------------------- - 0 -(1 row) - --- RETURNING should just work fine for reference tables -INSERT INTO reference_table VALUES (500) RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 (key) VALUES (500) RETURNING key - key ---------------------------------------------------------------------- - 500 -(1 row) - -DELETE FROM reference_table WHERE key = 500 RETURNING *; -NOTICE: executing the command locally: DELETE FROM local_shard_execution.reference_table_1470000 reference_table WHERE (key OPERATOR(pg_catalog.=) 500) RETURNING key - key ---------------------------------------------------------------------- - 500 -(1 row) - --- should be able to skip local execution even if in a sequential mode of execution -BEGIN; - SET LOCAL citus.multi_shard_modify_mode TO sequential ; - DELETE FROM distributed_table; -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table - INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '100' RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '100'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age - key | value | age ---------------------------------------------------------------------- - 1 | 11 | 21 -(1 row) - -ROLLBACK; --- sequential execution should just work fine after a local execution -BEGIN; - SET citus.multi_shard_modify_mode TO sequential ; - INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '100' RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '100'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age - key | value | age ---------------------------------------------------------------------- - 1 | 100 | 21 -(1 row) - - DELETE FROM distributed_table; -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table -ROLLBACK; --- load some data so that foreign keys won't complain with the next tests -TRUNCATE reference_table CASCADE; -NOTICE: truncate cascades to table "distributed_table" -NOTICE: truncate cascades to table "second_distributed_table" -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.reference_table_xxxxx CASCADE -NOTICE: truncate cascades to table "distributed_table_xxxxx" -NOTICE: truncate cascades to table "distributed_table_xxxxx" -NOTICE: truncate cascades to table "second_distributed_table_xxxxx" -NOTICE: truncate cascades to table "second_distributed_table_xxxxx" -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.distributed_table_xxxxx CASCADE -NOTICE: truncate cascades to table "second_distributed_table_xxxxx" -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.distributed_table_xxxxx CASCADE -NOTICE: truncate cascades to table "second_distributed_table_xxxxx" -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.second_distributed_table_xxxxx CASCADE -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.second_distributed_table_xxxxx CASCADE -INSERT INTO reference_table SELECT i FROM generate_series(500, 600) i; -NOTICE: executing the copy locally for shard xxxxx -INSERT INTO distributed_table SELECT i, i::text, i % 10 + 25 FROM generate_series(500, 600) i; -NOTICE: executing the copy locally for shard xxxxx -NOTICE: executing the copy locally for shard xxxxx --- show that both local, and mixed local-distributed executions --- calculate rows processed correctly -BEGIN; - DELETE FROM distributed_table WHERE key = 500; -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) - DELETE FROM distributed_table WHERE value != '123123213123213'; -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (value OPERATOR(pg_catalog.<>) '123123213123213'::text) -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (value OPERATOR(pg_catalog.<>) '123123213123213'::text) -ROLLBACK; -BEGIN; - DELETE FROM reference_table WHERE key = 500 RETURNING *; -NOTICE: executing the command locally: DELETE FROM local_shard_execution.reference_table_1470000 reference_table WHERE (key OPERATOR(pg_catalog.=) 500) RETURNING key - key ---------------------------------------------------------------------- - 500 -(1 row) - - DELETE FROM reference_table; -NOTICE: executing the command locally: DELETE FROM local_shard_execution.reference_table_1470000 reference_table -ROLLBACK; -BEGIN; - DELETE FROM distributed_table WHERE key = 500; -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) - SELECT count(*) FROM distributed_table; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE true - count ---------------------------------------------------------------------- - 100 -(1 row) - -ROLLBACK; -BEGIN; - SET LOCAL client_min_messages TO INFO; - SELECT count(*) FROM distributed_table; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE true - count ---------------------------------------------------------------------- - 101 -(1 row) - - SET LOCAL client_min_messages TO LOG; - DELETE FROM distributed_table WHERE key = 500; -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) -ROLLBACK; --- probably not a realistic case since views are not very --- well supported with MX -SET citus.enable_ddl_propagation TO OFF; -CREATE VIEW v_local_query_execution AS -SELECT * FROM distributed_table WHERE key = 500; -RESET citus.enable_ddl_propagation; -SELECT * FROM v_local_query_execution; -NOTICE: executing the command locally: SELECT key, value, age FROM (SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) 500)) v_local_query_execution - key | value | age ---------------------------------------------------------------------- - 500 | 500 | 25 -(1 row) - --- similar test, but this time the view itself is a non-local --- query, but the query on the view is local -SET citus.enable_ddl_propagation TO OFF; -CREATE VIEW v_local_query_execution_2 AS -SELECT * FROM distributed_table; -RESET citus.enable_ddl_propagation; -SELECT * FROM v_local_query_execution_2 WHERE key = 500; -NOTICE: executing the command locally: SELECT key, value, age FROM (SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution.distributed_table_1470003 distributed_table) v_local_query_execution_2 WHERE (key OPERATOR(pg_catalog.=) 500) - key | value | age ---------------------------------------------------------------------- - 500 | 500 | 25 -(1 row) - --- even if we switch from remote execution -> local execution, --- we are able to use remote execution after rollback -BEGIN; - SAVEPOINT my_savepoint; - SELECT count(*) FROM distributed_table; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE true - count ---------------------------------------------------------------------- - 101 -(1 row) - - DELETE FROM distributed_table WHERE key = 500; -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) - ROLLBACK TO SAVEPOINT my_savepoint; - DELETE FROM distributed_table WHERE key = 500; -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) -COMMIT; --- even if we switch from local execution -> remote execution, --- we are able to use local execution after rollback -BEGIN; - SAVEPOINT my_savepoint; - DELETE FROM distributed_table WHERE key = 500; -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) - SELECT count(*) FROM distributed_table; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE true - count ---------------------------------------------------------------------- - 100 -(1 row) - - ROLLBACK TO SAVEPOINT my_savepoint; - DELETE FROM distributed_table WHERE key = 500; -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) -COMMIT; --- sanity check: local execution on partitions -INSERT INTO collections_list (collection_id) VALUES (0) RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.collections_list_1470011 (key, ser, collection_id) VALUES ('3940649673949185'::bigint, '3940649673949185'::bigint, 0) RETURNING key, ser, ts, collection_id, value - key | ser | ts | collection_id | value ---------------------------------------------------------------------- - 3940649673949185 | 3940649673949185 | | 0 | -(1 row) - -BEGIN; - INSERT INTO collections_list (key, collection_id) VALUES (1,0); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.collections_list_1470009 (key, ser, collection_id) VALUES ('1'::bigint, '3940649673949186'::bigint, 0) - SELECT count(*) FROM collections_list_0 WHERE key = 1; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.collections_list_0_1470013 collections_list_0 WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - - SELECT count(*) FROM collections_list; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.collections_list_1470009 collections_list WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.collections_list_1470011 collections_list WHERE true - count ---------------------------------------------------------------------- - 2 -(1 row) - - SELECT * FROM collections_list ORDER BY 1,2,3,4; -NOTICE: executing the command locally: SELECT key, ser, ts, collection_id, value FROM local_shard_execution.collections_list_1470009 collections_list WHERE true -NOTICE: executing the command locally: SELECT key, ser, ts, collection_id, value FROM local_shard_execution.collections_list_1470011 collections_list WHERE true - key | ser | ts | collection_id | value ---------------------------------------------------------------------- - 1 | 3940649673949186 | | 0 | - 3940649673949185 | 3940649673949185 | | 0 | -(2 rows) - -COMMIT; -TRUNCATE collections_list; --- make sure that even if local execution is used, the sequence values --- are generated locally -SET citus.enable_ddl_propagation TO OFF; -ALTER SEQUENCE collections_list_key_seq NO MINVALUE NO MAXVALUE; -RESET citus.enable_ddl_propagation; -PREPARE serial_prepared_local AS INSERT INTO collections_list (collection_id) VALUES (0) RETURNING key, ser; -SELECT setval('collections_list_key_seq', 4); - setval ---------------------------------------------------------------------- - 4 -(1 row) - -EXECUTE serial_prepared_local; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.collections_list_1470009 (key, ser, collection_id) VALUES ('5'::bigint, '3940649673949187'::bigint, 0) RETURNING key, ser - key | ser ---------------------------------------------------------------------- - 5 | 3940649673949187 -(1 row) - -SELECT setval('collections_list_key_seq', 5); - setval ---------------------------------------------------------------------- - 5 -(1 row) - -EXECUTE serial_prepared_local; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.collections_list_1470011 (key, ser, collection_id) VALUES ('6'::bigint, '3940649673949188'::bigint, 0) RETURNING key, ser - key | ser ---------------------------------------------------------------------- - 6 | 3940649673949188 -(1 row) - -SELECT setval('collections_list_key_seq', 499); - setval ---------------------------------------------------------------------- - 499 -(1 row) - -EXECUTE serial_prepared_local; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.collections_list_1470011 (key, ser, collection_id) VALUES ('500'::bigint, '3940649673949189'::bigint, 0) RETURNING key, ser - key | ser ---------------------------------------------------------------------- - 500 | 3940649673949189 -(1 row) - -SELECT setval('collections_list_key_seq', 700); - setval ---------------------------------------------------------------------- - 700 -(1 row) - -EXECUTE serial_prepared_local; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.collections_list_1470009 (key, ser, collection_id) VALUES ('701'::bigint, '3940649673949190'::bigint, 0) RETURNING key, ser - key | ser ---------------------------------------------------------------------- - 701 | 3940649673949190 -(1 row) - -SELECT setval('collections_list_key_seq', 708); - setval ---------------------------------------------------------------------- - 708 -(1 row) - -EXECUTE serial_prepared_local; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.collections_list_1470011 (key, ser, collection_id) VALUES ('709'::bigint, '3940649673949191'::bigint, 0) RETURNING key, ser - key | ser ---------------------------------------------------------------------- - 709 | 3940649673949191 -(1 row) - -SELECT setval('collections_list_key_seq', 709); - setval ---------------------------------------------------------------------- - 709 -(1 row) - -EXECUTE serial_prepared_local; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.collections_list_1470009 (key, ser, collection_id) VALUES ('710'::bigint, '3940649673949192'::bigint, 0) RETURNING key, ser - key | ser ---------------------------------------------------------------------- - 710 | 3940649673949192 -(1 row) - --- get ready for the next executions -DELETE FROM collections_list WHERE key IN (5,6); -SELECT setval('collections_list_key_seq', 4); - setval ---------------------------------------------------------------------- - 4 -(1 row) - -EXECUTE serial_prepared_local; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.collections_list_1470009 (key, ser, collection_id) VALUES ('5'::bigint, '3940649673949193'::bigint, 0) RETURNING key, ser - key | ser ---------------------------------------------------------------------- - 5 | 3940649673949193 -(1 row) - -SELECT setval('collections_list_key_seq', 5); - setval ---------------------------------------------------------------------- - 5 -(1 row) - -EXECUTE serial_prepared_local; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.collections_list_1470011 (key, ser, collection_id) VALUES ('6'::bigint, '3940649673949194'::bigint, 0) RETURNING key, ser - key | ser ---------------------------------------------------------------------- - 6 | 3940649673949194 -(1 row) - --- and, one remote test -SELECT setval('collections_list_key_seq', 10); - setval ---------------------------------------------------------------------- - 10 -(1 row) - -EXECUTE serial_prepared_local; - key | ser ---------------------------------------------------------------------- - 11 | 3940649673949195 -(1 row) - --- the final queries for the following CTEs are going to happen on the intermediate results only --- one of them will be executed remotely, and the other is locally --- Citus currently doesn't allow using task_assignment_policy for intermediate results -WITH distributed_local_mixed AS (INSERT INTO reference_table VALUES (1000) RETURNING *) SELECT * FROM distributed_local_mixed; -NOTICE: executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 (key) VALUES (1000) RETURNING key -NOTICE: executing the command locally: SELECT key FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) distributed_local_mixed - key ---------------------------------------------------------------------- - 1000 -(1 row) - --- clean the table for the next tests -SET search_path TO local_shard_execution; -TRUNCATE distributed_table CASCADE; -NOTICE: truncate cascades to table "second_distributed_table" --- load some data on a remote shard -INSERT INTO reference_table (key) VALUES (1), (2); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 AS citus_table_alias (key) VALUES (1), (2) -INSERT INTO distributed_table (key) VALUES (2); -BEGIN; - -- local execution followed by a distributed query - INSERT INTO distributed_table (key) VALUES (1); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 (key) VALUES (1) - DELETE FROM distributed_table RETURNING key; -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table RETURNING key -NOTICE: executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table RETURNING key - key ---------------------------------------------------------------------- - 1 - 2 -(2 rows) - -COMMIT; --- a similar test with a reference table -TRUNCATE reference_table CASCADE; -NOTICE: truncate cascades to table "distributed_table" -NOTICE: truncate cascades to table "second_distributed_table" -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.reference_table_xxxxx CASCADE -NOTICE: truncate cascades to table "distributed_table_xxxxx" -NOTICE: truncate cascades to table "distributed_table_xxxxx" -NOTICE: truncate cascades to table "second_distributed_table_xxxxx" -NOTICE: truncate cascades to table "second_distributed_table_xxxxx" -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.distributed_table_xxxxx CASCADE -NOTICE: truncate cascades to table "second_distributed_table_xxxxx" -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.distributed_table_xxxxx CASCADE -NOTICE: truncate cascades to table "second_distributed_table_xxxxx" -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.second_distributed_table_xxxxx CASCADE -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution.second_distributed_table_xxxxx CASCADE --- load some data on a remote shard -INSERT INTO reference_table (key) VALUES (2); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 (key) VALUES (2) -BEGIN; - -- local execution followed by a distributed query - INSERT INTO reference_table (key) VALUES (1); -NOTICE: executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 (key) VALUES (1) - DELETE FROM reference_table RETURNING key; -NOTICE: executing the command locally: DELETE FROM local_shard_execution.reference_table_1470000 reference_table RETURNING key - key ---------------------------------------------------------------------- - 1 - 2 -(2 rows) - -COMMIT; --- however complex the query, local execution can handle -SET client_min_messages TO LOG; -SET citus.log_local_commands TO ON; -WITH cte_1 AS - (SELECT * - FROM - (WITH cte_1 AS - (SELECT * - FROM distributed_table - WHERE key = 1) SELECT * - FROM cte_1) AS foo) -SELECT count(*) -FROM cte_1 -JOIN distributed_table USING (key) -WHERE distributed_table.key = 1 - AND distributed_table.key IN - (SELECT key - FROM distributed_table - WHERE key = 1); -NOTICE: executing the command locally: SELECT count(*) AS count FROM ((SELECT foo.key, foo.value, foo.age FROM (SELECT cte_1_1.key, cte_1_1.value, cte_1_1.age FROM (SELECT distributed_table_1.key, distributed_table_1.value, distributed_table_1.age FROM local_shard_execution.distributed_table_1470001 distributed_table_1 WHERE (distributed_table_1.key OPERATOR(pg_catalog.=) 1)) cte_1_1) foo) cte_1 JOIN local_shard_execution.distributed_table_1470001 distributed_table(key, value, age) USING (key)) WHERE ((distributed_table.key OPERATOR(pg_catalog.=) 1) AND (distributed_table.key OPERATOR(pg_catalog.=) ANY (SELECT distributed_table_1.key FROM local_shard_execution.distributed_table_1470001 distributed_table_1 WHERE (distributed_table_1.key OPERATOR(pg_catalog.=) 1)))) - count ---------------------------------------------------------------------- - 0 -(1 row) - -RESET client_min_messages; -RESET citus.log_local_commands; -\c - - - :master_port -SET search_path TO local_shard_execution; -SET citus.next_shard_id TO 1480000; --- test both local and remote execution with custom type -SET citus.shard_replication_factor TO 1; -CREATE TYPE invite_resp AS ENUM ('yes', 'no', 'maybe'); -CREATE TABLE event_responses ( - event_id int, - user_id int, - response invite_resp, - primary key (event_id, user_id) -); -SELECT create_distributed_table('event_responses', 'event_id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO event_responses VALUES (1, 1, 'yes'), (2, 2, 'yes'), (3, 3, 'no'), (4, 4, 'no'); -CREATE TABLE event_responses_no_pkey ( - event_id int, - user_id int, - response invite_resp -); -SELECT create_distributed_table('event_responses_no_pkey', 'event_id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -CREATE OR REPLACE FUNCTION regular_func(p invite_resp) -RETURNS int AS $$ -DECLARE - q1Result INT; - q2Result INT; - q3Result INT; -BEGIN -SELECT count(*) INTO q1Result FROM event_responses WHERE response = $1; -SELECT count(*) INTO q2Result FROM event_responses e1 LEFT JOIN event_responses e2 USING (event_id) WHERE e2.response = $1; -SELECT count(*) INTO q3Result FROM (SELECT * FROM event_responses WHERE response = $1 LIMIT 5) as foo; -RETURN q3Result+q2Result+q1Result; -END; -$$ LANGUAGE plpgsql; -SELECT regular_func('yes'); - regular_func ---------------------------------------------------------------------- - 6 -(1 row) - -SELECT regular_func('yes'); - regular_func ---------------------------------------------------------------------- - 6 -(1 row) - -SELECT regular_func('yes'); - regular_func ---------------------------------------------------------------------- - 6 -(1 row) - -SELECT regular_func('yes'); - regular_func ---------------------------------------------------------------------- - 6 -(1 row) - -SELECT regular_func('yes'); - regular_func ---------------------------------------------------------------------- - 6 -(1 row) - -SELECT regular_func('yes'); - regular_func ---------------------------------------------------------------------- - 6 -(1 row) - -SELECT regular_func('yes'); - regular_func ---------------------------------------------------------------------- - 6 -(1 row) - -SELECT regular_func('yes'); - regular_func ---------------------------------------------------------------------- - 6 -(1 row) - -CREATE OR REPLACE PROCEDURE regular_procedure(p invite_resp) -AS $$ -BEGIN -PERFORM * FROM event_responses WHERE response = $1 ORDER BY 1 DESC, 2 DESC, 3 DESC; -PERFORM * FROM event_responses e1 LEFT JOIN event_responses e2 USING (event_id) WHERE e2.response = $1 ORDER BY 1 DESC, 2 DESC, 3 DESC, 4 DESC; -PERFORM * FROM (SELECT * FROM event_responses WHERE response = $1 LIMIT 5) as foo ORDER BY 1 DESC, 2 DESC, 3 DESC; -END; -$$ LANGUAGE plpgsql; -CALL regular_procedure('no'); -CALL regular_procedure('no'); -CALL regular_procedure('no'); -CALL regular_procedure('no'); -CALL regular_procedure('no'); -CALL regular_procedure('no'); -CALL regular_procedure('no'); -CALL regular_procedure('no'); -PREPARE multi_shard_no_dist_key(invite_resp) AS select * from event_responses where response = $1::invite_resp ORDER BY 1 DESC, 2 DESC, 3 DESC LIMIT 1; -EXECUTE multi_shard_no_dist_key('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_no_dist_key('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_no_dist_key('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_no_dist_key('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_no_dist_key('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_no_dist_key('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_no_dist_key('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_no_dist_key('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -PREPARE multi_shard_with_dist_key(int, invite_resp) AS select * from event_responses where event_id > $1 AND response = $2::invite_resp ORDER BY 1 DESC, 2 DESC, 3 DESC LIMIT 1; -EXECUTE multi_shard_with_dist_key(1, 'yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_with_dist_key(1, 'yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_with_dist_key(1, 'yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_with_dist_key(1, 'yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_with_dist_key(1, 'yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_with_dist_key(1, 'yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_with_dist_key(1, 'yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_with_dist_key(1, 'yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -PREPARE query_pushdown_no_dist_key(invite_resp) AS select * from event_responses e1 LEFT JOIN event_responses e2 USING(event_id) where e1.response = $1::invite_resp ORDER BY 1 DESC, 2 DESC, 3 DESC, 4 DESC LIMIT 1; -EXECUTE query_pushdown_no_dist_key('yes'); - event_id | user_id | response | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes | 2 | yes -(1 row) - -EXECUTE query_pushdown_no_dist_key('yes'); - event_id | user_id | response | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes | 2 | yes -(1 row) - -EXECUTE query_pushdown_no_dist_key('yes'); - event_id | user_id | response | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes | 2 | yes -(1 row) - -EXECUTE query_pushdown_no_dist_key('yes'); - event_id | user_id | response | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes | 2 | yes -(1 row) - -EXECUTE query_pushdown_no_dist_key('yes'); - event_id | user_id | response | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes | 2 | yes -(1 row) - -EXECUTE query_pushdown_no_dist_key('yes'); - event_id | user_id | response | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes | 2 | yes -(1 row) - -EXECUTE query_pushdown_no_dist_key('yes'); - event_id | user_id | response | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes | 2 | yes -(1 row) - -EXECUTE query_pushdown_no_dist_key('yes'); - event_id | user_id | response | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes | 2 | yes -(1 row) - -PREPARE insert_select_via_coord(invite_resp) AS INSERT INTO event_responses SELECT * FROM event_responses where response = $1::invite_resp LIMIT 1 ON CONFLICT (event_id, user_id) DO NOTHING ; -EXECUTE insert_select_via_coord('yes'); -EXECUTE insert_select_via_coord('yes'); -EXECUTE insert_select_via_coord('yes'); -EXECUTE insert_select_via_coord('yes'); -EXECUTE insert_select_via_coord('yes'); -EXECUTE insert_select_via_coord('yes'); -EXECUTE insert_select_via_coord('yes'); -EXECUTE insert_select_via_coord('yes'); -PREPARE insert_select_pushdown(invite_resp) AS INSERT INTO event_responses SELECT * FROM event_responses where response = $1::invite_resp ON CONFLICT (event_id, user_id) DO NOTHING; -EXECUTE insert_select_pushdown('yes'); -EXECUTE insert_select_pushdown('yes'); -EXECUTE insert_select_pushdown('yes'); -EXECUTE insert_select_pushdown('yes'); -EXECUTE insert_select_pushdown('yes'); -EXECUTE insert_select_pushdown('yes'); -EXECUTE insert_select_pushdown('yes'); -EXECUTE insert_select_pushdown('yes'); -PREPARE router_select_with_no_dist_key_filter(invite_resp) AS select * from event_responses where event_id = 1 AND response = $1::invite_resp ORDER BY 1 DESC, 2 DESC, 3 DESC LIMIT 1; -EXECUTE router_select_with_no_dist_key_filter('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 1 | 1 | yes -(1 row) - -EXECUTE router_select_with_no_dist_key_filter('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 1 | 1 | yes -(1 row) - -EXECUTE router_select_with_no_dist_key_filter('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 1 | 1 | yes -(1 row) - -EXECUTE router_select_with_no_dist_key_filter('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 1 | 1 | yes -(1 row) - -EXECUTE router_select_with_no_dist_key_filter('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 1 | 1 | yes -(1 row) - -EXECUTE router_select_with_no_dist_key_filter('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 1 | 1 | yes -(1 row) - -EXECUTE router_select_with_no_dist_key_filter('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 1 | 1 | yes -(1 row) - -EXECUTE router_select_with_no_dist_key_filter('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 1 | 1 | yes -(1 row) - --- rest of the tests assume the table is empty -TRUNCATE event_responses; -CREATE OR REPLACE PROCEDURE register_for_event(p_event_id int, p_user_id int, p_choice invite_resp) -LANGUAGE plpgsql -SET search_path TO local_shard_execution -AS $fn$ -BEGIN - INSERT INTO event_responses VALUES (p_event_id, p_user_id, p_choice) - ON CONFLICT (event_id, user_id) - DO UPDATE SET response = EXCLUDED.response; - - PERFORM count(*) FROM event_responses WHERE event_id = p_event_id; - - PERFORM count(*) FROM event_responses WHERE event_id = p_event_id AND false; - - UPDATE event_responses SET response = p_choice WHERE event_id = p_event_id; - -END; -$fn$; -SELECT create_distributed_function('register_for_event(int,int,invite_resp)', 'p_event_id', 'event_responses'); - create_distributed_function ---------------------------------------------------------------------- - -(1 row) - --- call 8 times to make sure it works after the 5th time(postgres binds values after the 5th time and Citus 2nd time) --- after 6th, the local execution caches the local plans and uses it --- execute it both locally and remotely -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -\c - - - :worker_2_port -SET search_path TO local_shard_execution; -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); --- values 16, 17 and 19 hits the same --- shard, so we're re-using the same cached --- plans per statement across different distribution --- key values -CALL register_for_event(17, 1, 'yes'); -CALL register_for_event(19, 1, 'yes'); -CALL register_for_event(17, 1, 'yes'); -CALL register_for_event(19, 1, 'yes'); --- should work fine if the logs are enabled -\set VERBOSITY terse -SET citus.log_local_commands TO ON; -SET client_min_messages TO DEBUG2; -CALL register_for_event(19, 1, 'yes'); -DEBUG: not pushing down procedure to the same node -NOTICE: executing the command locally: INSERT INTO local_shard_execution.event_responses_1480001 AS citus_table_alias (event_id, user_id, response) VALUES (19, 1, 'yes'::local_shard_execution.invite_resp) ON CONFLICT(event_id, user_id) DO UPDATE SET response = excluded.response -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.event_responses_1480001 event_responses WHERE (event_id OPERATOR(pg_catalog.=) 19) -NOTICE: executing the command locally: SELECT count(*) AS count FROM (SELECT NULL::integer AS event_id, NULL::integer AS user_id, NULL::local_shard_execution.invite_resp AS response WHERE false) event_responses(event_id, user_id, response) WHERE ((event_id OPERATOR(pg_catalog.=) 19) AND false) -NOTICE: executing the command locally: UPDATE local_shard_execution.event_responses_1480001 event_responses SET response = 'yes'::local_shard_execution.invite_resp WHERE (event_id OPERATOR(pg_catalog.=) 19) --- should be fine even if no parameters exists in the query -SELECT count(*) FROM event_responses WHERE event_id = 16; -DEBUG: Distributed planning for a fast-path router query -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 16 -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.event_responses_1480001 event_responses WHERE (event_id OPERATOR(pg_catalog.=) 16) - count ---------------------------------------------------------------------- - 1 -(1 row) - -SELECT count(*) FROM event_responses WHERE event_id = 16; -DEBUG: Distributed planning for a fast-path router query -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 16 -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution.event_responses_1480001 event_responses WHERE (event_id OPERATOR(pg_catalog.=) 16) - count ---------------------------------------------------------------------- - 1 -(1 row) - -UPDATE event_responses SET response = 'no' WHERE event_id = 16; -DEBUG: Distributed planning for a fast-path router query -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 16 -NOTICE: executing the command locally: UPDATE local_shard_execution.event_responses_1480001 event_responses SET response = 'no'::local_shard_execution.invite_resp WHERE (event_id OPERATOR(pg_catalog.=) 16) -INSERT INTO event_responses VALUES (16, 666, 'maybe') -ON CONFLICT (event_id, user_id) -DO UPDATE SET response = EXCLUDED.response RETURNING *; -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 16 -NOTICE: executing the command locally: INSERT INTO local_shard_execution.event_responses_1480001 AS citus_table_alias (event_id, user_id, response) VALUES (16, 666, 'maybe'::local_shard_execution.invite_resp) ON CONFLICT(event_id, user_id) DO UPDATE SET response = excluded.response RETURNING citus_table_alias.event_id, citus_table_alias.user_id, citus_table_alias.response - event_id | user_id | response ---------------------------------------------------------------------- - 16 | 666 | maybe -(1 row) - --- multi row INSERTs hitting the same shard -INSERT INTO event_responses VALUES (16, 666, 'maybe'), (17, 777, 'no') -ON CONFLICT (event_id, user_id) -DO UPDATE SET response = EXCLUDED.response RETURNING *; -DEBUG: Creating router plan -NOTICE: executing the command locally: INSERT INTO local_shard_execution.event_responses_1480001 AS citus_table_alias (event_id, user_id, response) VALUES (16,666,'maybe'::local_shard_execution.invite_resp), (17,777,'no'::local_shard_execution.invite_resp) ON CONFLICT(event_id, user_id) DO UPDATE SET response = excluded.response RETURNING citus_table_alias.event_id, citus_table_alias.user_id, citus_table_alias.response - event_id | user_id | response ---------------------------------------------------------------------- - 16 | 666 | maybe - 17 | 777 | no -(2 rows) - --- now, similar tests with some settings changed -SET citus.enable_local_execution TO false; -SET citus.enable_fast_path_router_planner TO false; -CALL register_for_event(19, 1, 'yes'); -DEBUG: not pushing down procedure to the same node --- should be fine even if no parameters exists in the query -SELECT count(*) FROM event_responses WHERE event_id = 16; -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 16 - count ---------------------------------------------------------------------- - 2 -(1 row) - -SELECT count(*) FROM event_responses WHERE event_id = 16; -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 16 - count ---------------------------------------------------------------------- - 2 -(1 row) - -UPDATE event_responses SET response = 'no' WHERE event_id = 16; -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 16 -INSERT INTO event_responses VALUES (16, 666, 'maybe') -ON CONFLICT (event_id, user_id) -DO UPDATE SET response = EXCLUDED.response RETURNING *; -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 16 - event_id | user_id | response ---------------------------------------------------------------------- - 16 | 666 | maybe -(1 row) - --- multi row INSERTs hitting the same shard -INSERT INTO event_responses VALUES (16, 666, 'maybe'), (17, 777, 'no') -ON CONFLICT (event_id, user_id) -DO UPDATE SET response = EXCLUDED.response RETURNING *; -DEBUG: Creating router plan - event_id | user_id | response ---------------------------------------------------------------------- - 16 | 666 | maybe - 17 | 777 | no -(2 rows) - --- set back to sane settings -RESET citus.enable_local_execution; -RESET citus.enable_fast_path_router_planner; --- we'll test some 2PC states -SET citus.enable_metadata_sync TO OFF; --- coordinated_transaction_should_use_2PC prints the internal --- state for 2PC decision on Citus. However, even if 2PC is decided, --- we may not necessarily use 2PC over a connection unless it does --- a modification -CREATE OR REPLACE FUNCTION coordinated_transaction_should_use_2PC() -RETURNS BOOL LANGUAGE C STRICT VOLATILE AS 'citus', -$$coordinated_transaction_should_use_2PC$$; --- make tests consistent -SET citus.max_adaptive_executor_pool_size TO 1; -RESET citus.enable_metadata_sync; -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - -SET citus.log_remote_commands TO ON; --- we use event_id = 2 for local execution and event_id = 1 for reemote execution ---show it here, if anything changes here, all the tests below might be broken --- we prefer this to avoid excessive logging below -SELECT * FROM event_responses_no_pkey WHERE event_id = 2; -DEBUG: Distributed planning for a fast-path router query -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 2 -NOTICE: executing the command locally: SELECT event_id, user_id, response FROM local_shard_execution.event_responses_no_pkey_1480007 event_responses_no_pkey WHERE (event_id OPERATOR(pg_catalog.=) 2) - event_id | user_id | response ---------------------------------------------------------------------- -(0 rows) - -SELECT * FROM event_responses_no_pkey WHERE event_id = 1; -DEBUG: Distributed planning for a fast-path router query -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 1 -NOTICE: issuing SELECT event_id, user_id, response FROM local_shard_execution.event_responses_no_pkey_1480004 event_responses_no_pkey WHERE (event_id OPERATOR(pg_catalog.=) 1) - event_id | user_id | response ---------------------------------------------------------------------- -(0 rows) - -RESET citus.log_remote_commands; -RESET citus.log_local_commands; -RESET client_min_messages; --- single shard local command without transaction block does set the --- internal state for 2PC, but does not require any actual entries -WITH cte_1 AS (INSERT INTO event_responses_no_pkey VALUES (2, 2, 'yes') RETURNING *) -SELECT coordinated_transaction_should_use_2PC() FROM cte_1; - coordinated_transaction_should_use_2pc ---------------------------------------------------------------------- - t -(1 row) - -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - --- two local commands without transaction block set the internal 2PC state --- but does not use remotely -WITH cte_1 AS (INSERT INTO event_responses_no_pkey VALUES (2, 2, 'yes') RETURNING *), - cte_2 AS (INSERT INTO event_responses_no_pkey VALUES (2, 2, 'yes') RETURNING *) -SELECT bool_or(coordinated_transaction_should_use_2PC()) FROM cte_1, cte_2; - bool_or ---------------------------------------------------------------------- - t -(1 row) - -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - --- single shard local modification followed by another single shard --- local modification sets the 2PC state, but does not use remotely -BEGIN; - INSERT INTO event_responses_no_pkey VALUES (2, 2, 'yes') RETURNING *; - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - - INSERT INTO event_responses_no_pkey VALUES (2, 2, 'yes') RETURNING *; - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - - SELECT coordinated_transaction_should_use_2PC(); - coordinated_transaction_should_use_2pc ---------------------------------------------------------------------- - t -(1 row) - -COMMIT; -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - --- single shard local modification followed by a single shard --- remote modification uses 2PC because multiple nodes involved --- in the modification -BEGIN; - INSERT INTO event_responses_no_pkey VALUES (2, 2, 'yes') RETURNING *; - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - - INSERT INTO event_responses_no_pkey VALUES (1, 2, 'yes') RETURNING *; - event_id | user_id | response ---------------------------------------------------------------------- - 1 | 2 | yes -(1 row) - - SELECT coordinated_transaction_should_use_2PC(); - coordinated_transaction_should_use_2pc ---------------------------------------------------------------------- - t -(1 row) - -COMMIT; -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 1 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - --- single shard local modification followed by a single shard --- remote modification uses 2PC even if it is not in an explicit --- tx block as multiple nodes involved in the modification -WITH cte_1 AS (INSERT INTO event_responses_no_pkey VALUES (2, 2, 'yes') RETURNING *), - cte_2 AS (INSERT INTO event_responses_no_pkey VALUES (1, 1, 'yes') RETURNING *) -SELECT bool_or(coordinated_transaction_should_use_2PC()) FROM cte_1, cte_2; - bool_or ---------------------------------------------------------------------- - t -(1 row) - -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 1 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - --- single shard remote modification followed by a single shard --- local modification uses 2PC as multiple nodes involved --- in the modification -BEGIN; - INSERT INTO event_responses_no_pkey VALUES (1, 2, 'yes') RETURNING *; - event_id | user_id | response ---------------------------------------------------------------------- - 1 | 2 | yes -(1 row) - - INSERT INTO event_responses_no_pkey VALUES (2, 2, 'yes') RETURNING *; - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - - SELECT coordinated_transaction_should_use_2PC(); - coordinated_transaction_should_use_2pc ---------------------------------------------------------------------- - t -(1 row) - -COMMIT; -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 1 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - --- single shard remote modification followed by a single shard --- local modification uses 2PC even if it is not in an explicit --- tx block -WITH cte_1 AS (INSERT INTO event_responses_no_pkey VALUES (1, 1, 'yes') RETURNING *), - cte_2 AS (INSERT INTO event_responses_no_pkey VALUES (2, 2, 'yes') RETURNING *) -SELECT bool_or(coordinated_transaction_should_use_2PC()) FROM cte_1, cte_2; - bool_or ---------------------------------------------------------------------- - t -(1 row) - -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 1 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - --- single shard local SELECT command without transaction block does not set the --- internal state for 2PC -WITH cte_1 AS (SELECT * FROM event_responses_no_pkey WHERE event_id = 2) -SELECT coordinated_transaction_should_use_2PC() FROM cte_1; -ERROR: The transaction is not a coordinated transaction -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - --- two local SELECT commands without transaction block does not set the internal 2PC state --- and does not use remotely -WITH cte_1 AS (SELECT count(*) FROM event_responses_no_pkey WHERE event_id = 2), - cte_2 AS (SELECT count(*) FROM event_responses_no_pkey WHERE event_id = 2) -SELECT count(*) FROM cte_1, cte_2; - count ---------------------------------------------------------------------- - 1 -(1 row) - -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - --- two local SELECT commands without transaction block does not set the internal 2PC state --- and does not use remotely -BEGIN; - SELECT count(*) FROM event_responses_no_pkey WHERE event_id = 2; - count ---------------------------------------------------------------------- - 9 -(1 row) - - SELECT count(*) FROM event_responses_no_pkey WHERE event_id = 2; - count ---------------------------------------------------------------------- - 9 -(1 row) - - SELECT coordinated_transaction_should_use_2PC(); - coordinated_transaction_should_use_2pc ---------------------------------------------------------------------- - f -(1 row) - -COMMIT; -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - --- a local SELECT followed by a remote SELECT does not require to --- use actual 2PC -BEGIN; - SELECT count(*) FROM event_responses_no_pkey WHERE event_id = 2; - count ---------------------------------------------------------------------- - 9 -(1 row) - - SELECT count(*) FROM event_responses_no_pkey; - count ---------------------------------------------------------------------- - 13 -(1 row) - -COMMIT; -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - --- single shard local SELECT followed by a single shard --- remote modification does not use 2PC, because only a single --- machine involved in the modification -BEGIN; - SELECT * FROM event_responses_no_pkey WHERE event_id = 2; - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes - 2 | 2 | yes - 2 | 2 | yes - 2 | 2 | yes - 2 | 2 | yes - 2 | 2 | yes - 2 | 2 | yes - 2 | 2 | yes - 2 | 2 | yes -(9 rows) - - INSERT INTO event_responses_no_pkey VALUES (1, 2, 'yes') RETURNING *; - event_id | user_id | response ---------------------------------------------------------------------- - 1 | 2 | yes -(1 row) - - SELECT coordinated_transaction_should_use_2PC(); - coordinated_transaction_should_use_2pc ---------------------------------------------------------------------- - f -(1 row) - -COMMIT; -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - --- single shard local SELECT followed by a single shard --- remote modification does not use 2PC, because only a single --- machine involved in the modification -WITH cte_1 AS (SELECT * FROM event_responses_no_pkey WHERE event_id = 2), - cte_2 AS (INSERT INTO event_responses_no_pkey VALUES (1, 1, 'yes') RETURNING *) -SELECT bool_or(coordinated_transaction_should_use_2PC()) FROM cte_1, cte_2; - bool_or ---------------------------------------------------------------------- - f -(1 row) - -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - --- single shard remote modification followed by a single shard --- local SELECT does not use 2PC, because only a single --- machine involved in the modification -BEGIN; - INSERT INTO event_responses_no_pkey VALUES (1, 2, 'yes') RETURNING *; - event_id | user_id | response ---------------------------------------------------------------------- - 1 | 2 | yes -(1 row) - - SELECT count(*) FROM event_responses_no_pkey WHERE event_id = 2; - count ---------------------------------------------------------------------- - 9 -(1 row) - - SELECT coordinated_transaction_should_use_2PC(); - coordinated_transaction_should_use_2pc ---------------------------------------------------------------------- - f -(1 row) - -COMMIT; -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - --- single shard remote modification followed by a single shard --- local SELECT does not use 2PC, because only a single --- machine involved in the modification -WITH cte_1 AS (INSERT INTO event_responses_no_pkey VALUES (1, 1, 'yes') RETURNING *), - cte_2 AS (SELECT * FROM event_responses_no_pkey WHERE event_id = 2) -SELECT bool_or(coordinated_transaction_should_use_2PC()) FROM cte_1, cte_2; - bool_or ---------------------------------------------------------------------- - f -(1 row) - -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - --- multi shard local SELECT command without transaction block does not set the --- internal state for 2PC -WITH cte_1 AS (SELECT count(*) FROM event_responses_no_pkey) -SELECT coordinated_transaction_should_use_2PC() FROM cte_1; - coordinated_transaction_should_use_2pc ---------------------------------------------------------------------- - f -(1 row) - -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - --- two multi-shard SELECT commands without transaction block does not set the internal 2PC state --- and does not use remotely -WITH cte_1 AS (SELECT count(*) FROM event_responses_no_pkey), - cte_2 AS (SELECT count(*) FROM event_responses_no_pkey) -SELECT bool_or(coordinated_transaction_should_use_2PC()) FROM cte_1, cte_2; - bool_or ---------------------------------------------------------------------- - f -(1 row) - -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - --- two multi-shard SELECT commands without transaction block does not set the internal 2PC state --- and does not use remotely -BEGIN; - SELECT count(*) FROM event_responses_no_pkey; - count ---------------------------------------------------------------------- - 17 -(1 row) - - SELECT count(*) FROM event_responses_no_pkey; - count ---------------------------------------------------------------------- - 17 -(1 row) - - SELECT coordinated_transaction_should_use_2PC(); - coordinated_transaction_should_use_2pc ---------------------------------------------------------------------- - f -(1 row) - -COMMIT; -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - --- multi-shard shard SELECT followed by a single shard --- remote modification does not use 2PC, because only a single --- machine involved in the modification -BEGIN; - SELECT count(*) FROM event_responses_no_pkey; - count ---------------------------------------------------------------------- - 17 -(1 row) - - INSERT INTO event_responses_no_pkey VALUES (1, 2, 'yes') RETURNING *; - event_id | user_id | response ---------------------------------------------------------------------- - 1 | 2 | yes -(1 row) - - SELECT coordinated_transaction_should_use_2PC(); - coordinated_transaction_should_use_2pc ---------------------------------------------------------------------- - f -(1 row) - -COMMIT; -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - --- multi shard SELECT followed by a single shard --- remote single shard modification does not use 2PC, because only a single --- machine involved in the modification -WITH cte_1 AS (SELECT count(*) FROM event_responses_no_pkey), - cte_2 AS (INSERT INTO event_responses_no_pkey VALUES (1, 1, 'yes') RETURNING *) -SELECT bool_or(coordinated_transaction_should_use_2PC()) FROM cte_1, cte_2; - bool_or ---------------------------------------------------------------------- - f -(1 row) - -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - --- single shard remote modification followed by a multi shard --- SELECT does not use 2PC, because only a single --- machine involved in the modification -BEGIN; - INSERT INTO event_responses_no_pkey VALUES (1, 2, 'yes') RETURNING *; - event_id | user_id | response ---------------------------------------------------------------------- - 1 | 2 | yes -(1 row) - - SELECT count(*) FROM event_responses_no_pkey; - count ---------------------------------------------------------------------- - 20 -(1 row) - - SELECT coordinated_transaction_should_use_2PC(); - coordinated_transaction_should_use_2pc ---------------------------------------------------------------------- - f -(1 row) - -COMMIT; -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - --- single shard remote modification followed by a multi shard --- SELECT does not use 2PC, because only a single --- machine involved in the modification -WITH cte_1 AS (INSERT INTO event_responses_no_pkey VALUES (1, 1, 'yes') RETURNING *), - cte_2 AS (SELECT count(*) FROM event_responses_no_pkey) -SELECT bool_or(coordinated_transaction_should_use_2PC()) FROM cte_1, cte_2; - bool_or ---------------------------------------------------------------------- - f -(1 row) - -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - --- single shard local modification followed by remote multi-shard --- modification uses 2PC as multiple nodes are involved in modifications -WITH cte_1 AS (INSERT INTO event_responses_no_pkey VALUES (2, 2, 'yes') RETURNING *), - cte_2 AS (UPDATE event_responses_no_pkey SET user_id = 1000 RETURNING *) -SELECT bool_or(coordinated_transaction_should_use_2PC()) FROM cte_1, cte_2; - bool_or ---------------------------------------------------------------------- - t -(1 row) - -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 1 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - --- a local SELECT followed by a remote multi-shard UPDATE requires to --- use actual 2PC as multiple nodes are involved in modifications -BEGIN; - SELECT count(*) FROM event_responses_no_pkey WHERE event_id = 2; - count ---------------------------------------------------------------------- - 10 -(1 row) - - UPDATE event_responses_no_pkey SET user_id = 1; -COMMIT; -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 1 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - --- a local SELECT followed by a remote single-shard UPDATE does not require to --- use actual 2PC. This is because a single node is involved in modification -BEGIN; - SELECT count(*) FROM event_responses_no_pkey WHERE event_id = 2; - count ---------------------------------------------------------------------- - 10 -(1 row) - - UPDATE event_responses_no_pkey SET user_id = 1 WHERE event_id = 1; -COMMIT; -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - --- a remote single-shard UPDATE followed by a local single shard SELECT --- does not require to use actual 2PC. This is because a single node --- is involved in modification -BEGIN; - UPDATE event_responses_no_pkey SET user_id = 1 WHERE event_id = 1; - SELECT count(*) FROM event_responses_no_pkey WHERE event_id = 2; - count ---------------------------------------------------------------------- - 10 -(1 row) - -COMMIT; -SELECT count(*) FROM pg_dist_transaction; - count ---------------------------------------------------------------------- - 0 -(1 row) - -SELECT recover_prepared_transactions(); - recover_prepared_transactions ---------------------------------------------------------------------- - 0 -(1 row) - -\c - - - :master_port -SET search_path TO local_shard_execution; --- verify the local_hostname guc is used for local executions that should connect to the --- local host -ALTER SYSTEM SET citus.local_hostname TO 'foobar'; -SELECT pg_reload_conf(); - pg_reload_conf ---------------------------------------------------------------------- - t -(1 row) - -SELECT pg_sleep(0.1); -- wait to make sure the config has changed before running the GUC - pg_sleep ---------------------------------------------------------------------- - -(1 row) - -SET citus.enable_local_execution TO false; -- force a connection to the dummy placements --- run queries that use dummy placements for local execution -SELECT * FROM event_responses WHERE FALSE; -ERROR: connection to the remote node postgres@foobar:57636 failed with the following error: could not translate host name "foobar" to address: -WITH cte_1 AS (SELECT * FROM event_responses LIMIT 1) SELECT count(*) FROM cte_1; -ERROR: connection to the remote node postgres@foobar:57636 failed with the following error: could not translate host name "foobar" to address: -ALTER SYSTEM RESET citus.local_hostname; -SELECT pg_reload_conf(); - pg_reload_conf ---------------------------------------------------------------------- - t -(1 row) - -SELECT pg_sleep(.1); -- wait to make sure the config has changed before running the GUC - pg_sleep ---------------------------------------------------------------------- - -(1 row) - -SET client_min_messages TO ERROR; -SET search_path TO public; -DROP SCHEMA local_shard_execution CASCADE; diff --git a/src/test/regress/expected/local_shard_execution_replicated.out b/src/test/regress/expected/local_shard_execution_replicated.out index d0593db4a..b086d7a84 100644 --- a/src/test/regress/expected/local_shard_execution_replicated.out +++ b/src/test/regress/expected/local_shard_execution_replicated.out @@ -1,17 +1,6 @@ -- -- LOCAL_SHARD_EXECUTION_REPLICATED -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - t -(1 row) - CREATE SCHEMA local_shard_execution_replicated; SET search_path TO local_shard_execution_replicated; SET citus.shard_count TO 4; diff --git a/src/test/regress/expected/local_shard_execution_replicated_0.out b/src/test/regress/expected/local_shard_execution_replicated_0.out deleted file mode 100644 index 992ff6b81..000000000 --- a/src/test/regress/expected/local_shard_execution_replicated_0.out +++ /dev/null @@ -1,2462 +0,0 @@ --- --- LOCAL_SHARD_EXECUTION_REPLICATED --- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - f -(1 row) - -CREATE SCHEMA local_shard_execution_replicated; -SET search_path TO local_shard_execution_replicated; -SET citus.shard_count TO 4; -SET citus.shard_replication_factor TO 2; -SET citus.next_shard_id TO 1500000; -CREATE TABLE reference_table (key int PRIMARY KEY); -SELECT create_reference_table('reference_table'); - create_reference_table ---------------------------------------------------------------------- - -(1 row) - -CREATE TABLE distributed_table (key int PRIMARY KEY , value text, age bigint CHECK (age > 10)); -SELECT create_distributed_table('distributed_table','key'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -CREATE TABLE second_distributed_table (key int PRIMARY KEY , value text); -SELECT create_distributed_table('second_distributed_table','key'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - --- ingest some data to enable some tests with data -INSERT INTO distributed_table VALUES (1, '1', 20); --- This GUC prevents to acquire the remote lock for replicated --- tables -BEGIN; - SET LOCAL citus.allow_modifications_from_workers_to_replicated_tables TO false; - INSERT INTO second_distributed_table VALUES (1, '1'); - INSERT INTO reference_table VALUES (1); -COMMIT; --- a simple test for -CREATE TABLE collections_list ( - key bigserial, - ser bigserial, - ts timestamptz, - collection_id integer, - value numeric, - PRIMARY KEY(key, collection_id) -) PARTITION BY LIST (collection_id ); -SELECT create_distributed_table('collections_list', 'key'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -CREATE TABLE collections_list_0 - PARTITION OF collections_list (key, ser, ts, collection_id, value) - FOR VALUES IN ( 0 ); --- create a volatile function that returns the local node id -CREATE OR REPLACE FUNCTION get_local_node_id_volatile() -RETURNS INT AS $$ -DECLARE localGroupId int; -BEGIN - SELECT groupid INTO localGroupId FROM pg_dist_local_group; - RETURN localGroupId; -END; $$ language plpgsql VOLATILE; -SELECT create_distributed_function('get_local_node_id_volatile()'); -NOTICE: procedure local_shard_execution_replicated.get_local_node_id_volatile is already distributed -DETAIL: Citus distributes procedures with CREATE [PROCEDURE|FUNCTION|AGGREGATE] commands - create_distributed_function ---------------------------------------------------------------------- - -(1 row) - --- test case for issue #3556 -CREATE TABLE accounts (id text PRIMARY KEY); -CREATE TABLE stats (account_id text PRIMARY KEY, spent int); -SELECT create_distributed_table('accounts', 'id', colocate_with => 'none'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -SELECT create_distributed_table('stats', 'account_id', colocate_with => 'accounts'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO accounts (id) VALUES ('foo'); -INSERT INTO stats (account_id, spent) VALUES ('foo', 100); -CREATE TABLE abcd(a int, b int, c int, d int); -SELECT create_distributed_table('abcd', 'b'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO abcd VALUES (1,2,3,4); -INSERT INTO abcd VALUES (2,3,4,5); -INSERT INTO abcd VALUES (3,4,5,6); -ALTER TABLE abcd DROP COLUMN a; --- connection worker and get ready for the tests -\c - - - :worker_1_port -SET search_path TO local_shard_execution_replicated; --- test case for issue #3556 -SET citus.log_intermediate_results TO TRUE; -SET client_min_messages TO DEBUG1; -SELECT * -FROM -( - WITH accounts_cte AS ( - SELECT id AS account_id - FROM accounts - ), - joined_stats_cte_1 AS ( - SELECT spent, account_id - FROM stats - INNER JOIN accounts_cte USING (account_id) - ), - joined_stats_cte_2 AS ( - SELECT spent, account_id - FROM joined_stats_cte_1 - INNER JOIN accounts_cte USING (account_id) - ) - SELECT SUM(spent) OVER (PARTITION BY coalesce(account_id, NULL)) - FROM accounts_cte - INNER JOIN joined_stats_cte_2 USING (account_id) -) inner_query; -DEBUG: CTE joined_stats_cte_1 is going to be inlined via distributed planning -DEBUG: CTE joined_stats_cte_2 is going to be inlined via distributed planning -DEBUG: generating subplan XXX_1 for CTE accounts_cte: SELECT id AS account_id FROM local_shard_execution_replicated.accounts -DEBUG: generating subplan XXX_2 for subquery SELECT sum(joined_stats_cte_2.spent) OVER (PARTITION BY COALESCE(accounts_cte.account_id, NULL::text)) AS sum FROM ((SELECT intermediate_result.account_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(account_id text)) accounts_cte JOIN (SELECT joined_stats_cte_1.spent, joined_stats_cte_1.account_id FROM ((SELECT stats.spent, stats.account_id FROM (local_shard_execution_replicated.stats JOIN (SELECT intermediate_result.account_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(account_id text)) accounts_cte_2 USING (account_id))) joined_stats_cte_1 JOIN (SELECT intermediate_result.account_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(account_id text)) accounts_cte_1 USING (account_id))) joined_stats_cte_2 USING (account_id)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT sum FROM (SELECT intermediate_result.sum FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(sum bigint)) inner_query -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be written to local file - sum ---------------------------------------------------------------------- - 100 -(1 row) - -SET citus.log_intermediate_results TO DEFAULT; -SET client_min_messages TO DEFAULT; ---- enable logging to see which tasks are executed locally -SET citus.log_local_commands TO ON; --- first, make sure that local execution works fine --- with simple queries that are not in transcation blocks -SELECT count(*) FROM distributed_table WHERE key = 1; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - --- multiple tasks both of which are local should NOT use local execution --- because local execution means executing the tasks locally, so the executor --- favors parallel execution even if everyting is local to node -SELECT count(*) FROM distributed_table WHERE key IN (1,6); - count ---------------------------------------------------------------------- - 1 -(1 row) - --- queries that hit any remote shards should NOT use local execution -SELECT count(*) FROM distributed_table WHERE key IN (1,11); - count ---------------------------------------------------------------------- - 1 -(1 row) - -SELECT count(*) FROM distributed_table; - count ---------------------------------------------------------------------- - 1 -(1 row) - --- modifications also follow the same rules -INSERT INTO reference_table VALUES (1) ON CONFLICT DO NOTHING; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.reference_table_1500000 AS citus_table_alias (key) VALUES (1) ON CONFLICT DO NOTHING -INSERT INTO distributed_table VALUES (1, '1', 21) ON CONFLICT DO NOTHING; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '1'::text, 21) ON CONFLICT DO NOTHING --- local query -DELETE FROM distributed_table WHERE key = 1 AND age = 21; -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE ((key OPERATOR(pg_catalog.=) 1) AND (age OPERATOR(pg_catalog.=) 21)) --- hitting multiple shards, so should be a distributed execution -DELETE FROM distributed_table WHERE age = 21; --- although both shards are local, the executor choose the parallel execution --- over the wire because as noted above local execution is sequential -DELETE FROM second_distributed_table WHERE key IN (1,6); --- similarly, any multi-shard query just follows distributed execution -DELETE FROM second_distributed_table; --- load some more data for the following tests -INSERT INTO second_distributed_table VALUES (1, '1'); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.second_distributed_table_1500005 (key, value) VALUES (1, '1'::text) --- INSERT .. SELECT hitting a single single (co-located) shard(s) should --- be executed locally -INSERT INTO distributed_table -SELECT - distributed_table.* -FROM - distributed_table, second_distributed_table -WHERE - distributed_table.key = 1 and distributed_table.key=second_distributed_table.key -ON CONFLICT(key) DO UPDATE SET value = '22' -RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table, local_shard_execution_replicated.second_distributed_table_1500005 second_distributed_table WHERE (((distributed_table.key OPERATOR(pg_catalog.=) 1) AND (distributed_table.key OPERATOR(pg_catalog.=) second_distributed_table.key)) AND (distributed_table.key IS NOT NULL)) ON CONFLICT(key) DO UPDATE SET value = '22'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age - key | value | age ---------------------------------------------------------------------- - 1 | 22 | 20 -(1 row) - --- INSERT .. SELECT hitting multi-shards should go thourgh distributed execution -INSERT INTO distributed_table -SELECT - distributed_table.* -FROM - distributed_table, second_distributed_table -WHERE - distributed_table.key != 1 and distributed_table.key=second_distributed_table.key -ON CONFLICT(key) DO UPDATE SET value = '22' -RETURNING *; - key | value | age ---------------------------------------------------------------------- -(0 rows) - --- INSERT..SELECT via coordinator consists of two steps, select + COPY --- that's why it is disallowed to use local execution even if the SELECT --- can be executed locally -INSERT INTO distributed_table SELECT sum(key), value, max(age) FROM distributed_table WHERE key = 1 GROUP BY value ON CONFLICT DO NOTHING; -NOTICE: executing the command locally: SELECT int4(sum(key)) AS key, value, max(age) AS age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) GROUP BY value -NOTICE: executing the copy locally for colocated file with shard xxxxx -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) SELECT key, value, age FROM read_intermediate_result('insert_select_XXX_1500001'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint) ON CONFLICT DO NOTHING -INSERT INTO distributed_table SELECT 1, '1',15 FROM distributed_table WHERE key = 2 LIMIT 1 ON CONFLICT DO NOTHING; -NOTICE: executing the command locally: SELECT 1 AS key, '1'::text AS value, int8(15) AS age FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE (key OPERATOR(pg_catalog.=) 2) LIMIT 1 --- sanity check: multi-shard INSERT..SELECT pushdown goes through distributed execution -INSERT INTO distributed_table SELECT * FROM distributed_table ON CONFLICT DO NOTHING; --- Ensure tuple data in explain analyze output is the same on all PG versions -SET citus.enable_binary_protocol = TRUE; --- EXPLAIN for local execution just works fine --- though going through distributed execution -EXPLAIN (COSTS OFF) SELECT * FROM distributed_table WHERE key = 1 AND age = 20; - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus Adaptive) - Task Count: 1 - Tasks Shown: All - -> Task - Node: host=localhost port=xxxxx dbname=regression - -> Index Scan using distributed_table_pkey_1500001 on distributed_table_1500001 distributed_table - Index Cond: (key = 1) - Filter: (age = 20) -(8 rows) - -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) SELECT * FROM distributed_table WHERE key = 1 AND age = 20; - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus Adaptive) (actual rows=1 loops=1) - Task Count: 1 - Tuple data received from nodes: 14 bytes - Tasks Shown: All - -> Task - Tuple data received from node: 14 bytes - Node: host=localhost port=xxxxx dbname=regression - -> Index Scan using distributed_table_pkey_1500001 on distributed_table_1500001 distributed_table (actual rows=1 loops=1) - Index Cond: (key = 1) - Filter: (age = 20) -(10 rows) - -EXPLAIN (ANALYZE ON, COSTS OFF, SUMMARY OFF, TIMING OFF) -WITH r AS ( SELECT GREATEST(random(), 2) z,* FROM distributed_table) -SELECT 1 FROM r WHERE z < 3; - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus Adaptive) (actual rows=1 loops=1) - -> Distributed Subplan XXX_1 - Intermediate Data Size: 40 bytes - Result destination: Write locally - -> Custom Scan (Citus Adaptive) (actual rows=1 loops=1) - Task Count: 4 - Tuple data received from nodes: 22 bytes - Tasks Shown: One of 4 - -> Task - Tuple data received from node: 22 bytes - Node: host=localhost port=xxxxx dbname=regression - -> Seq Scan on distributed_table_1500001 distributed_table (actual rows=1 loops=1) - Task Count: 1 - Tuple data received from nodes: 4 bytes - Tasks Shown: All - -> Task - Tuple data received from node: 4 bytes - Node: host=localhost port=xxxxx dbname=regression - -> Function Scan on read_intermediate_result intermediate_result (actual rows=1 loops=1) - Filter: (z < '3'::double precision) -(20 rows) - -EXPLAIN (COSTS OFF) DELETE FROM distributed_table WHERE key = 1 AND age = 20; - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus Adaptive) - Task Count: 1 - Tasks Shown: All - -> Task - Node: host=localhost port=xxxxx dbname=regression - -> Delete on distributed_table_1500001 distributed_table - -> Index Scan using distributed_table_pkey_1500001 on distributed_table_1500001 distributed_table - Index Cond: (key = 1) - Filter: (age = 20) -(9 rows) - -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) DELETE FROM distributed_table WHERE key = 1 AND age = 20; - QUERY PLAN ---------------------------------------------------------------------- - Custom Scan (Citus Adaptive) (actual rows=0 loops=1) - Task Count: 1 - Tasks Shown: All - -> Task - Node: host=localhost port=xxxxx dbname=regression - -> Delete on distributed_table_1500001 distributed_table (actual rows=0 loops=1) - -> Index Scan using distributed_table_pkey_1500001 on distributed_table_1500001 distributed_table (actual rows=1 loops=1) - Index Cond: (key = 1) - Filter: (age = 20) -(9 rows) - --- show that EXPLAIN ANALYZE deleted the row -SELECT * FROM distributed_table WHERE key = 1 AND age = 20 ORDER BY 1,2,3; -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE ((key OPERATOR(pg_catalog.=) 1) AND (age OPERATOR(pg_catalog.=) 20)) ORDER BY key, value, age - key | value | age ---------------------------------------------------------------------- -(0 rows) - -SELECT * FROM second_distributed_table WHERE key = 1 ORDER BY 1,2; -NOTICE: executing the command locally: SELECT key, value FROM local_shard_execution_replicated.second_distributed_table_1500005 second_distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value - key | value ---------------------------------------------------------------------- - 1 | 1 -(1 row) - --- Put row back for other tests -INSERT INTO distributed_table VALUES (1, '22', 20); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 (key, value, age) VALUES (1, '22'::text, 20) -SET citus.enable_ddl_propagation TO OFF; -CREATE VIEW abcd_view AS SELECT * FROM abcd; -RESET citus.enable_ddl_propagation; -SELECT * FROM abcd first join abcd second on first.b = second.b ORDER BY 1,2,3,4; - b | c | d | b | c | d ---------------------------------------------------------------------- - 2 | 3 | 4 | 2 | 3 | 4 - 3 | 4 | 5 | 3 | 4 | 5 - 4 | 5 | 6 | 4 | 5 | 6 -(3 rows) - -BEGIN; -SELECT * FROM abcd first join abcd second on first.b = second.b ORDER BY 1,2,3,4; -NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.b, second.c, second.d FROM (local_shard_execution_replicated.abcd_1500025 first JOIN local_shard_execution_replicated.abcd_1500025 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) WHERE true -NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.b, second.c, second.d FROM (local_shard_execution_replicated.abcd_1500026 first JOIN local_shard_execution_replicated.abcd_1500026 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) WHERE true -NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.b, second.c, second.d FROM (local_shard_execution_replicated.abcd_1500027 first JOIN local_shard_execution_replicated.abcd_1500027 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) WHERE true -NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.b, second.c, second.d FROM (local_shard_execution_replicated.abcd_1500028 first JOIN local_shard_execution_replicated.abcd_1500028 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) WHERE true - b | c | d | b | c | d ---------------------------------------------------------------------- - 2 | 3 | 4 | 2 | 3 | 4 - 3 | 4 | 5 | 3 | 4 | 5 - 4 | 5 | 6 | 4 | 5 | 6 -(3 rows) - -END; -BEGIN; -SELECT * FROM abcd_view first join abcd_view second on first.b = second.b ORDER BY 1,2,3,4; -NOTICE: executing the command locally: SELECT abcd.b, abcd.c, abcd.d, abcd_1.b, abcd_1.c, abcd_1.d FROM (local_shard_execution_replicated.abcd_1500025 abcd JOIN local_shard_execution_replicated.abcd_1500025 abcd_1 ON ((abcd.b OPERATOR(pg_catalog.=) abcd_1.b))) WHERE true -NOTICE: executing the command locally: SELECT abcd.b, abcd.c, abcd.d, abcd_1.b, abcd_1.c, abcd_1.d FROM (local_shard_execution_replicated.abcd_1500026 abcd JOIN local_shard_execution_replicated.abcd_1500026 abcd_1 ON ((abcd.b OPERATOR(pg_catalog.=) abcd_1.b))) WHERE true -NOTICE: executing the command locally: SELECT abcd.b, abcd.c, abcd.d, abcd_1.b, abcd_1.c, abcd_1.d FROM (local_shard_execution_replicated.abcd_1500027 abcd JOIN local_shard_execution_replicated.abcd_1500027 abcd_1 ON ((abcd.b OPERATOR(pg_catalog.=) abcd_1.b))) WHERE true -NOTICE: executing the command locally: SELECT abcd.b, abcd.c, abcd.d, abcd_1.b, abcd_1.c, abcd_1.d FROM (local_shard_execution_replicated.abcd_1500028 abcd JOIN local_shard_execution_replicated.abcd_1500028 abcd_1 ON ((abcd.b OPERATOR(pg_catalog.=) abcd_1.b))) WHERE true - b | c | d | b | c | d ---------------------------------------------------------------------- - 2 | 3 | 4 | 2 | 3 | 4 - 3 | 4 | 5 | 3 | 4 | 5 - 4 | 5 | 6 | 4 | 5 | 6 -(3 rows) - -END; -BEGIN; -SELECT * FROM abcd first full join abcd second on first.b = second.b ORDER BY 1,2,3,4; -NOTICE: executing the command locally: SELECT worker_column_1 AS b, worker_column_2 AS c, worker_column_3 AS d, worker_column_4 AS b, worker_column_5 AS c, worker_column_6 AS d FROM (SELECT first.b AS worker_column_1, first.c AS worker_column_2, first.d AS worker_column_3, second.b AS worker_column_4, second.c AS worker_column_5, second.d AS worker_column_6 FROM (local_shard_execution_replicated.abcd_1500025 first FULL JOIN local_shard_execution_replicated.abcd_1500025 second ON ((first.b OPERATOR(pg_catalog.=) second.b)))) worker_subquery -NOTICE: executing the command locally: SELECT worker_column_1 AS b, worker_column_2 AS c, worker_column_3 AS d, worker_column_4 AS b, worker_column_5 AS c, worker_column_6 AS d FROM (SELECT first.b AS worker_column_1, first.c AS worker_column_2, first.d AS worker_column_3, second.b AS worker_column_4, second.c AS worker_column_5, second.d AS worker_column_6 FROM (local_shard_execution_replicated.abcd_1500026 first FULL JOIN local_shard_execution_replicated.abcd_1500026 second ON ((first.b OPERATOR(pg_catalog.=) second.b)))) worker_subquery -NOTICE: executing the command locally: SELECT worker_column_1 AS b, worker_column_2 AS c, worker_column_3 AS d, worker_column_4 AS b, worker_column_5 AS c, worker_column_6 AS d FROM (SELECT first.b AS worker_column_1, first.c AS worker_column_2, first.d AS worker_column_3, second.b AS worker_column_4, second.c AS worker_column_5, second.d AS worker_column_6 FROM (local_shard_execution_replicated.abcd_1500027 first FULL JOIN local_shard_execution_replicated.abcd_1500027 second ON ((first.b OPERATOR(pg_catalog.=) second.b)))) worker_subquery -NOTICE: executing the command locally: SELECT worker_column_1 AS b, worker_column_2 AS c, worker_column_3 AS d, worker_column_4 AS b, worker_column_5 AS c, worker_column_6 AS d FROM (SELECT first.b AS worker_column_1, first.c AS worker_column_2, first.d AS worker_column_3, second.b AS worker_column_4, second.c AS worker_column_5, second.d AS worker_column_6 FROM (local_shard_execution_replicated.abcd_1500028 first FULL JOIN local_shard_execution_replicated.abcd_1500028 second ON ((first.b OPERATOR(pg_catalog.=) second.b)))) worker_subquery - b | c | d | b | c | d ---------------------------------------------------------------------- - 2 | 3 | 4 | 2 | 3 | 4 - 3 | 4 | 5 | 3 | 4 | 5 - 4 | 5 | 6 | 4 | 5 | 6 -(3 rows) - -END; -BEGIN; -SELECT * FROM abcd first join abcd second USING(b) ORDER BY 1,2,3,4; -NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.c, second.d FROM (local_shard_execution_replicated.abcd_1500025 first JOIN local_shard_execution_replicated.abcd_1500025 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) WHERE true -NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.c, second.d FROM (local_shard_execution_replicated.abcd_1500026 first JOIN local_shard_execution_replicated.abcd_1500026 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) WHERE true -NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.c, second.d FROM (local_shard_execution_replicated.abcd_1500027 first JOIN local_shard_execution_replicated.abcd_1500027 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) WHERE true -NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.c, second.d FROM (local_shard_execution_replicated.abcd_1500028 first JOIN local_shard_execution_replicated.abcd_1500028 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) WHERE true - b | c | d | c | d ---------------------------------------------------------------------- - 2 | 3 | 4 | 3 | 4 - 3 | 4 | 5 | 4 | 5 - 4 | 5 | 6 | 5 | 6 -(3 rows) - -END; -BEGIN; -SELECT * FROM abcd first join abcd second USING(b) join abcd third on first.b=third.b ORDER BY 1,2,3,4; -NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.c, second.d, third.b, third.c, third.d FROM ((local_shard_execution_replicated.abcd_1500025 first JOIN local_shard_execution_replicated.abcd_1500025 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) JOIN local_shard_execution_replicated.abcd_1500025 third ON ((first.b OPERATOR(pg_catalog.=) third.b))) WHERE true -NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.c, second.d, third.b, third.c, third.d FROM ((local_shard_execution_replicated.abcd_1500026 first JOIN local_shard_execution_replicated.abcd_1500026 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) JOIN local_shard_execution_replicated.abcd_1500026 third ON ((first.b OPERATOR(pg_catalog.=) third.b))) WHERE true -NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.c, second.d, third.b, third.c, third.d FROM ((local_shard_execution_replicated.abcd_1500027 first JOIN local_shard_execution_replicated.abcd_1500027 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) JOIN local_shard_execution_replicated.abcd_1500027 third ON ((first.b OPERATOR(pg_catalog.=) third.b))) WHERE true -NOTICE: executing the command locally: SELECT first.b, first.c, first.d, second.c, second.d, third.b, third.c, third.d FROM ((local_shard_execution_replicated.abcd_1500028 first JOIN local_shard_execution_replicated.abcd_1500028 second ON ((first.b OPERATOR(pg_catalog.=) second.b))) JOIN local_shard_execution_replicated.abcd_1500028 third ON ((first.b OPERATOR(pg_catalog.=) third.b))) WHERE true - b | c | d | c | d | b | c | d ---------------------------------------------------------------------- - 2 | 3 | 4 | 3 | 4 | 2 | 3 | 4 - 3 | 4 | 5 | 4 | 5 | 3 | 4 | 5 - 4 | 5 | 6 | 5 | 6 | 4 | 5 | 6 -(3 rows) - -END; --- copy always happens via distributed execution irrespective of the --- shards that are accessed -COPY reference_table FROM STDIN; -COPY distributed_table FROM STDIN WITH CSV; -COPY second_distributed_table FROM STDIN WITH CSV; --- the behaviour in transaction blocks is the following: - -- (a) Unless the first query is a local query, always use distributed execution. - -- (b) If the executor has used local execution, it has to use local execution - -- for the remaining of the transaction block. If that's not possible, the - -- executor has to error out --- rollback should be able to rollback local execution -BEGIN; - INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age - key | value | age ---------------------------------------------------------------------- - 1 | 29 | 20 -(1 row) - - SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3; -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age - key | value | age ---------------------------------------------------------------------- - 1 | 29 | 20 -(1 row) - -ROLLBACK; --- make sure that the value is rollbacked -SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3; -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age - key | value | age ---------------------------------------------------------------------- - 1 | 22 | 20 -(1 row) - --- rollback should be able to rollback both the local and distributed executions -BEGIN; - INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age - key | value | age ---------------------------------------------------------------------- - 1 | 29 | 20 -(1 row) - - DELETE FROM distributed_table; -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table - SELECT count(*) FROM second_distributed_table; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.second_distributed_table_1500005 second_distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.second_distributed_table_1500006 second_distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.second_distributed_table_1500007 second_distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.second_distributed_table_1500008 second_distributed_table WHERE true - count ---------------------------------------------------------------------- - 2 -(1 row) - -ROLLBACK; --- make sure that everything is rollbacked -SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3; -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age - key | value | age ---------------------------------------------------------------------- - 1 | 22 | 20 -(1 row) - -SELECT count(*) FROM second_distributed_table; - count ---------------------------------------------------------------------- - 2 -(1 row) - -SELECT * FROM second_distributed_table ORDER BY 1; - key | value ---------------------------------------------------------------------- - 1 | 1 - 6 | '6' -(2 rows) - --- very simple examples, an SELECTs should see the modifications --- that has done before -BEGIN; - -- INSERT is executed locally - INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '23' RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '23'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age - key | value | age ---------------------------------------------------------------------- - 1 | 23 | 20 -(1 row) - - -- since the INSERT is executed locally, the SELECT should also be - -- executed locally and see the changes - SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3; -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age - key | value | age ---------------------------------------------------------------------- - 1 | 23 | 20 -(1 row) - - -- multi-shard SELECTs are now forced to use local execution on - -- the shards that reside on this node - SELECT * FROM distributed_table WHERE value = '23' ORDER BY 1,2,3; -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) - key | value | age ---------------------------------------------------------------------- - 1 | 23 | 20 -(1 row) - - -- similarly, multi-shard modifications should use local exection - -- on the shards that reside on this node - DELETE FROM distributed_table WHERE value = '23'; -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) - -- make sure that the value is deleted - SELECT * FROM distributed_table WHERE value = '23' ORDER BY 1,2,3; -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text) - key | value | age ---------------------------------------------------------------------- -(0 rows) - -COMMIT; --- make sure that we've committed everything -SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3; -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age - key | value | age ---------------------------------------------------------------------- -(0 rows) - --- if we start with a distributed execution, we should keep --- using that and never switch back to local execution -BEGIN; - DELETE FROM distributed_table WHERE value = '11'; -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (value OPERATOR(pg_catalog.=) '11'::text) -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE (value OPERATOR(pg_catalog.=) '11'::text) -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (value OPERATOR(pg_catalog.=) '11'::text) -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE (value OPERATOR(pg_catalog.=) '11'::text) - -- although this command could have been executed - -- locally, it is not going to be executed locally - SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3; -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age - key | value | age ---------------------------------------------------------------------- -(0 rows) - - -- but we can still execute parallel queries, even if - -- they are utility commands - TRUNCATE distributed_table CASCADE; -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.distributed_table_xxxxx CASCADE -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.distributed_table_xxxxx CASCADE -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.distributed_table_xxxxx CASCADE -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.distributed_table_xxxxx CASCADE - -- TRUNCATE didn't cascade into second_distributed_table - SELECT count(*) FROM second_distributed_table; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.second_distributed_table_1500005 second_distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.second_distributed_table_1500006 second_distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.second_distributed_table_1500007 second_distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.second_distributed_table_1500008 second_distributed_table WHERE true - count ---------------------------------------------------------------------- - 2 -(1 row) - -ROLLBACK; --- load some data -INSERT INTO reference_table SELECT i FROM generate_series(500, 600) i; -NOTICE: executing the copy locally for shard xxxxx --- show that complex tx blocks work fine -BEGIN; - INSERT INTO reference_table VALUES (701); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.reference_table_1500000 (key) VALUES (701) - INSERT INTO distributed_table VALUES (701, '701', 701); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 (key, value, age) VALUES (701, '701'::text, 701) - INSERT INTO second_distributed_table VALUES (701, '701'); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.second_distributed_table_1500005 (key, value) VALUES (701, '701'::text) - DELETE FROM reference_table WHERE key = 701; -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.reference_table_1500000 reference_table WHERE (key OPERATOR(pg_catalog.=) 701) - SELECT count(*) FROM distributed_table WHERE key = 701; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 701) - count ---------------------------------------------------------------------- - 1 -(1 row) - - SELECT count(*) FROM second_distributed_table WHERE key = 701; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.second_distributed_table_1500005 second_distributed_table WHERE (key OPERATOR(pg_catalog.=) 701) - count ---------------------------------------------------------------------- - 1 -(1 row) - - -- multi-shard commands should also see the changes - SELECT count(*) FROM distributed_table WHERE key > 700; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.>) 700) -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE (key OPERATOR(pg_catalog.>) 700) -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.>) 700) -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE (key OPERATOR(pg_catalog.>) 700) - count ---------------------------------------------------------------------- - 1 -(1 row) - - -- we can still do multi-shard commands - DELETE FROM distributed_table; -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table -ROLLBACK; --- multiple queries hitting different shards can be executed locally -BEGIN; - SELECT count(*) FROM distributed_table WHERE key = 1; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 0 -(1 row) - - SELECT count(*) FROM distributed_table WHERE key = 6; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6) - count ---------------------------------------------------------------------- - 1 -(1 row) - - SELECT count(*) FROM distributed_table WHERE key = 500; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) - count ---------------------------------------------------------------------- - 0 -(1 row) - -ROLLBACK; --- a local query followed by TRUNCATE command can be executed locally -BEGIN; - SELECT count(*) FROM distributed_table WHERE key = 1; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 0 -(1 row) - - TRUNCATE distributed_table CASCADE; -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.distributed_table_xxxxx CASCADE -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.distributed_table_xxxxx CASCADE -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.distributed_table_xxxxx CASCADE -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.distributed_table_xxxxx CASCADE -ROLLBACK; --- a local query is followed by an INSERT..SELECT via the coordinator -BEGIN; - SELECT count(*) FROM distributed_table WHERE key = 1; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 0 -(1 row) - - INSERT INTO distributed_table (key) SELECT i FROM generate_series(1,1) i; -NOTICE: executing the copy locally for shard xxxxx -ROLLBACK; -BEGIN; -SET citus.enable_repartition_joins TO ON; -SET citus.enable_unique_job_ids TO off; -SELECT count(*) FROM distributed_table; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE true - count ---------------------------------------------------------------------- - 2 -(1 row) - -SELECT count(*) FROM distributed_table d1 join distributed_table d2 using(age); -NOTICE: executing the command locally: SELECT partition_index, 'repartition_69_1' || '_' || partition_index::text , rows_written FROM pg_catalog.worker_partition_query_result('repartition_69_1','SELECT age AS column1 FROM local_shard_execution_replicated.distributed_table_1500001 d1 WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true,true,true) WHERE rows_written > 0 -NOTICE: executing the command locally: SELECT partition_index, 'repartition_69_3' || '_' || partition_index::text , rows_written FROM pg_catalog.worker_partition_query_result('repartition_69_3','SELECT age AS column1 FROM local_shard_execution_replicated.distributed_table_1500003 d1 WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true,true,true) WHERE rows_written > 0 -NOTICE: executing the command locally: SELECT partition_index, 'repartition_70_1' || '_' || partition_index::text , rows_written FROM pg_catalog.worker_partition_query_result('repartition_70_1','SELECT age AS column1 FROM local_shard_execution_replicated.distributed_table_1500001 d2 WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true,true,true) WHERE rows_written > 0 -NOTICE: executing the command locally: SELECT partition_index, 'repartition_70_3' || '_' || partition_index::text , rows_written FROM pg_catalog.worker_partition_query_result('repartition_70_3','SELECT age AS column1 FROM local_shard_execution_replicated.distributed_table_1500003 d2 WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true,true,true) WHERE rows_written > 0 -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_69_1_0']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_69_2_0']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_69_3_0']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_69_4_0']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_1_0']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_2_0']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_3_0']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_4_0']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_69_1_1']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_69_2_1']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_69_3_1']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_69_4_1']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_1_1']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_2_1']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_3_1']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_4_1']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_69_1_2']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_69_2_2']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_69_3_2']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_69_4_2']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_1_2']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_2_2']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_3_2']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_4_2']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_69_1_3']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_69_2_3']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_69_3_3']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_69_4_3']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_1_3']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_2_3']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_3_3']::text[],'localhost',57637) bytes -NOTICE: executing the command locally: SELECT bytes FROM fetch_intermediate_results(ARRAY['repartition_70_4_3']::text[],'localhost',57638) bytes -NOTICE: executing the command locally: SELECT count(*) AS count FROM (read_intermediate_results('{repartition_69_1_0,repartition_69_2_0,repartition_69_3_0,repartition_69_4_0}'::text[], 'binary'::citus_copy_format) intermediate_result(column1 bigint) JOIN read_intermediate_results('{repartition_70_1_0,repartition_70_2_0,repartition_70_3_0,repartition_70_4_0}'::text[], 'binary'::citus_copy_format) intermediate_result_1(column1 bigint) ON ((intermediate_result.column1 OPERATOR(pg_catalog.=) intermediate_result_1.column1))) WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM (read_intermediate_results('{repartition_69_1_1,repartition_69_2_1,repartition_69_3_1,repartition_69_4_1}'::text[], 'binary'::citus_copy_format) intermediate_result(column1 bigint) JOIN read_intermediate_results('{repartition_70_1_1,repartition_70_2_1,repartition_70_3_1,repartition_70_4_1}'::text[], 'binary'::citus_copy_format) intermediate_result_1(column1 bigint) ON ((intermediate_result.column1 OPERATOR(pg_catalog.=) intermediate_result_1.column1))) WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM (read_intermediate_results('{repartition_69_1_2,repartition_69_2_2,repartition_69_3_2,repartition_69_4_2}'::text[], 'binary'::citus_copy_format) intermediate_result(column1 bigint) JOIN read_intermediate_results('{repartition_70_1_2,repartition_70_2_2,repartition_70_3_2,repartition_70_4_2}'::text[], 'binary'::citus_copy_format) intermediate_result_1(column1 bigint) ON ((intermediate_result.column1 OPERATOR(pg_catalog.=) intermediate_result_1.column1))) WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM (read_intermediate_results('{repartition_69_1_3,repartition_69_2_3,repartition_69_3_3,repartition_69_4_3}'::text[], 'binary'::citus_copy_format) intermediate_result(column1 bigint) JOIN read_intermediate_results('{repartition_70_1_3,repartition_70_2_3,repartition_70_3_3,repartition_70_4_3}'::text[], 'binary'::citus_copy_format) intermediate_result_1(column1 bigint) ON ((intermediate_result.column1 OPERATOR(pg_catalog.=) intermediate_result_1.column1))) WHERE true - count ---------------------------------------------------------------------- - 2 -(1 row) - -ROLLBACK; --- a local query is followed by an INSERT..SELECT with re-partitioning -BEGIN; - SELECT count(*) FROM distributed_table WHERE key = 6; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6) - count ---------------------------------------------------------------------- - 1 -(1 row) - - INSERT INTO reference_table (key) SELECT -key FROM distributed_table; -NOTICE: executing the command locally: SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE true -NOTICE: executing the command locally: SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE true -NOTICE: executing the command locally: SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE true -NOTICE: executing the command locally: SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE true -NOTICE: executing the copy locally for shard xxxxx - INSERT INTO distributed_table (key) SELECT -key FROM distributed_table; -NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_1500001_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_1500001_to','SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true) WHERE rows_written > 0 -NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_1500002_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_1500002_to','SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true) WHERE rows_written > 0 -NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_1500003_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_1500003_to','SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true) WHERE rows_written > 0 -NOTICE: executing the command locally: SELECT partition_index, 'repartitioned_results_xxxxx_from_1500004_to' || '_' || partition_index::text , rows_written FROM worker_partition_query_result('repartitioned_results_xxxxx_from_1500004_to','SELECT (OPERATOR(pg_catalog.-) key) AS key FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE true',0,'hash','{-2147483648,-1073741824,0,1073741824}'::text[],'{-1073741825,-1,1073741823,2147483647}'::text[],true) WHERE rows_written > 0 -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key) SELECT key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1500003_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer) -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500004 AS citus_table_alias (key) SELECT key FROM read_intermediate_results('{repartitioned_results_xxxxx_from_1500004_to_3}'::text[], 'binary'::citus_copy_format) intermediate_result(key integer) - SELECT count(*) FROM distributed_table WHERE key = -6; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) '-6'::integer) - count ---------------------------------------------------------------------- - 1 -(1 row) - -ROLLBACK; -INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age - key | value | age ---------------------------------------------------------------------- - 1 | 11 | 21 -(1 row) - -BEGIN; - DELETE FROM distributed_table WHERE key = 1; -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - EXPLAIN ANALYZE DELETE FROM distributed_table WHERE key = 1; -ERROR: cannot execute command because a local execution has accessed a placement in the transaction -DETAIL: Some parallel commands cannot be executed if a previous command has already been executed locally -HINT: Try re-running the transaction with "SET LOCAL citus.enable_local_execution TO OFF;" -ROLLBACK; -BEGIN; - INSERT INTO distributed_table VALUES (11, '111',29) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500004 AS citus_table_alias (key, value, age) VALUES (11, '111'::text, 29) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age - key | value | age ---------------------------------------------------------------------- - 11 | 29 | 121 -(1 row) - - -- this is already disallowed on the nodes, adding it in case we - -- support DDLs from the worker nodes in the future - ALTER TABLE distributed_table ADD COLUMN x INT; -ERROR: operation is not allowed on this node -HINT: Connect to the coordinator and run it again. -ROLLBACK; -BEGIN; - INSERT INTO distributed_table VALUES (11, '111',29) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500004 AS citus_table_alias (key, value, age) VALUES (11, '111'::text, 29) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age - key | value | age ---------------------------------------------------------------------- - 11 | 29 | 121 -(1 row) - - -- this is already disallowed because VACUUM cannot be executed in tx block - -- adding in case this is supported some day - VACUUM second_distributed_table; -ERROR: VACUUM cannot run inside a transaction block -ROLLBACK; --- make sure that functions can use local execution -SET citus.enable_metadata_sync TO OFF; -CREATE OR REPLACE PROCEDURE only_local_execution() AS $$ - DECLARE cnt INT; - BEGIN - INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'; - SELECT count(*) INTO cnt FROM distributed_table WHERE key = 1; - DELETE FROM distributed_table WHERE key = 1; - END; -$$ LANGUAGE plpgsql; -CALL only_local_execution(); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text -CONTEXT: SQL statement "INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'" -PL/pgSQL function only_local_execution() line XX at SQL statement -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) -CONTEXT: SQL statement "SELECT count(*) FROM distributed_table WHERE key = 1" -PL/pgSQL function only_local_execution() line XX at SQL statement -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) -CONTEXT: SQL statement "DELETE FROM distributed_table WHERE key = 1" -PL/pgSQL function only_local_execution() line XX at SQL statement --- insert a row that we need in the next tests -INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text --- make sure that functions can use local execution -CREATE OR REPLACE PROCEDURE only_local_execution_with_function_evaluation() AS $$ - DECLARE nodeId INT; - BEGIN - -- fast path router - SELECT get_local_node_id_volatile() INTO nodeId FROM distributed_table WHERE key = 1; - IF nodeId <= 0 THEN - RAISE NOTICE 'unexpected node id'; - END IF; - - -- regular router - SELECT get_local_node_id_volatile() INTO nodeId FROM distributed_table d1 JOIN distributed_table d2 USING (key) WHERE d1.key = 1; - IF nodeId <= 0 THEN - RAISE NOTICE 'unexpected node id'; - END IF; - END; -$$ LANGUAGE plpgsql; -CALL only_local_execution_with_function_evaluation(); -NOTICE: executing the command locally: SELECT local_shard_execution_replicated.get_local_node_id_volatile() AS get_local_node_id_volatile FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) -CONTEXT: SQL statement "SELECT get_local_node_id_volatile() FROM distributed_table WHERE key = 1" -PL/pgSQL function only_local_execution_with_function_evaluation() line XX at SQL statement -NOTICE: executing the command locally: SELECT local_shard_execution_replicated.get_local_node_id_volatile() AS get_local_node_id_volatile FROM (local_shard_execution_replicated.distributed_table_1500001 d1(key, value, age) JOIN local_shard_execution_replicated.distributed_table_1500001 d2(key, value, age) USING (key)) WHERE (d1.key OPERATOR(pg_catalog.=) 1) -CONTEXT: SQL statement "SELECT get_local_node_id_volatile() FROM distributed_table d1 JOIN distributed_table d2 USING (key) WHERE d1.key = 1" -PL/pgSQL function only_local_execution_with_function_evaluation() line XX at SQL statement -CREATE OR REPLACE PROCEDURE only_local_execution_with_params(int) AS $$ - DECLARE cnt INT; - BEGIN - INSERT INTO distributed_table VALUES ($1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'; - SELECT count(*) INTO cnt FROM distributed_table WHERE key = $1; - DELETE FROM distributed_table WHERE key = $1; - END; -$$ LANGUAGE plpgsql; -CALL only_local_execution_with_params(1); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '29'::text -CONTEXT: SQL statement "INSERT INTO distributed_table VALUES ($1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'" -PL/pgSQL function only_local_execution_with_params(integer) line XX at SQL statement -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) -CONTEXT: SQL statement "SELECT count(*) FROM distributed_table WHERE key = $1" -PL/pgSQL function only_local_execution_with_params(integer) line XX at SQL statement -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) -CONTEXT: SQL statement "DELETE FROM distributed_table WHERE key = $1" -PL/pgSQL function only_local_execution_with_params(integer) line XX at SQL statement -CREATE OR REPLACE PROCEDURE only_local_execution_with_function_evaluation_param(int) AS $$ - DECLARE nodeId INT; - BEGIN - -- fast path router - SELECT get_local_node_id_volatile() INTO nodeId FROM distributed_table WHERE key = $1; - IF nodeId <= 0 THEN - RAISE NOTICE 'unexpected node id'; - END IF; - - -- regular router - SELECT get_local_node_id_volatile() INTO nodeId FROM distributed_table d1 JOIN distributed_table d2 USING (key) WHERE d1.key = $1; - IF nodeId <= 0 THEN - RAISE NOTICE 'unexpected node id'; - END IF; - END; -$$ LANGUAGE plpgsql; -CALL only_local_execution_with_function_evaluation_param(1); -NOTICE: executing the command locally: SELECT local_shard_execution_replicated.get_local_node_id_volatile() AS get_local_node_id_volatile FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) -CONTEXT: SQL statement "SELECT get_local_node_id_volatile() FROM distributed_table WHERE key = $1" -PL/pgSQL function only_local_execution_with_function_evaluation_param(integer) line XX at SQL statement -NOTICE: executing the command locally: SELECT local_shard_execution_replicated.get_local_node_id_volatile() AS get_local_node_id_volatile FROM (local_shard_execution_replicated.distributed_table_1500001 d1(key, value, age) JOIN local_shard_execution_replicated.distributed_table_1500001 d2(key, value, age) USING (key)) WHERE (d1.key OPERATOR(pg_catalog.=) $1) -CONTEXT: SQL statement "SELECT get_local_node_id_volatile() FROM distributed_table d1 JOIN distributed_table d2 USING (key) WHERE d1.key = $1" -PL/pgSQL function only_local_execution_with_function_evaluation_param(integer) line XX at SQL statement -CREATE OR REPLACE PROCEDURE local_execution_followed_by_dist() AS $$ - DECLARE cnt INT; - BEGIN - INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'; - SELECT count(*) INTO cnt FROM distributed_table WHERE key = 1; - DELETE FROM distributed_table; - SELECT count(*) INTO cnt FROM distributed_table; - END; -$$ LANGUAGE plpgsql; -RESET citus.enable_metadata_sync; -CALL local_execution_followed_by_dist(); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text -CONTEXT: SQL statement "INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'" -PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) -CONTEXT: SQL statement "SELECT count(*) FROM distributed_table WHERE key = 1" -PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table -CONTEXT: SQL statement "DELETE FROM distributed_table" -PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table -CONTEXT: SQL statement "DELETE FROM distributed_table" -PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table -CONTEXT: SQL statement "DELETE FROM distributed_table" -PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table -CONTEXT: SQL statement "DELETE FROM distributed_table" -PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE true -CONTEXT: SQL statement "SELECT count(*) FROM distributed_table" -PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE true -CONTEXT: SQL statement "SELECT count(*) FROM distributed_table" -PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE true -CONTEXT: SQL statement "SELECT count(*) FROM distributed_table" -PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE true -CONTEXT: SQL statement "SELECT count(*) FROM distributed_table" -PL/pgSQL function local_execution_followed_by_dist() line XX at SQL statement --- test CTEs, including modifying CTEs -WITH local_insert AS (INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *), -distributed_local_mixed AS (SELECT * FROM reference_table WHERE key IN (SELECT key FROM local_insert)) -SELECT * FROM local_insert, distributed_local_mixed; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age -NOTICE: executing the command locally: SELECT key FROM local_shard_execution_replicated.reference_table_1500000 reference_table WHERE (key OPERATOR(pg_catalog.=) ANY (SELECT local_insert.key FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) local_insert)) -NOTICE: executing the command locally: SELECT local_insert.key, local_insert.value, local_insert.age, distributed_local_mixed.key FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) local_insert, (SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) distributed_local_mixed - key | value | age | key ---------------------------------------------------------------------- - 1 | 11 | 21 | 1 -(1 row) - --- since we start with parallel execution, we do not switch back to local execution in the --- latter CTEs -WITH distributed_local_mixed AS (SELECT * FROM distributed_table), -local_insert AS (INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *) -SELECT * FROM local_insert, distributed_local_mixed ORDER BY 1,2,3,4,5; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age -NOTICE: executing the command locally: SELECT worker_column_1 AS key, worker_column_2 AS value, worker_column_3 AS age, worker_column_4 AS key, worker_column_5 AS value, worker_column_6 AS age FROM (SELECT local_insert.key AS worker_column_1, local_insert.value AS worker_column_2, local_insert.age AS worker_column_3, distributed_local_mixed.key AS worker_column_4, distributed_local_mixed.value AS worker_column_5, distributed_local_mixed.age AS worker_column_6 FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) local_insert, (SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table) distributed_local_mixed) worker_subquery -NOTICE: executing the command locally: SELECT worker_column_1 AS key, worker_column_2 AS value, worker_column_3 AS age, worker_column_4 AS key, worker_column_5 AS value, worker_column_6 AS age FROM (SELECT local_insert.key AS worker_column_1, local_insert.value AS worker_column_2, local_insert.age AS worker_column_3, distributed_local_mixed.key AS worker_column_4, distributed_local_mixed.value AS worker_column_5, distributed_local_mixed.age AS worker_column_6 FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) local_insert, (SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table) distributed_local_mixed) worker_subquery -NOTICE: executing the command locally: SELECT worker_column_1 AS key, worker_column_2 AS value, worker_column_3 AS age, worker_column_4 AS key, worker_column_5 AS value, worker_column_6 AS age FROM (SELECT local_insert.key AS worker_column_1, local_insert.value AS worker_column_2, local_insert.age AS worker_column_3, distributed_local_mixed.key AS worker_column_4, distributed_local_mixed.value AS worker_column_5, distributed_local_mixed.age AS worker_column_6 FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) local_insert, (SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table) distributed_local_mixed) worker_subquery -NOTICE: executing the command locally: SELECT worker_column_1 AS key, worker_column_2 AS value, worker_column_3 AS age, worker_column_4 AS key, worker_column_5 AS value, worker_column_6 AS age FROM (SELECT local_insert.key AS worker_column_1, local_insert.value AS worker_column_2, local_insert.age AS worker_column_3, distributed_local_mixed.key AS worker_column_4, distributed_local_mixed.value AS worker_column_5, distributed_local_mixed.age AS worker_column_6 FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) local_insert, (SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table) distributed_local_mixed) worker_subquery - key | value | age | key | value | age ---------------------------------------------------------------------- - 1 | 29 | 21 | 1 | 11 | 21 -(1 row) - --- router CTE pushdown -WITH all_data AS (SELECT * FROM distributed_table WHERE key = 1) -SELECT - count(*) -FROM - distributed_table, all_data -WHERE - distributed_table.key = all_data.key AND distributed_table.key = 1; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table, (SELECT distributed_table_1.key, distributed_table_1.value, distributed_table_1.age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table_1 WHERE (distributed_table_1.key OPERATOR(pg_catalog.=) 1)) all_data WHERE ((distributed_table.key OPERATOR(pg_catalog.=) all_data.key) AND (distributed_table.key OPERATOR(pg_catalog.=) 1)) - count ---------------------------------------------------------------------- - 1 -(1 row) - -INSERT INTO reference_table VALUES (2); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.reference_table_1500000 (key) VALUES (2) -INSERT INTO distributed_table VALUES (2, '29', 29); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500004 (key, value, age) VALUES (2, '29'::text, 29) -INSERT INTO second_distributed_table VALUES (2, '29'); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.second_distributed_table_1500008 (key, value) VALUES (2, '29'::text) --- single shard that is not a local query followed by a local query -WITH all_data AS (SELECT * FROM second_distributed_table WHERE key = 2) -SELECT - distributed_table.key -FROM - distributed_table, all_data -WHERE - distributed_table.value = all_data.value AND distributed_table.key = 1 -ORDER BY - 1 DESC; -NOTICE: executing the command locally: SELECT key, value FROM local_shard_execution_replicated.second_distributed_table_1500008 second_distributed_table WHERE (key OPERATOR(pg_catalog.=) 2) -NOTICE: executing the command locally: SELECT distributed_table.key FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table, (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) all_data WHERE ((distributed_table.value OPERATOR(pg_catalog.=) all_data.value) AND (distributed_table.key OPERATOR(pg_catalog.=) 1)) ORDER BY distributed_table.key DESC - key ---------------------------------------------------------------------- - 1 -(1 row) - --- multi-shard CTE is followed by a query which could be executed locally, but --- since the query started with a parallel query, it doesn't use local execution --- note that if we allow Postgres to inline the CTE (e.g., not have the EXISTS --- subquery), then it'd pushdown the filters and the query becomes single-shard, --- locally executable query -WITH all_data AS (SELECT * FROM distributed_table) -SELECT - count(*) -FROM - distributed_table, all_data -WHERE - distributed_table.key = all_data.key AND distributed_table.key = 1 - AND EXISTS (SELECT * FROM all_data); -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE true -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE true -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE true -NOTICE: executing the command locally: SELECT key, value, age FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table, (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) all_data WHERE ((distributed_table.key OPERATOR(pg_catalog.=) all_data.key) AND (distributed_table.key OPERATOR(pg_catalog.=) 1) AND (EXISTS (SELECT all_data_1.key, all_data_1.value, all_data_1.age FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) all_data_1))) - count ---------------------------------------------------------------------- - 1 -(1 row) - --- in pg12, the following CTE can be inlined, still the query becomes --- a subquery that needs to be recursively planned and a parallel --- query, so do not use local execution -WITH all_data AS (SELECT age FROM distributed_table) -SELECT - count(*) -FROM - distributed_table, all_data -WHERE - distributed_table.key = all_data.age AND distributed_table.key = 1; -NOTICE: executing the command locally: SELECT age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE true -NOTICE: executing the command locally: SELECT age FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE true -NOTICE: executing the command locally: SELECT age FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE true -NOTICE: executing the command locally: SELECT age FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table, (SELECT intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(age bigint)) all_data WHERE ((distributed_table.key OPERATOR(pg_catalog.=) all_data.age) AND (distributed_table.key OPERATOR(pg_catalog.=) 1)) - count ---------------------------------------------------------------------- - 0 -(1 row) - --- get ready for the next commands -TRUNCATE reference_table, distributed_table, second_distributed_table; -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.reference_table_xxxxx CASCADE -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.distributed_table_xxxxx CASCADE -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.distributed_table_xxxxx CASCADE -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.distributed_table_xxxxx CASCADE -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.distributed_table_xxxxx CASCADE -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.second_distributed_table_xxxxx CASCADE -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.second_distributed_table_xxxxx CASCADE -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.second_distributed_table_xxxxx CASCADE -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.second_distributed_table_xxxxx CASCADE --- local execution of returning of reference tables -INSERT INTO reference_table VALUES (1),(2),(3),(4),(5),(6) RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.reference_table_1500000 AS citus_table_alias (key) VALUES (1), (2), (3), (4), (5), (6) RETURNING citus_table_alias.key - key ---------------------------------------------------------------------- - 1 - 2 - 3 - 4 - 5 - 6 -(6 rows) - --- local execution of multi-row INSERTs -INSERT INTO distributed_table VALUES (1, '11',21), (5,'55',22) ON CONFLICT(key) DO UPDATE SET value = (EXCLUDED.value::int + 1)::text RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'11'::text,'21'::bigint), (5,'55'::text,'22'::bigint) ON CONFLICT(key) DO UPDATE SET value = (((excluded.value)::integer OPERATOR(pg_catalog.+) 1))::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age - key | value | age ---------------------------------------------------------------------- - 1 | 11 | 21 - 5 | 55 | 22 -(2 rows) - --- distributed execution of multi-rows INSERTs, where executor --- is smart enough to execute local tasks via local execution -INSERT INTO distributed_table VALUES (1, '11',21), (2,'22',22), (3,'33',33), (4,'44',44),(5,'55',55) ON CONFLICT(key) DO UPDATE SET value = (EXCLUDED.value::int + 1)::text RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'11'::text,'21'::bigint), (5,'55'::text,'55'::bigint) ON CONFLICT(key) DO UPDATE SET value = (((excluded.value)::integer OPERATOR(pg_catalog.+) 1))::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500002 AS citus_table_alias (key, value, age) VALUES (3,'33'::text,'33'::bigint), (4,'44'::text,'44'::bigint) ON CONFLICT(key) DO UPDATE SET value = (((excluded.value)::integer OPERATOR(pg_catalog.+) 1))::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500004 AS citus_table_alias (key, value, age) VALUES (2,'22'::text,'22'::bigint) ON CONFLICT(key) DO UPDATE SET value = (((excluded.value)::integer OPERATOR(pg_catalog.+) 1))::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age - key | value | age ---------------------------------------------------------------------- - 1 | 12 | 21 - 2 | 22 | 22 - 3 | 33 | 33 - 4 | 44 | 44 - 5 | 56 | 22 -(5 rows) - -PREPARE local_prepare_no_param AS SELECT count(*) FROM distributed_table WHERE key = 1; -PREPARE local_prepare_no_param_subquery AS -SELECT DISTINCT trim(value) FROM ( - SELECT value FROM distributed_table - WHERE - key IN (1, 6, 500, 701) - AND (select 2) > random() - order by 1 - limit 2 - ) t; -PREPARE local_prepare_param (int) AS SELECT count(*) FROM distributed_table WHERE key = $1; -PREPARE remote_prepare_param (int) AS SELECT count(*) FROM distributed_table WHERE key != $1; -BEGIN; - -- 8 local execution without params - EXECUTE local_prepare_no_param; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - - EXECUTE local_prepare_no_param; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - - EXECUTE local_prepare_no_param; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - - EXECUTE local_prepare_no_param; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - - EXECUTE local_prepare_no_param; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - - EXECUTE local_prepare_no_param; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - - EXECUTE local_prepare_no_param; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - - EXECUTE local_prepare_no_param; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - - -- 8 local execution without params and some subqueries - EXECUTE local_prepare_no_param_subquery; -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT DISTINCT TRIM(BOTH FROM value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t - btrim ---------------------------------------------------------------------- - 12 -(1 row) - - EXECUTE local_prepare_no_param_subquery; -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT DISTINCT TRIM(BOTH FROM value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t - btrim ---------------------------------------------------------------------- - 12 -(1 row) - - EXECUTE local_prepare_no_param_subquery; -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT DISTINCT TRIM(BOTH FROM value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t - btrim ---------------------------------------------------------------------- - 12 -(1 row) - - EXECUTE local_prepare_no_param_subquery; -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT DISTINCT TRIM(BOTH FROM value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t - btrim ---------------------------------------------------------------------- - 12 -(1 row) - - EXECUTE local_prepare_no_param_subquery; -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT DISTINCT TRIM(BOTH FROM value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t - btrim ---------------------------------------------------------------------- - 12 -(1 row) - - EXECUTE local_prepare_no_param_subquery; -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT DISTINCT TRIM(BOTH FROM value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t - btrim ---------------------------------------------------------------------- - 12 -(1 row) - - EXECUTE local_prepare_no_param_subquery; -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT DISTINCT TRIM(BOTH FROM value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t - btrim ---------------------------------------------------------------------- - 12 -(1 row) - - EXECUTE local_prepare_no_param_subquery; -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint -NOTICE: executing the command locally: SELECT DISTINCT TRIM(BOTH FROM value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t - btrim ---------------------------------------------------------------------- - 12 -(1 row) - - -- 8 local executions with params - EXECUTE local_prepare_param(1); -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - - EXECUTE local_prepare_param(5); -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 5) - count ---------------------------------------------------------------------- - 1 -(1 row) - - EXECUTE local_prepare_param(6); -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6) - count ---------------------------------------------------------------------- - 0 -(1 row) - - EXECUTE local_prepare_param(1); -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - - EXECUTE local_prepare_param(5); -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 5) - count ---------------------------------------------------------------------- - 1 -(1 row) - - EXECUTE local_prepare_param(6); -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6) - count ---------------------------------------------------------------------- - 0 -(1 row) - - EXECUTE local_prepare_param(6); -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6) - count ---------------------------------------------------------------------- - 0 -(1 row) - - EXECUTE local_prepare_param(6); -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6) - count ---------------------------------------------------------------------- - 0 -(1 row) - - -- followed by a non-local execution - EXECUTE remote_prepare_param(1); -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 1) -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 1) -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 1) -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 1) - count ---------------------------------------------------------------------- - 4 -(1 row) - -COMMIT; -PREPARE local_insert_prepare_no_param AS INSERT INTO distributed_table VALUES (1+0*random(), '11',21::int) ON CONFLICT(key) DO UPDATE SET value = '29' || '28' RETURNING *, key + 1, value || '30', age * 15; -PREPARE local_insert_prepare_param (int) AS INSERT INTO distributed_table VALUES ($1+0*random(), '11',21::int) ON CONFLICT(key) DO UPDATE SET value = '29' || '28' RETURNING *, key + 1, value || '30', age * 15; -BEGIN; - -- 8 local execution without params - EXECUTE local_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 1 | 2928 | 21 | 2 | 292830 | 315 -(1 row) - - EXECUTE local_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 1 | 2928 | 21 | 2 | 292830 | 315 -(1 row) - - EXECUTE local_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 1 | 2928 | 21 | 2 | 292830 | 315 -(1 row) - - EXECUTE local_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 1 | 2928 | 21 | 2 | 292830 | 315 -(1 row) - - EXECUTE local_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 1 | 2928 | 21 | 2 | 292830 | 315 -(1 row) - - EXECUTE local_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 1 | 2928 | 21 | 2 | 292830 | 315 -(1 row) - - EXECUTE local_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 1 | 2928 | 21 | 2 | 292830 | 315 -(1 row) - - EXECUTE local_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 1 | 2928 | 21 | 2 | 292830 | 315 -(1 row) - - -- 8 local executions with params - EXECUTE local_insert_prepare_param(1); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 1 | 2928 | 21 | 2 | 292830 | 315 -(1 row) - - EXECUTE local_insert_prepare_param(5); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 5 | 2928 | 22 | 6 | 292830 | 330 -(1 row) - - EXECUTE local_insert_prepare_param(6); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 6 | 11 | 21 | 7 | 1130 | 315 -(1 row) - - EXECUTE local_insert_prepare_param(1); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 1 | 2928 | 21 | 2 | 292830 | 315 -(1 row) - - EXECUTE local_insert_prepare_param(5); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 5 | 2928 | 22 | 6 | 292830 | 330 -(1 row) - - EXECUTE local_insert_prepare_param(6); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 6 | 2928 | 21 | 7 | 292830 | 315 -(1 row) - - EXECUTE local_insert_prepare_param(6); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 6 | 2928 | 21 | 7 | 292830 | 315 -(1 row) - - EXECUTE local_insert_prepare_param(6); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15) - key | value | age | ?column? | ?column? | ?column? ---------------------------------------------------------------------- - 6 | 2928 | 21 | 7 | 292830 | 315 -(1 row) - - -- followed by a non-local execution - EXECUTE remote_prepare_param(2); -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 2) -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 2) -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 2) -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 2) - count ---------------------------------------------------------------------- - 5 -(1 row) - -COMMIT; -PREPARE local_multi_row_insert_prepare_no_param AS - INSERT INTO distributed_table VALUES (1,'55', 21), (5,'15',33) ON CONFLICT (key) WHERE key > 3 and key < 4 DO UPDATE SET value = '88' || EXCLUDED.value; -PREPARE local_multi_row_insert_prepare_no_param_multi_shard AS - INSERT INTO distributed_table VALUES (6,'55', 21), (5,'15',33) ON CONFLICT (key) WHERE key > 3 AND key < 4 DO UPDATE SET value = '88' || EXCLUDED.value;; -PREPARE local_multi_row_insert_prepare_params(int,int) AS - INSERT INTO distributed_table VALUES ($1,'55', 21), ($2,'15',33) ON CONFLICT (key) WHERE key > 3 and key < 4 DO UPDATE SET value = '88' || EXCLUDED.value;; -INSERT INTO reference_table VALUES (11); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.reference_table_1500000 (key) VALUES (11) -BEGIN; - EXECUTE local_multi_row_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_no_param_multi_shard; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_params(1,6); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_params(1,5); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_params(6,5); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_params(5,1); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'55'::text,'21'::bigint), (1,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_params(5,6); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_params(5,1); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'55'::text,'21'::bigint), (1,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_params(1,6); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500003 AS citus_table_alias (key, value, age) VALUES (6,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - EXECUTE local_multi_row_insert_prepare_params(1,5); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) - -- one task is remote - EXECUTE local_multi_row_insert_prepare_params(5,11); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (5,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500004 AS citus_table_alias (key, value, age) VALUES (11,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value) -ROLLBACK; --- failures of local execution should rollback both the --- local execution and remote executions --- fail on a local execution -BEGIN; - INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '100' RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '100'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age - key | value | age ---------------------------------------------------------------------- - 1 | 100 | 21 -(1 row) - - UPDATE distributed_table SET value = '200'; -NOTICE: executing the command locally: UPDATE local_shard_execution_replicated.distributed_table_1500001 distributed_table SET value = '200'::text -NOTICE: executing the command locally: UPDATE local_shard_execution_replicated.distributed_table_1500002 distributed_table SET value = '200'::text -NOTICE: executing the command locally: UPDATE local_shard_execution_replicated.distributed_table_1500003 distributed_table SET value = '200'::text -NOTICE: executing the command locally: UPDATE local_shard_execution_replicated.distributed_table_1500004 distributed_table SET value = '200'::text - INSERT INTO distributed_table VALUES (1, '100',21) ON CONFLICT(key) DO UPDATE SET value = (1 / (100.0 - EXCLUDED.value::int))::text RETURNING *; -ERROR: division by zero -CONTEXT: while executing command on localhost:xxxxx -ROLLBACK; --- we've rollbacked everything -SELECT count(*) FROM distributed_table WHERE value = '200'; - count ---------------------------------------------------------------------- - 0 -(1 row) - --- RETURNING should just work fine for reference tables -INSERT INTO reference_table VALUES (500) RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.reference_table_1500000 (key) VALUES (500) RETURNING key - key ---------------------------------------------------------------------- - 500 -(1 row) - -DELETE FROM reference_table WHERE key = 500 RETURNING *; -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.reference_table_1500000 reference_table WHERE (key OPERATOR(pg_catalog.=) 500) RETURNING key - key ---------------------------------------------------------------------- - 500 -(1 row) - --- should be able to skip local execution even if in a sequential mode of execution -BEGIN; - SET LOCAL citus.multi_shard_modify_mode TO sequential ; - DELETE FROM distributed_table; -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table - INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '100' RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '100'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age - key | value | age ---------------------------------------------------------------------- - 1 | 11 | 21 -(1 row) - -ROLLBACK; --- sequential execution should just work fine after a local execution -BEGIN; - SET citus.multi_shard_modify_mode TO sequential ; - INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '100' RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '100'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age - key | value | age ---------------------------------------------------------------------- - 1 | 100 | 21 -(1 row) - - DELETE FROM distributed_table; -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table -ROLLBACK; --- load some data so that foreign keys won't complain with the next tests -TRUNCATE reference_table CASCADE; -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.reference_table_xxxxx CASCADE -INSERT INTO reference_table SELECT i FROM generate_series(500, 600) i; -NOTICE: executing the copy locally for shard xxxxx -INSERT INTO distributed_table SELECT i, i::text, i % 10 + 25 FROM generate_series(500, 600) i; -NOTICE: executing the copy locally for shard xxxxx -NOTICE: executing the copy locally for shard xxxxx -NOTICE: executing the copy locally for shard xxxxx -NOTICE: executing the copy locally for shard xxxxx --- show that both local, and mixed local-distributed executions --- calculate rows processed correctly -BEGIN; - DELETE FROM distributed_table WHERE key = 500; -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) - DELETE FROM distributed_table WHERE value != '123123213123213'; -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE (value OPERATOR(pg_catalog.<>) '123123213123213'::text) -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE (value OPERATOR(pg_catalog.<>) '123123213123213'::text) -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (value OPERATOR(pg_catalog.<>) '123123213123213'::text) -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE (value OPERATOR(pg_catalog.<>) '123123213123213'::text) -ROLLBACK; -BEGIN; - DELETE FROM reference_table WHERE key = 500 RETURNING *; -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.reference_table_1500000 reference_table WHERE (key OPERATOR(pg_catalog.=) 500) RETURNING key - key ---------------------------------------------------------------------- - 500 -(1 row) - - DELETE FROM reference_table; -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.reference_table_1500000 reference_table -ROLLBACK; -BEGIN; - DELETE FROM distributed_table WHERE key = 500; -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) - SELECT count(*) FROM distributed_table; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE true - count ---------------------------------------------------------------------- - 106 -(1 row) - -ROLLBACK; -BEGIN; - SET LOCAL client_min_messages TO INFO; - SELECT count(*) FROM distributed_table; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE true - count ---------------------------------------------------------------------- - 107 -(1 row) - - SET LOCAL client_min_messages TO LOG; - DELETE FROM distributed_table WHERE key = 500; -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) -ROLLBACK; --- probably not a realistic case since views are not very --- well supported with MX -SET citus.enable_ddl_propagation TO OFF; -CREATE VIEW v_local_query_execution AS -SELECT * FROM distributed_table WHERE key = 500; -RESET citus.enable_ddl_propagation; -SELECT * FROM v_local_query_execution; -NOTICE: executing the command locally: SELECT key, value, age FROM (SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) 500)) v_local_query_execution - key | value | age ---------------------------------------------------------------------- - 500 | 500 | 25 -(1 row) - --- similar test, but this time the view itself is a non-local --- query, but the query on the view is local -SET citus.enable_ddl_propagation TO OFF; -CREATE VIEW v_local_query_execution_2 AS -SELECT * FROM distributed_table; -RESET citus.enable_ddl_propagation; -SELECT * FROM v_local_query_execution_2 WHERE key = 500; -NOTICE: executing the command locally: SELECT key, value, age FROM (SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table) v_local_query_execution_2 WHERE (key OPERATOR(pg_catalog.=) 500) - key | value | age ---------------------------------------------------------------------- - 500 | 500 | 25 -(1 row) - --- even if we switch from remote execution -> local execution, --- we are able to use remote execution after rollback -BEGIN; - SAVEPOINT my_savepoint; - SELECT count(*) FROM distributed_table; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE true - count ---------------------------------------------------------------------- - 107 -(1 row) - - DELETE FROM distributed_table WHERE key = 500; -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) - ROLLBACK TO SAVEPOINT my_savepoint; - DELETE FROM distributed_table WHERE key = 500; -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) -COMMIT; --- even if we switch from local execution -> remote execution, --- we are able to use local execution after rollback -BEGIN; - SAVEPOINT my_savepoint; - DELETE FROM distributed_table WHERE key = 500; -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) - SELECT count(*) FROM distributed_table; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table WHERE true - count ---------------------------------------------------------------------- - 106 -(1 row) - - ROLLBACK TO SAVEPOINT my_savepoint; - DELETE FROM distributed_table WHERE key = 500; -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500) -COMMIT; --- sanity check: local execution on partitions -INSERT INTO collections_list (collection_id) VALUES (0) RETURNING *; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.collections_list_1500011 (key, ser, collection_id) VALUES ('3940649673949185'::bigint, '3940649673949185'::bigint, 0) RETURNING key, ser, ts, collection_id, value - key | ser | ts | collection_id | value ---------------------------------------------------------------------- - 3940649673949185 | 3940649673949185 | | 0 | -(1 row) - -BEGIN; - INSERT INTO collections_list (key, collection_id) VALUES (1,0); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.collections_list_1500009 (key, ser, collection_id) VALUES ('1'::bigint, '3940649673949186'::bigint, 0) - SELECT count(*) FROM collections_list_0 WHERE key = 1; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.collections_list_0_1500013 collections_list_0 WHERE (key OPERATOR(pg_catalog.=) 1) - count ---------------------------------------------------------------------- - 1 -(1 row) - - SELECT count(*) FROM collections_list; -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.collections_list_1500009 collections_list WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.collections_list_1500010 collections_list WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.collections_list_1500011 collections_list WHERE true -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.collections_list_1500012 collections_list WHERE true - count ---------------------------------------------------------------------- - 2 -(1 row) - - SELECT * FROM collections_list ORDER BY 1,2,3,4; -NOTICE: executing the command locally: SELECT key, ser, ts, collection_id, value FROM local_shard_execution_replicated.collections_list_1500009 collections_list WHERE true -NOTICE: executing the command locally: SELECT key, ser, ts, collection_id, value FROM local_shard_execution_replicated.collections_list_1500010 collections_list WHERE true -NOTICE: executing the command locally: SELECT key, ser, ts, collection_id, value FROM local_shard_execution_replicated.collections_list_1500011 collections_list WHERE true -NOTICE: executing the command locally: SELECT key, ser, ts, collection_id, value FROM local_shard_execution_replicated.collections_list_1500012 collections_list WHERE true - key | ser | ts | collection_id | value ---------------------------------------------------------------------- - 1 | 3940649673949186 | | 0 | - 3940649673949185 | 3940649673949185 | | 0 | -(2 rows) - -COMMIT; -TRUNCATE collections_list; --- make sure that even if local execution is used, the sequence values --- are generated locally -SET citus.enable_ddl_propagation TO OFF; -ALTER SEQUENCE collections_list_key_seq NO MINVALUE NO MAXVALUE; -RESET citus.enable_ddl_propagation; -PREPARE serial_prepared_local AS INSERT INTO collections_list (collection_id) VALUES (0) RETURNING key, ser; -SELECT setval('collections_list_key_seq', 4); - setval ---------------------------------------------------------------------- - 4 -(1 row) - -EXECUTE serial_prepared_local; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.collections_list_1500009 (key, ser, collection_id) VALUES ('5'::bigint, '3940649673949187'::bigint, 0) RETURNING key, ser - key | ser ---------------------------------------------------------------------- - 5 | 3940649673949187 -(1 row) - -SELECT setval('collections_list_key_seq', 5); - setval ---------------------------------------------------------------------- - 5 -(1 row) - -EXECUTE serial_prepared_local; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.collections_list_1500011 (key, ser, collection_id) VALUES ('6'::bigint, '3940649673949188'::bigint, 0) RETURNING key, ser - key | ser ---------------------------------------------------------------------- - 6 | 3940649673949188 -(1 row) - -SELECT setval('collections_list_key_seq', 499); - setval ---------------------------------------------------------------------- - 499 -(1 row) - -EXECUTE serial_prepared_local; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.collections_list_1500011 (key, ser, collection_id) VALUES ('500'::bigint, '3940649673949189'::bigint, 0) RETURNING key, ser - key | ser ---------------------------------------------------------------------- - 500 | 3940649673949189 -(1 row) - -SELECT setval('collections_list_key_seq', 700); - setval ---------------------------------------------------------------------- - 700 -(1 row) - -EXECUTE serial_prepared_local; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.collections_list_1500009 (key, ser, collection_id) VALUES ('701'::bigint, '3940649673949190'::bigint, 0) RETURNING key, ser - key | ser ---------------------------------------------------------------------- - 701 | 3940649673949190 -(1 row) - -SELECT setval('collections_list_key_seq', 708); - setval ---------------------------------------------------------------------- - 708 -(1 row) - -EXECUTE serial_prepared_local; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.collections_list_1500011 (key, ser, collection_id) VALUES ('709'::bigint, '3940649673949191'::bigint, 0) RETURNING key, ser - key | ser ---------------------------------------------------------------------- - 709 | 3940649673949191 -(1 row) - -SELECT setval('collections_list_key_seq', 709); - setval ---------------------------------------------------------------------- - 709 -(1 row) - -EXECUTE serial_prepared_local; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.collections_list_1500009 (key, ser, collection_id) VALUES ('710'::bigint, '3940649673949192'::bigint, 0) RETURNING key, ser - key | ser ---------------------------------------------------------------------- - 710 | 3940649673949192 -(1 row) - --- get ready for the next executions -DELETE FROM collections_list WHERE key IN (5,6); -SELECT setval('collections_list_key_seq', 4); - setval ---------------------------------------------------------------------- - 4 -(1 row) - -EXECUTE serial_prepared_local; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.collections_list_1500009 (key, ser, collection_id) VALUES ('5'::bigint, '3940649673949193'::bigint, 0) RETURNING key, ser - key | ser ---------------------------------------------------------------------- - 5 | 3940649673949193 -(1 row) - -SELECT setval('collections_list_key_seq', 5); - setval ---------------------------------------------------------------------- - 5 -(1 row) - -EXECUTE serial_prepared_local; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.collections_list_1500011 (key, ser, collection_id) VALUES ('6'::bigint, '3940649673949194'::bigint, 0) RETURNING key, ser - key | ser ---------------------------------------------------------------------- - 6 | 3940649673949194 -(1 row) - --- and, one remote test -SELECT setval('collections_list_key_seq', 10); - setval ---------------------------------------------------------------------- - 10 -(1 row) - -EXECUTE serial_prepared_local; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.collections_list_1500012 (key, ser, collection_id) VALUES ('11'::bigint, '3940649673949195'::bigint, 0) RETURNING key, ser - key | ser ---------------------------------------------------------------------- - 11 | 3940649673949195 -(1 row) - --- the final queries for the following CTEs are going to happen on the intermediate results only --- one of them will be executed remotely, and the other is locally --- Citus currently doesn't allow using task_assignment_policy for intermediate results -WITH distributed_local_mixed AS (INSERT INTO reference_table VALUES (1000) RETURNING *) SELECT * FROM distributed_local_mixed; -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.reference_table_1500000 (key) VALUES (1000) RETURNING key -NOTICE: executing the command locally: SELECT key FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) distributed_local_mixed - key ---------------------------------------------------------------------- - 1000 -(1 row) - --- clean the table for the next tests -SET search_path TO local_shard_execution_replicated; -TRUNCATE distributed_table CASCADE; --- load some data on a remote shard -INSERT INTO reference_table (key) VALUES (1), (2); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.reference_table_1500000 AS citus_table_alias (key) VALUES (1), (2) -INSERT INTO distributed_table (key) VALUES (2); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500004 (key) VALUES (2) -BEGIN; - -- local execution followed by a distributed query - INSERT INTO distributed_table (key) VALUES (1); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.distributed_table_1500001 (key) VALUES (1) - DELETE FROM distributed_table RETURNING key; -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table RETURNING key -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500002 distributed_table RETURNING key -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500003 distributed_table RETURNING key -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.distributed_table_1500004 distributed_table RETURNING key - key ---------------------------------------------------------------------- - 1 - 2 -(2 rows) - -COMMIT; --- a similar test with a reference table -TRUNCATE reference_table CASCADE; -NOTICE: executing the command locally: TRUNCATE TABLE local_shard_execution_replicated.reference_table_xxxxx CASCADE --- load some data on a remote shard -INSERT INTO reference_table (key) VALUES (2); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.reference_table_1500000 (key) VALUES (2) -BEGIN; - -- local execution followed by a distributed query - INSERT INTO reference_table (key) VALUES (1); -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.reference_table_1500000 (key) VALUES (1) - DELETE FROM reference_table RETURNING key; -NOTICE: executing the command locally: DELETE FROM local_shard_execution_replicated.reference_table_1500000 reference_table RETURNING key - key ---------------------------------------------------------------------- - 1 - 2 -(2 rows) - -COMMIT; --- however complex the query, local execution can handle -SET client_min_messages TO LOG; -SET citus.log_local_commands TO ON; -WITH cte_1 AS - (SELECT * - FROM - (WITH cte_1 AS - (SELECT * - FROM distributed_table - WHERE key = 1) SELECT * - FROM cte_1) AS foo) -SELECT count(*) -FROM cte_1 -JOIN distributed_table USING (key) -WHERE distributed_table.key = 1 - AND distributed_table.key IN - (SELECT key - FROM distributed_table - WHERE key = 1); -NOTICE: executing the command locally: SELECT count(*) AS count FROM ((SELECT foo.key, foo.value, foo.age FROM (SELECT cte_1_1.key, cte_1_1.value, cte_1_1.age FROM (SELECT distributed_table_1.key, distributed_table_1.value, distributed_table_1.age FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table_1 WHERE (distributed_table_1.key OPERATOR(pg_catalog.=) 1)) cte_1_1) foo) cte_1 JOIN local_shard_execution_replicated.distributed_table_1500001 distributed_table(key, value, age) USING (key)) WHERE ((distributed_table.key OPERATOR(pg_catalog.=) 1) AND (distributed_table.key OPERATOR(pg_catalog.=) ANY (SELECT distributed_table_1.key FROM local_shard_execution_replicated.distributed_table_1500001 distributed_table_1 WHERE (distributed_table_1.key OPERATOR(pg_catalog.=) 1)))) - count ---------------------------------------------------------------------- - 0 -(1 row) - -RESET client_min_messages; -RESET citus.log_local_commands; -\c - - - :master_port -SET citus.next_shard_id TO 1501000; --- test both local and remote execution with custom type -SET citus.shard_replication_factor TO 2; -SET search_path TO local_shard_execution_replicated; -CREATE TYPE invite_resp AS ENUM ('yes', 'no', 'maybe'); -CREATE TABLE event_responses ( - event_id int, - user_id int, - response invite_resp, - primary key (event_id, user_id) -); -SELECT create_distributed_table('event_responses', 'event_id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO event_responses VALUES (1, 1, 'yes'), (2, 2, 'yes'), (3, 3, 'no'), (4, 4, 'no'); -CREATE OR REPLACE FUNCTION regular_func(p invite_resp) -RETURNS int AS $$ -DECLARE - q1Result INT; - q2Result INT; - q3Result INT; -BEGIN -SELECT count(*) INTO q1Result FROM event_responses WHERE response = $1; -SELECT count(*) INTO q2Result FROM event_responses e1 LEFT JOIN event_responses e2 USING (event_id) WHERE e2.response = $1; -SELECT count(*) INTO q3Result FROM (SELECT * FROM event_responses WHERE response = $1 LIMIT 5) as foo; -RETURN q3Result+q2Result+q1Result; -END; -$$ LANGUAGE plpgsql; -SELECT regular_func('yes'); - regular_func ---------------------------------------------------------------------- - 6 -(1 row) - -SELECT regular_func('yes'); - regular_func ---------------------------------------------------------------------- - 6 -(1 row) - -SELECT regular_func('yes'); - regular_func ---------------------------------------------------------------------- - 6 -(1 row) - -SELECT regular_func('yes'); - regular_func ---------------------------------------------------------------------- - 6 -(1 row) - -SELECT regular_func('yes'); - regular_func ---------------------------------------------------------------------- - 6 -(1 row) - -SELECT regular_func('yes'); - regular_func ---------------------------------------------------------------------- - 6 -(1 row) - -SELECT regular_func('yes'); - regular_func ---------------------------------------------------------------------- - 6 -(1 row) - -SELECT regular_func('yes'); - regular_func ---------------------------------------------------------------------- - 6 -(1 row) - -CREATE OR REPLACE PROCEDURE regular_procedure(p invite_resp) -AS $$ -BEGIN -PERFORM * FROM event_responses WHERE response = $1 ORDER BY 1 DESC, 2 DESC, 3 DESC; -PERFORM * FROM event_responses e1 LEFT JOIN event_responses e2 USING (event_id) WHERE e2.response = $1 ORDER BY 1 DESC, 2 DESC, 3 DESC, 4 DESC; -PERFORM * FROM (SELECT * FROM event_responses WHERE response = $1 LIMIT 5) as foo ORDER BY 1 DESC, 2 DESC, 3 DESC; -END; -$$ LANGUAGE plpgsql; -CALL regular_procedure('no'); -CALL regular_procedure('no'); -CALL regular_procedure('no'); -CALL regular_procedure('no'); -CALL regular_procedure('no'); -CALL regular_procedure('no'); -CALL regular_procedure('no'); -CALL regular_procedure('no'); -PREPARE multi_shard_no_dist_key(invite_resp) AS select * from event_responses where response = $1::invite_resp ORDER BY 1 DESC, 2 DESC, 3 DESC LIMIT 1; -EXECUTE multi_shard_no_dist_key('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_no_dist_key('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_no_dist_key('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_no_dist_key('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_no_dist_key('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_no_dist_key('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_no_dist_key('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_no_dist_key('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -PREPARE multi_shard_with_dist_key(int, invite_resp) AS select * from event_responses where event_id > $1 AND response = $2::invite_resp ORDER BY 1 DESC, 2 DESC, 3 DESC LIMIT 1; -EXECUTE multi_shard_with_dist_key(1, 'yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_with_dist_key(1, 'yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_with_dist_key(1, 'yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_with_dist_key(1, 'yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_with_dist_key(1, 'yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_with_dist_key(1, 'yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_with_dist_key(1, 'yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -EXECUTE multi_shard_with_dist_key(1, 'yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes -(1 row) - -PREPARE query_pushdown_no_dist_key(invite_resp) AS select * from event_responses e1 LEFT JOIN event_responses e2 USING(event_id) where e1.response = $1::invite_resp ORDER BY 1 DESC, 2 DESC, 3 DESC, 4 DESC LIMIT 1; -EXECUTE query_pushdown_no_dist_key('yes'); - event_id | user_id | response | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes | 2 | yes -(1 row) - -EXECUTE query_pushdown_no_dist_key('yes'); - event_id | user_id | response | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes | 2 | yes -(1 row) - -EXECUTE query_pushdown_no_dist_key('yes'); - event_id | user_id | response | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes | 2 | yes -(1 row) - -EXECUTE query_pushdown_no_dist_key('yes'); - event_id | user_id | response | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes | 2 | yes -(1 row) - -EXECUTE query_pushdown_no_dist_key('yes'); - event_id | user_id | response | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes | 2 | yes -(1 row) - -EXECUTE query_pushdown_no_dist_key('yes'); - event_id | user_id | response | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes | 2 | yes -(1 row) - -EXECUTE query_pushdown_no_dist_key('yes'); - event_id | user_id | response | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes | 2 | yes -(1 row) - -EXECUTE query_pushdown_no_dist_key('yes'); - event_id | user_id | response | user_id | response ---------------------------------------------------------------------- - 2 | 2 | yes | 2 | yes -(1 row) - -PREPARE insert_select_via_coord(invite_resp) AS INSERT INTO event_responses SELECT * FROM event_responses where response = $1::invite_resp LIMIT 1 ON CONFLICT (event_id, user_id) DO NOTHING ; -EXECUTE insert_select_via_coord('yes'); -EXECUTE insert_select_via_coord('yes'); -EXECUTE insert_select_via_coord('yes'); -EXECUTE insert_select_via_coord('yes'); -EXECUTE insert_select_via_coord('yes'); -EXECUTE insert_select_via_coord('yes'); -EXECUTE insert_select_via_coord('yes'); -EXECUTE insert_select_via_coord('yes'); -PREPARE insert_select_pushdown(invite_resp) AS INSERT INTO event_responses SELECT * FROM event_responses where response = $1::invite_resp ON CONFLICT (event_id, user_id) DO NOTHING; -EXECUTE insert_select_pushdown('yes'); -EXECUTE insert_select_pushdown('yes'); -EXECUTE insert_select_pushdown('yes'); -EXECUTE insert_select_pushdown('yes'); -EXECUTE insert_select_pushdown('yes'); -EXECUTE insert_select_pushdown('yes'); -EXECUTE insert_select_pushdown('yes'); -EXECUTE insert_select_pushdown('yes'); -PREPARE router_select_with_no_dist_key_filter(invite_resp) AS select * from event_responses where event_id = 1 AND response = $1::invite_resp ORDER BY 1 DESC, 2 DESC, 3 DESC LIMIT 1; -EXECUTE router_select_with_no_dist_key_filter('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 1 | 1 | yes -(1 row) - -EXECUTE router_select_with_no_dist_key_filter('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 1 | 1 | yes -(1 row) - -EXECUTE router_select_with_no_dist_key_filter('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 1 | 1 | yes -(1 row) - -EXECUTE router_select_with_no_dist_key_filter('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 1 | 1 | yes -(1 row) - -EXECUTE router_select_with_no_dist_key_filter('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 1 | 1 | yes -(1 row) - -EXECUTE router_select_with_no_dist_key_filter('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 1 | 1 | yes -(1 row) - -EXECUTE router_select_with_no_dist_key_filter('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 1 | 1 | yes -(1 row) - -EXECUTE router_select_with_no_dist_key_filter('yes'); - event_id | user_id | response ---------------------------------------------------------------------- - 1 | 1 | yes -(1 row) - --- rest of the tests assume the table is empty -TRUNCATE event_responses; -CREATE OR REPLACE PROCEDURE register_for_event(p_event_id int, p_user_id int, p_choice invite_resp) -LANGUAGE plpgsql AS $fn$ -BEGIN - INSERT INTO local_shard_execution_replicated.event_responses VALUES (p_event_id, p_user_id, p_choice) - ON CONFLICT (event_id, user_id) - DO UPDATE SET response = EXCLUDED.response; - - PERFORM count(*) FROM local_shard_execution_replicated.event_responses WHERE event_id = p_event_id; - - PERFORM count(*) FROM local_shard_execution_replicated.event_responses WHERE event_id = p_event_id AND false; - - UPDATE local_shard_execution_replicated.event_responses SET response = p_choice WHERE event_id = p_event_id; - -END; -$fn$; -SELECT create_distributed_function('register_for_event(int,int,invite_resp)'); -NOTICE: procedure local_shard_execution_replicated.register_for_event is already distributed -DETAIL: Citus distributes procedures with CREATE [PROCEDURE|FUNCTION|AGGREGATE] commands - create_distributed_function ---------------------------------------------------------------------- - -(1 row) - --- call 8 times to make sure it works after the 5th time(postgres binds values after the 5th time and Citus 2nd time) --- after 6th, the local execution caches the local plans and uses it --- execute it both locally and remotely -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -\c - - - :worker_2_port -SET search_path TO local_shard_execution_replicated; -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); -CALL register_for_event(16, 1, 'yes'); --- values 16, 17 and 19 hits the same --- shard, so we're re-using the same cached --- plans per statement across different distribution --- key values -CALL register_for_event(17, 1, 'yes'); -CALL register_for_event(19, 1, 'yes'); -CALL register_for_event(17, 1, 'yes'); -CALL register_for_event(19, 1, 'yes'); --- should work fine if the logs are enabled -\set VERBOSITY terse -SET citus.log_local_commands TO ON; -SET client_min_messages TO DEBUG2; -CALL register_for_event(19, 1, 'yes'); -DEBUG: stored procedure does not have co-located tables -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.event_responses_1501001 AS citus_table_alias (event_id, user_id, response) VALUES (19, 1, 'yes'::local_shard_execution_replicated.invite_resp) ON CONFLICT(event_id, user_id) DO UPDATE SET response = excluded.response -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.event_responses_1501001 event_responses WHERE (event_id OPERATOR(pg_catalog.=) 19) -NOTICE: executing the command locally: SELECT count(*) AS count FROM (SELECT NULL::integer AS event_id, NULL::integer AS user_id, NULL::local_shard_execution_replicated.invite_resp AS response WHERE false) event_responses(event_id, user_id, response) WHERE ((event_id OPERATOR(pg_catalog.=) 19) AND false) -NOTICE: executing the command locally: UPDATE local_shard_execution_replicated.event_responses_1501001 event_responses SET response = 'yes'::local_shard_execution_replicated.invite_resp WHERE (event_id OPERATOR(pg_catalog.=) 19) --- should be fine even if no parameters exists in the query -SELECT count(*) FROM event_responses WHERE event_id = 16; -DEBUG: Distributed planning for a fast-path router query -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 16 -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.event_responses_1501001 event_responses WHERE (event_id OPERATOR(pg_catalog.=) 16) - count ---------------------------------------------------------------------- - 1 -(1 row) - -SELECT count(*) FROM event_responses WHERE event_id = 16; -DEBUG: Distributed planning for a fast-path router query -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 16 -NOTICE: executing the command locally: SELECT count(*) AS count FROM local_shard_execution_replicated.event_responses_1501001 event_responses WHERE (event_id OPERATOR(pg_catalog.=) 16) - count ---------------------------------------------------------------------- - 1 -(1 row) - -UPDATE event_responses SET response = 'no' WHERE event_id = 16; -DEBUG: Distributed planning for a fast-path router query -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 16 -NOTICE: executing the command locally: UPDATE local_shard_execution_replicated.event_responses_1501001 event_responses SET response = 'no'::local_shard_execution_replicated.invite_resp WHERE (event_id OPERATOR(pg_catalog.=) 16) -INSERT INTO event_responses VALUES (16, 666, 'maybe') -ON CONFLICT (event_id, user_id) -DO UPDATE SET response = EXCLUDED.response RETURNING *; -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 16 -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.event_responses_1501001 AS citus_table_alias (event_id, user_id, response) VALUES (16, 666, 'maybe'::local_shard_execution_replicated.invite_resp) ON CONFLICT(event_id, user_id) DO UPDATE SET response = excluded.response RETURNING citus_table_alias.event_id, citus_table_alias.user_id, citus_table_alias.response - event_id | user_id | response ---------------------------------------------------------------------- - 16 | 666 | maybe -(1 row) - --- multi row INSERTs hitting the same shard -INSERT INTO event_responses VALUES (16, 666, 'maybe'), (17, 777, 'no') -ON CONFLICT (event_id, user_id) -DO UPDATE SET response = EXCLUDED.response RETURNING *; -DEBUG: Creating router plan -NOTICE: executing the command locally: INSERT INTO local_shard_execution_replicated.event_responses_1501001 AS citus_table_alias (event_id, user_id, response) VALUES (16,666,'maybe'::local_shard_execution_replicated.invite_resp), (17,777,'no'::local_shard_execution_replicated.invite_resp) ON CONFLICT(event_id, user_id) DO UPDATE SET response = excluded.response RETURNING citus_table_alias.event_id, citus_table_alias.user_id, citus_table_alias.response - event_id | user_id | response ---------------------------------------------------------------------- - 16 | 666 | maybe - 17 | 777 | no -(2 rows) - --- now, similar tests with some settings changed -SET citus.enable_local_execution TO false; -SET citus.enable_fast_path_router_planner TO false; -CALL register_for_event(19, 1, 'yes'); -DEBUG: stored procedure does not have co-located tables --- should be fine even if no parameters exists in the query -SELECT count(*) FROM event_responses WHERE event_id = 16; -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 16 - count ---------------------------------------------------------------------- - 2 -(1 row) - -SELECT count(*) FROM event_responses WHERE event_id = 16; -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 16 - count ---------------------------------------------------------------------- - 2 -(1 row) - -UPDATE event_responses SET response = 'no' WHERE event_id = 16; -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 16 -INSERT INTO event_responses VALUES (16, 666, 'maybe') -ON CONFLICT (event_id, user_id) -DO UPDATE SET response = EXCLUDED.response RETURNING *; -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 16 - event_id | user_id | response ---------------------------------------------------------------------- - 16 | 666 | maybe -(1 row) - --- multi row INSERTs hitting the same shard -INSERT INTO event_responses VALUES (16, 666, 'maybe'), (17, 777, 'no') -ON CONFLICT (event_id, user_id) -DO UPDATE SET response = EXCLUDED.response RETURNING *; -DEBUG: Creating router plan - event_id | user_id | response ---------------------------------------------------------------------- - 16 | 666 | maybe - 17 | 777 | no -(2 rows) - --- not allow commands over the workers when user disables -SET citus.allow_modifications_from_workers_to_replicated_tables TO false; -INSERT INTO event_responses VALUES (16, 666, 'maybe'), (17, 777, 'no') -ON CONFLICT (event_id, user_id) -DO UPDATE SET response = EXCLUDED.response RETURNING *; -ERROR: modifications via the worker nodes are not allowed for replicated tables such as reference tables or hash distributed tables with replication factor greater than 1. -\c - - - :master_port -SET client_min_messages TO ERROR; -SET search_path TO public; -DROP SCHEMA local_shard_execution_replicated CASCADE; diff --git a/src/test/regress/expected/merge.out b/src/test/regress/expected/merge.out index 5056ba543..1e5e85242 100644 --- a/src/test/regress/expected/merge.out +++ b/src/test/regress/expected/merge.out @@ -1,10 +1,3 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif -- MERGE command performs a join from data_source to target_table_name DROP SCHEMA IF EXISTS merge_schema CASCADE; NOTICE: schema "merge_schema" does not exist, skipping diff --git a/src/test/regress/expected/merge_0.out b/src/test/regress/expected/merge_0.out deleted file mode 100644 index a7e3fbf20..000000000 --- a/src/test/regress/expected/merge_0.out +++ /dev/null @@ -1,6 +0,0 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q diff --git a/src/test/regress/expected/merge_arbitrary.out b/src/test/regress/expected/merge_arbitrary.out index b55306b44..052a9d066 100644 --- a/src/test/regress/expected/merge_arbitrary.out +++ b/src/test/regress/expected/merge_arbitrary.out @@ -1,10 +1,3 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif SET search_path TO merge_arbitrary_schema; INSERT INTO target_cj VALUES (1, 'target', 0); INSERT INTO target_cj VALUES (2, 'target', 0); diff --git a/src/test/regress/expected/merge_arbitrary_0.out b/src/test/regress/expected/merge_arbitrary_0.out deleted file mode 100644 index a7e3fbf20..000000000 --- a/src/test/regress/expected/merge_arbitrary_0.out +++ /dev/null @@ -1,6 +0,0 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q diff --git a/src/test/regress/expected/merge_arbitrary_create.out b/src/test/regress/expected/merge_arbitrary_create.out index aff9ecd97..1d0a25f6a 100644 --- a/src/test/regress/expected/merge_arbitrary_create.out +++ b/src/test/regress/expected/merge_arbitrary_create.out @@ -1,10 +1,3 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif DROP SCHEMA IF EXISTS merge_arbitrary_schema CASCADE; CREATE SCHEMA merge_arbitrary_schema; SET search_path TO merge_arbitrary_schema; diff --git a/src/test/regress/expected/merge_arbitrary_create_0.out b/src/test/regress/expected/merge_arbitrary_create_0.out deleted file mode 100644 index a7e3fbf20..000000000 --- a/src/test/regress/expected/merge_arbitrary_create_0.out +++ /dev/null @@ -1,6 +0,0 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q diff --git a/src/test/regress/expected/merge_partition_tables.out b/src/test/regress/expected/merge_partition_tables.out index 5ac375817..6ca7d6398 100644 --- a/src/test/regress/expected/merge_partition_tables.out +++ b/src/test/regress/expected/merge_partition_tables.out @@ -1,10 +1,3 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif -- We create two sets of source and target tables, one set in Postgres and -- the other in Citus distributed. We run the _exact_ MERGE SQL on both sets -- and compare the final results of the target tables in Postgres and Citus. diff --git a/src/test/regress/expected/merge_partition_tables_0.out b/src/test/regress/expected/merge_partition_tables_0.out deleted file mode 100644 index a7e3fbf20..000000000 --- a/src/test/regress/expected/merge_partition_tables_0.out +++ /dev/null @@ -1,6 +0,0 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q diff --git a/src/test/regress/expected/merge_repartition1.out b/src/test/regress/expected/merge_repartition1.out index 279358e30..ac718f73c 100644 --- a/src/test/regress/expected/merge_repartition1.out +++ b/src/test/regress/expected/merge_repartition1.out @@ -1,10 +1,3 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif -- We create two sets of source and target tables, one set in Postgres and -- the other in Citus distributed. We run the _exact_ MERGE SQL on both sets -- and compare the final results of the target tables in Postgres and Citus. diff --git a/src/test/regress/expected/merge_repartition1_0.out b/src/test/regress/expected/merge_repartition1_0.out deleted file mode 100644 index a7e3fbf20..000000000 --- a/src/test/regress/expected/merge_repartition1_0.out +++ /dev/null @@ -1,6 +0,0 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q diff --git a/src/test/regress/expected/merge_repartition2.out b/src/test/regress/expected/merge_repartition2.out index 898b7c77a..524ae84f7 100644 --- a/src/test/regress/expected/merge_repartition2.out +++ b/src/test/regress/expected/merge_repartition2.out @@ -1,10 +1,3 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif -- We create two sets of source and target tables, one set in Postgres and -- the other in Citus distributed. We run the _exact_ MERGE SQL on both sets -- and compare the final results of the target tables in Postgres and Citus. diff --git a/src/test/regress/expected/merge_repartition2_0.out b/src/test/regress/expected/merge_repartition2_0.out deleted file mode 100644 index a7e3fbf20..000000000 --- a/src/test/regress/expected/merge_repartition2_0.out +++ /dev/null @@ -1,6 +0,0 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q diff --git a/src/test/regress/expected/merge_schema_sharding.out b/src/test/regress/expected/merge_schema_sharding.out index 17f6f6adb..a6fb11998 100644 --- a/src/test/regress/expected/merge_schema_sharding.out +++ b/src/test/regress/expected/merge_schema_sharding.out @@ -1,10 +1,3 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif -- MERGE command performs a join from data_source to target_table_name DROP SCHEMA IF EXISTS schema_shard_table1 CASCADE; NOTICE: schema "schema_shard_table1" does not exist, skipping diff --git a/src/test/regress/expected/merge_schema_sharding_0.out b/src/test/regress/expected/merge_schema_sharding_0.out deleted file mode 100644 index a7e3fbf20..000000000 --- a/src/test/regress/expected/merge_schema_sharding_0.out +++ /dev/null @@ -1,6 +0,0 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q diff --git a/src/test/regress/expected/merge_vcore.out b/src/test/regress/expected/merge_vcore.out index 0eccb811b..b3b6eb1ff 100644 --- a/src/test/regress/expected/merge_vcore.out +++ b/src/test/regress/expected/merge_vcore.out @@ -1,10 +1,3 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif -- MERGE command performs a join from data_source to target_table_name DROP SCHEMA IF EXISTS merge_vcore_schema CASCADE; NOTICE: schema "merge_vcore_schema" does not exist, skipping diff --git a/src/test/regress/expected/merge_vcore_0.out b/src/test/regress/expected/merge_vcore_0.out deleted file mode 100644 index a7e3fbf20..000000000 --- a/src/test/regress/expected/merge_vcore_0.out +++ /dev/null @@ -1,6 +0,0 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q diff --git a/src/test/regress/expected/multi_alter_table_add_constraints_without_name.out b/src/test/regress/expected/multi_alter_table_add_constraints_without_name.out index 0c268264d..6a6251f9e 100644 --- a/src/test/regress/expected/multi_alter_table_add_constraints_without_name.out +++ b/src/test/regress/expected/multi_alter_table_add_constraints_without_name.out @@ -214,13 +214,8 @@ SELECT con.conname \c - - :master_host :master_port ALTER TABLE AT_AddConstNoName.products DROP CONSTRAINT products_product_no_key; -- Check "ADD UNIQUE NULLS NOT DISTICT" -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 ALTER TABLE AT_AddConstNoName.products ADD UNIQUE NULLS NOT DISTINCT (product_no, price); ALTER TABLE AT_AddConstNoName.products DROP CONSTRAINT products_product_no_price_key; -\endif -- Check "ADD UNIQUE ... DEFERRABLE" ALTER TABLE AT_AddConstNoName.products ADD UNIQUE(product_no) INCLUDE(price) DEFERRABLE; \c - - :public_worker_1_host :worker_1_port diff --git a/src/test/regress/expected/multi_deparse_shard_query.out b/src/test/regress/expected/multi_deparse_shard_query.out index 4657db10d..407f89b8c 100644 --- a/src/test/regress/expected/multi_deparse_shard_query.out +++ b/src/test/regress/expected/multi_deparse_shard_query.out @@ -1,17 +1,6 @@ -- -- MULTI_DEPARSE_SHARD_QUERY -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - t -(1 row) - CREATE SCHEMA multi_deparse_shard_query; SET search_path TO multi_deparse_shard_query; SET citus.next_shard_id TO 13100000; diff --git a/src/test/regress/expected/multi_deparse_shard_query_0.out b/src/test/regress/expected/multi_deparse_shard_query_0.out deleted file mode 100644 index 4f2ca98b8..000000000 --- a/src/test/regress/expected/multi_deparse_shard_query_0.out +++ /dev/null @@ -1,423 +0,0 @@ --- --- MULTI_DEPARSE_SHARD_QUERY --- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - f -(1 row) - -CREATE SCHEMA multi_deparse_shard_query; -SET search_path TO multi_deparse_shard_query; -SET citus.next_shard_id TO 13100000; -SET citus.shard_replication_factor TO 1; -CREATE FUNCTION deparse_shard_query_test(text) - RETURNS VOID - AS 'citus' - LANGUAGE C STRICT; --- create the first table -CREATE TABLE raw_events_1 - (tenant_id bigint, - value_1 int, - value_2 int, - value_3 float, - value_4 bigint, - value_5 text, - value_6 int DEfAULT 10, - value_7 int, - event_at date DEfAULT now() - ); -SELECT create_distributed_table('raw_events_1', 'tenant_id', 'hash'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - --- create the first table -CREATE TABLE raw_events_2 - (tenant_id bigint, - value_1 int, - value_2 int, - value_3 float, - value_4 bigint, - value_5 text, - value_6 float DEfAULT (random()*100)::float, - value_7 int, - event_at date DEfAULT now() - ); -SELECT create_distributed_table('raw_events_2', 'tenant_id', 'hash'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -CREATE TABLE aggregated_events - (tenant_id bigint, - sum_value_1 bigint, - average_value_2 float, - average_value_3 float, - sum_value_4 bigint, - sum_value_5 float, - average_value_6 int, - rollup_hour date); -SELECT create_distributed_table('aggregated_events', 'tenant_id', 'hash'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - --- start with very simple examples on a single table -SELECT deparse_shard_query_test(' -INSERT INTO raw_events_1 -SELECT * FROM raw_events_1; -'); -INFO: query: INSERT INTO multi_deparse_shard_query.raw_events_1 (tenant_id, value_1, value_2, value_3, value_4, value_5, value_6, value_7, event_at) SELECT tenant_id, value_1, value_2, value_3, value_4, value_5, value_6, value_7, event_at FROM multi_deparse_shard_query.raw_events_1 - deparse_shard_query_test ---------------------------------------------------------------------- - -(1 row) - -SELECT deparse_shard_query_test(' -INSERT INTO raw_events_1(tenant_id, value_4) -SELECT - tenant_id, value_4 -FROM - raw_events_1; -'); -INFO: query: INSERT INTO multi_deparse_shard_query.raw_events_1 (tenant_id, value_4, value_6, event_at) SELECT tenant_id, value_4, 10 AS value_6, (now())::date AS event_at FROM multi_deparse_shard_query.raw_events_1 - deparse_shard_query_test ---------------------------------------------------------------------- - -(1 row) - --- now that shuffle columns a bit on a single table -SELECT deparse_shard_query_test(' -INSERT INTO raw_events_1(value_5, value_2, tenant_id, value_4) -SELECT - value_2::text, value_5::int, tenant_id, value_4 -FROM - raw_events_1; -'); -INFO: query: INSERT INTO multi_deparse_shard_query.raw_events_1 (tenant_id, value_2, value_4, value_5, value_6, event_at) SELECT tenant_id, (value_5)::integer AS value_5, value_4, (value_2)::text AS value_2, 10 AS value_6, (now())::date AS event_at FROM multi_deparse_shard_query.raw_events_1 - deparse_shard_query_test ---------------------------------------------------------------------- - -(1 row) - --- same test on two different tables -SELECT deparse_shard_query_test(' -INSERT INTO raw_events_1(value_5, value_2, tenant_id, value_4) -SELECT - value_2::text, value_5::int, tenant_id, value_4 -FROM - raw_events_2; -'); -INFO: query: INSERT INTO multi_deparse_shard_query.raw_events_1 (tenant_id, value_2, value_4, value_5, value_6, event_at) SELECT tenant_id, (value_5)::integer AS value_5, value_4, (value_2)::text AS value_2, 10 AS value_6, (now())::date AS event_at FROM multi_deparse_shard_query.raw_events_2 - deparse_shard_query_test ---------------------------------------------------------------------- - -(1 row) - --- lets do some simple aggregations -SELECT deparse_shard_query_test(E' -INSERT INTO aggregated_events (tenant_id, rollup_hour, sum_value_1, average_value_3, average_value_6, sum_value_4) -SELECT - tenant_id, date_trunc(\'hour\', event_at) , sum(value_1), avg(value_3), avg(value_6), sum(value_4) -FROM - raw_events_1 -GROUP BY - tenant_id, date_trunc(\'hour\', event_at) -'); -INFO: query: INSERT INTO multi_deparse_shard_query.aggregated_events (tenant_id, sum_value_1, average_value_3, sum_value_4, average_value_6, rollup_hour) SELECT tenant_id, sum(value_1) AS sum, avg(value_3) AS avg, sum(value_4) AS sum, avg(value_6) AS avg, date_trunc('hour'::text, (event_at)::timestamp with time zone) AS date_trunc FROM multi_deparse_shard_query.raw_events_1 GROUP BY tenant_id, (date_trunc('hour'::text, (event_at)::timestamp with time zone)) - deparse_shard_query_test ---------------------------------------------------------------------- - -(1 row) - --- also some subqueries, JOINS with a complicated target lists --- a simple JOIN -SELECT deparse_shard_query_test(' -INSERT INTO raw_events_1 (value_3, tenant_id) -SELECT - raw_events_2.value_3, raw_events_1.tenant_id -FROM - raw_events_1, raw_events_2 -WHERE - raw_events_1.tenant_id = raw_events_2.tenant_id; -'); -INFO: query: INSERT INTO multi_deparse_shard_query.raw_events_1 (tenant_id, value_3, value_6, event_at) SELECT raw_events_1.tenant_id, raw_events_2.value_3, 10 AS value_6, (now())::date AS event_at FROM multi_deparse_shard_query.raw_events_1, multi_deparse_shard_query.raw_events_2 WHERE (raw_events_1.tenant_id OPERATOR(pg_catalog.=) raw_events_2.tenant_id) - deparse_shard_query_test ---------------------------------------------------------------------- - -(1 row) - --- join with group by -SELECT deparse_shard_query_test(' -INSERT INTO raw_events_1 (value_3, tenant_id) -SELECT - max(raw_events_2.value_3), avg(raw_events_1.value_3) -FROM - raw_events_1, raw_events_2 -WHERE - raw_events_1.tenant_id = raw_events_2.tenant_id GROUP BY raw_events_1.event_at -'); -INFO: query: INSERT INTO multi_deparse_shard_query.raw_events_1 (tenant_id, value_3, value_6, event_at) SELECT avg(raw_events_1.value_3) AS avg, max(raw_events_2.value_3) AS max, 10 AS value_6, (now())::date AS event_at FROM multi_deparse_shard_query.raw_events_1, multi_deparse_shard_query.raw_events_2 WHERE (raw_events_1.tenant_id OPERATOR(pg_catalog.=) raw_events_2.tenant_id) GROUP BY raw_events_1.event_at - deparse_shard_query_test ---------------------------------------------------------------------- - -(1 row) - --- a more complicated JOIN -SELECT deparse_shard_query_test(' -INSERT INTO aggregated_events (sum_value_4, tenant_id) -SELECT - max(r1.value_4), r3.tenant_id -FROM - raw_events_1 r1, raw_events_2 r2, raw_events_1 r3 -WHERE - r1.tenant_id = r2.tenant_id AND r2.tenant_id = r3.tenant_id -GROUP BY - r1.value_1, r3.tenant_id, r2.event_at -ORDER BY - r2.event_at DESC; -'); -INFO: query: INSERT INTO multi_deparse_shard_query.aggregated_events (tenant_id, sum_value_4) SELECT r3.tenant_id, max(r1.value_4) AS max FROM multi_deparse_shard_query.raw_events_1 r1, multi_deparse_shard_query.raw_events_2 r2, multi_deparse_shard_query.raw_events_1 r3 WHERE ((r1.tenant_id OPERATOR(pg_catalog.=) r2.tenant_id) AND (r2.tenant_id OPERATOR(pg_catalog.=) r3.tenant_id)) GROUP BY r1.value_1, r3.tenant_id, r2.event_at ORDER BY r2.event_at DESC - deparse_shard_query_test ---------------------------------------------------------------------- - -(1 row) - --- queries with CTEs are supported -SELECT deparse_shard_query_test(' -WITH first_tenant AS (SELECT event_at, value_5, tenant_id FROM raw_events_1) -INSERT INTO aggregated_events (rollup_hour, sum_value_5, tenant_id) -SELECT - event_at, sum(value_5::int), tenant_id -FROM - raw_events_1 -GROUP BY - event_at, tenant_id; -'); -INFO: query: WITH first_tenant AS (SELECT raw_events_1.event_at, raw_events_1.value_5, raw_events_1.tenant_id FROM multi_deparse_shard_query.raw_events_1) INSERT INTO multi_deparse_shard_query.aggregated_events (tenant_id, sum_value_5, rollup_hour) SELECT tenant_id, sum((value_5)::integer) AS sum, event_at FROM multi_deparse_shard_query.raw_events_1 GROUP BY event_at, tenant_id - deparse_shard_query_test ---------------------------------------------------------------------- - -(1 row) - -SELECT deparse_shard_query_test(' -WITH first_tenant AS (SELECT event_at, value_5, tenant_id FROM raw_events_1) -INSERT INTO aggregated_events (sum_value_5, tenant_id) -SELECT - sum(value_5::int), tenant_id -FROM - raw_events_1 -GROUP BY - event_at, tenant_id; -'); -INFO: query: WITH first_tenant AS (SELECT raw_events_1.event_at, raw_events_1.value_5, raw_events_1.tenant_id FROM multi_deparse_shard_query.raw_events_1) INSERT INTO multi_deparse_shard_query.aggregated_events (tenant_id, sum_value_5) SELECT tenant_id, sum((value_5)::integer) AS sum FROM multi_deparse_shard_query.raw_events_1 GROUP BY event_at, tenant_id - deparse_shard_query_test ---------------------------------------------------------------------- - -(1 row) - -SELECT deparse_shard_query_test(' -INSERT INTO aggregated_events (sum_value_1, sum_value_5, tenant_id) -WITH RECURSIVE hierarchy as ( - SELECT value_1, 1 AS LEVEL, tenant_id - FROM raw_events_1 - WHERE tenant_id = 1 - UNION - SELECT re.value_2, (h.level+1), re.tenant_id - FROM hierarchy h JOIN raw_events_1 re - ON (h.tenant_id = re.tenant_id AND - h.value_1 = re.value_6)) -SELECT * FROM hierarchy WHERE LEVEL <= 2; -'); -INFO: query: INSERT INTO multi_deparse_shard_query.aggregated_events (tenant_id, sum_value_1, sum_value_5) WITH RECURSIVE hierarchy AS (SELECT raw_events_1.value_1, 1 AS level, raw_events_1.tenant_id FROM multi_deparse_shard_query.raw_events_1 WHERE (raw_events_1.tenant_id OPERATOR(pg_catalog.=) 1) UNION SELECT re.value_2, (h.level OPERATOR(pg_catalog.+) 1), re.tenant_id FROM (hierarchy h JOIN multi_deparse_shard_query.raw_events_1 re ON (((h.tenant_id OPERATOR(pg_catalog.=) re.tenant_id) AND (h.value_1 OPERATOR(pg_catalog.=) re.value_6))))) SELECT tenant_id, value_1, level FROM hierarchy WHERE (level OPERATOR(pg_catalog.<=) 2) - deparse_shard_query_test ---------------------------------------------------------------------- - -(1 row) - -SELECT deparse_shard_query_test(' -INSERT INTO aggregated_events (sum_value_1) -SELECT - DISTINCT value_1 -FROM - raw_events_1; -'); -INFO: query: INSERT INTO multi_deparse_shard_query.aggregated_events (sum_value_1) SELECT DISTINCT value_1 FROM multi_deparse_shard_query.raw_events_1 - deparse_shard_query_test ---------------------------------------------------------------------- - -(1 row) - --- many filters suffled -SELECT deparse_shard_query_test(E' -INSERT INTO aggregated_events (sum_value_5, sum_value_1, tenant_id) -SELECT value_3, value_2, tenant_id - FROM raw_events_1 - WHERE (value_5 like \'%s\' or value_5 like \'%a\') and (tenant_id = 1) and (value_6 < 3000 or value_3 > 8000); -'); -INFO: query: INSERT INTO multi_deparse_shard_query.aggregated_events (tenant_id, sum_value_1, sum_value_5) SELECT tenant_id, value_2, value_3 FROM multi_deparse_shard_query.raw_events_1 WHERE (((value_5 OPERATOR(pg_catalog.~~) '%s'::text) OR (value_5 OPERATOR(pg_catalog.~~) '%a'::text)) AND (tenant_id OPERATOR(pg_catalog.=) 1) AND ((value_6 OPERATOR(pg_catalog.<) 3000) OR (value_3 OPERATOR(pg_catalog.>) (8000)::double precision))) - deparse_shard_query_test ---------------------------------------------------------------------- - -(1 row) - -SELECT deparse_shard_query_test(E' -INSERT INTO aggregated_events (sum_value_5, tenant_id) -SELECT rank() OVER (PARTITION BY tenant_id ORDER BY value_6), tenant_id - FROM raw_events_1 - WHERE event_at = now(); -'); -INFO: query: INSERT INTO multi_deparse_shard_query.aggregated_events (tenant_id, sum_value_5) SELECT tenant_id, rank() OVER (PARTITION BY tenant_id ORDER BY value_6) AS rank FROM multi_deparse_shard_query.raw_events_1 WHERE (event_at OPERATOR(pg_catalog.=) now()) - deparse_shard_query_test ---------------------------------------------------------------------- - -(1 row) - -SELECT deparse_shard_query_test(E' -INSERT INTO aggregated_events (sum_value_5, tenant_id, sum_value_4) -SELECT random(), int4eq(1, max(value_1))::int, value_6 - FROM raw_events_1 - WHERE event_at = now() - GROUP BY event_at, value_7, value_6; -'); -INFO: query: INSERT INTO multi_deparse_shard_query.aggregated_events (tenant_id, sum_value_4, sum_value_5) SELECT (int4eq(1, max(value_1)))::integer AS int4eq, value_6, random() AS random FROM multi_deparse_shard_query.raw_events_1 WHERE (event_at OPERATOR(pg_catalog.=) now()) GROUP BY event_at, value_7, value_6 - deparse_shard_query_test ---------------------------------------------------------------------- - -(1 row) - -SELECT deparse_shard_query_test(' -INSERT INTO aggregated_events (sum_value_1, tenant_id) -SELECT - count(DISTINCT CASE - WHEN - value_1 > 100 - THEN - tenant_id - ELSE - value_6 - END) as c, - max(tenant_id) - FROM - raw_events_1; -'); -INFO: query: INSERT INTO multi_deparse_shard_query.aggregated_events (tenant_id, sum_value_1) SELECT max(tenant_id) AS max, count(DISTINCT CASE WHEN (value_1 OPERATOR(pg_catalog.>) 100) THEN tenant_id ELSE (value_6)::bigint END) AS c FROM multi_deparse_shard_query.raw_events_1 - deparse_shard_query_test ---------------------------------------------------------------------- - -(1 row) - -SELECT deparse_shard_query_test(' -INSERT INTO raw_events_1(value_7, value_1, tenant_id) -SELECT - value_7, value_1, tenant_id -FROM - (SELECT - tenant_id, value_2 as value_7, value_1 - FROM - raw_events_2 - ) as foo -'); -INFO: query: INSERT INTO multi_deparse_shard_query.raw_events_1 (tenant_id, value_1, value_6, value_7, event_at) SELECT tenant_id, value_1, 10 AS value_6, value_7, (now())::date AS event_at FROM (SELECT raw_events_2.tenant_id, raw_events_2.value_2 AS value_7, raw_events_2.value_1 FROM multi_deparse_shard_query.raw_events_2) foo - deparse_shard_query_test ---------------------------------------------------------------------- - -(1 row) - -SELECT deparse_shard_query_test(E' -INSERT INTO aggregated_events(sum_value_1, tenant_id, sum_value_5) -SELECT - sum(value_1), tenant_id, sum(value_5::bigint) -FROM - (SELECT - raw_events_1.event_at, raw_events_2.tenant_id, raw_events_2.value_5, raw_events_1.value_1 - FROM - raw_events_2, raw_events_1 - WHERE - raw_events_1.tenant_id = raw_events_2.tenant_id - ) as foo -GROUP BY - tenant_id, date_trunc(\'hour\', event_at) -'); -INFO: query: INSERT INTO multi_deparse_shard_query.aggregated_events (tenant_id, sum_value_1, sum_value_5) SELECT tenant_id, sum(value_1) AS sum, sum((value_5)::bigint) AS sum FROM (SELECT raw_events_1.event_at, raw_events_2.tenant_id, raw_events_2.value_5, raw_events_1.value_1 FROM multi_deparse_shard_query.raw_events_2, multi_deparse_shard_query.raw_events_1 WHERE (raw_events_1.tenant_id OPERATOR(pg_catalog.=) raw_events_2.tenant_id)) foo GROUP BY tenant_id, (date_trunc('hour'::text, (event_at)::timestamp with time zone)) - deparse_shard_query_test ---------------------------------------------------------------------- - -(1 row) - -SELECT deparse_shard_query_test(E' -INSERT INTO raw_events_2(tenant_id, value_1, value_2, value_3, value_4) -SELECT - tenant_id, value_1, value_2, value_3, value_4 -FROM - (SELECT - value_2, value_4, tenant_id, value_1, value_3 - FROM - raw_events_1 - ) as foo -'); -INFO: query: INSERT INTO multi_deparse_shard_query.raw_events_2 (tenant_id, value_1, value_2, value_3, value_4, value_6, event_at) SELECT tenant_id, value_1, value_2, value_3, value_4, (random() OPERATOR(pg_catalog.*) (100)::double precision) AS value_6, (now())::date AS event_at FROM (SELECT raw_events_1.value_2, raw_events_1.value_4, raw_events_1.tenant_id, raw_events_1.value_1, raw_events_1.value_3 FROM multi_deparse_shard_query.raw_events_1) foo - deparse_shard_query_test ---------------------------------------------------------------------- - -(1 row) - -SELECT deparse_shard_query_test(E' -INSERT INTO raw_events_2(tenant_id, value_1, value_4, value_2, value_3) -SELECT - * -FROM - (SELECT - value_2, value_4, tenant_id, value_1, value_3 - FROM - raw_events_1 - ) as foo -'); -INFO: query: INSERT INTO multi_deparse_shard_query.raw_events_2 (tenant_id, value_1, value_2, value_3, value_4, value_6, event_at) SELECT value_2, value_4, value_1, value_3, tenant_id, (random() OPERATOR(pg_catalog.*) (100)::double precision) AS value_6, (now())::date AS event_at FROM (SELECT raw_events_1.value_2, raw_events_1.value_4, raw_events_1.tenant_id, raw_events_1.value_1, raw_events_1.value_3 FROM multi_deparse_shard_query.raw_events_1) foo - deparse_shard_query_test ---------------------------------------------------------------------- - -(1 row) - --- use a column multiple times -SELECT deparse_shard_query_test(' -INSERT INTO raw_events_1(tenant_id, value_7, value_4) -SELECT - tenant_id, value_7, value_7 -FROM - raw_events_1 -ORDER BY - value_2, value_1; -'); -INFO: query: INSERT INTO multi_deparse_shard_query.raw_events_1 (tenant_id, value_4, value_6, value_7, event_at) SELECT tenant_id, value_7, 10 AS value_6, value_7, (now())::date AS event_at FROM multi_deparse_shard_query.raw_events_1 ORDER BY value_2, value_1 - deparse_shard_query_test ---------------------------------------------------------------------- - -(1 row) - --- test dropped table as well -ALTER TABLE raw_events_1 DROP COLUMN value_5; -SELECT deparse_shard_query_test(' -INSERT INTO raw_events_1(tenant_id, value_7, value_4) -SELECT - tenant_id, value_7, value_4 -FROM - raw_events_1; -'); -INFO: query: INSERT INTO multi_deparse_shard_query.raw_events_1 (tenant_id, value_4, value_6, value_7, event_at) SELECT tenant_id, value_4, 10 AS value_6, value_7, (now())::date AS event_at FROM multi_deparse_shard_query.raw_events_1 - deparse_shard_query_test ---------------------------------------------------------------------- - -(1 row) - -SET client_min_messages TO ERROR; -DROP SCHEMA multi_deparse_shard_query CASCADE; diff --git a/src/test/regress/expected/multi_extension.out b/src/test/regress/expected/multi_extension.out index ac3800aed..58414a4ec 100644 --- a/src/test/regress/expected/multi_extension.out +++ b/src/test/regress/expected/multi_extension.out @@ -747,14 +747,8 @@ SELECT * FROM multi_extension.print_extension_changes(); -- recreate public schema, and recreate citus_tables in the public schema by default CREATE SCHEMA public; --- In PG15, public schema is owned by pg_database_owner role --- Relevant PG commit: b073c3ccd06e4cb845e121387a43faa8c68a7b62 -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 +-- public schema is owned by pg_database_owner role ALTER SCHEMA public OWNER TO pg_database_owner; -\endif GRANT ALL ON SCHEMA public TO public; ALTER EXTENSION citus UPDATE TO '9.5-1'; ALTER EXTENSION citus UPDATE TO '10.0-4'; diff --git a/src/test/regress/expected/multi_insert_select.out b/src/test/regress/expected/multi_insert_select.out index 26a7dfcf5..58d22583e 100644 --- a/src/test/regress/expected/multi_insert_select.out +++ b/src/test/regress/expected/multi_insert_select.out @@ -1,19 +1,8 @@ -- -- MULTI_INSERT_SELECT -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- CREATE SCHEMA multi_insert_select; SET search_path = multi_insert_select,public; -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - t -(1 row) - SET citus.next_shard_id TO 13300000; SET citus.next_placement_id TO 13300000; -- create co-located tables diff --git a/src/test/regress/expected/multi_insert_select_0.out b/src/test/regress/expected/multi_insert_select_0.out deleted file mode 100644 index 193c869b1..000000000 --- a/src/test/regress/expected/multi_insert_select_0.out +++ /dev/null @@ -1,3507 +0,0 @@ --- --- MULTI_INSERT_SELECT --- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -CREATE SCHEMA multi_insert_select; -SET search_path = multi_insert_select,public; -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - f -(1 row) - -SET citus.next_shard_id TO 13300000; -SET citus.next_placement_id TO 13300000; --- create co-located tables -SET citus.shard_count = 4; -SET citus.shard_replication_factor = 2; --- order of execution might change in parallel executions --- and the error details might contain the worker node --- so be less verbose with \set VERBOSITY TERSE when necessary -CREATE TABLE raw_events_first (user_id int, time timestamp, value_1 int, value_2 int, value_3 float, value_4 bigint, UNIQUE(user_id, value_1)); -SELECT create_distributed_table('raw_events_first', 'user_id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -CREATE TABLE raw_events_second (user_id int, time timestamp, value_1 int, value_2 int, value_3 float, value_4 bigint, UNIQUE(user_id, value_1)); -SELECT create_distributed_table('raw_events_second', 'user_id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -CREATE TABLE agg_events (user_id int, value_1_agg int, value_2_agg int, value_3_agg float, value_4_agg bigint, agg_time timestamp, UNIQUE(user_id, value_1_agg)); -SELECT create_distributed_table('agg_events', 'user_id');; - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - --- create the reference table as well -CREATE TABLE reference_table (user_id int); -SELECT create_reference_table('reference_table'); - create_reference_table ---------------------------------------------------------------------- - -(1 row) - -CREATE TABLE insert_select_varchar_test (key varchar, value int); -SELECT create_distributed_table('insert_select_varchar_test', 'key', 'hash'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - --- set back to the defaults -SET citus.shard_count = DEFAULT; -SET citus.shard_replication_factor = DEFAULT; -INSERT INTO raw_events_first (user_id, time, value_1, value_2, value_3, value_4) VALUES - (1, now(), 10, 100, 1000.1, 10000); -INSERT INTO raw_events_first (user_id, time, value_1, value_2, value_3, value_4) VALUES - (2, now(), 20, 200, 2000.1, 20000); -INSERT INTO raw_events_first (user_id, time, value_1, value_2, value_3, value_4) VALUES - (3, now(), 30, 300, 3000.1, 30000); -INSERT INTO raw_events_first (user_id, time, value_1, value_2, value_3, value_4) VALUES - (4, now(), 40, 400, 4000.1, 40000); -INSERT INTO raw_events_first (user_id, time, value_1, value_2, value_3, value_4) VALUES - (5, now(), 50, 500, 5000.1, 50000); -INSERT INTO raw_events_first (user_id, time, value_1, value_2, value_3, value_4) VALUES - (6, now(), 60, 600, 6000.1, 60000); -SET client_min_messages TO DEBUG2; --- raw table to raw table -INSERT INTO raw_events_second SELECT * FROM raw_events_first; -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300004 AS citus_table_alias (user_id, "time", value_1, value_2, value_3, value_4) SELECT user_id, "time", value_1, value_2, value_3, value_4 FROM multi_insert_select.raw_events_first_13300000 raw_events_first WHERE (user_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300005 AS citus_table_alias (user_id, "time", value_1, value_2, value_3, value_4) SELECT user_id, "time", value_1, value_2, value_3, value_4 FROM multi_insert_select.raw_events_first_13300001 raw_events_first WHERE (user_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300006 AS citus_table_alias (user_id, "time", value_1, value_2, value_3, value_4) SELECT user_id, "time", value_1, value_2, value_3, value_4 FROM multi_insert_select.raw_events_first_13300002 raw_events_first WHERE (user_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300007 AS citus_table_alias (user_id, "time", value_1, value_2, value_3, value_4) SELECT user_id, "time", value_1, value_2, value_3, value_4 FROM multi_insert_select.raw_events_first_13300003 raw_events_first WHERE (user_id IS NOT NULL) --- see that our first multi shard INSERT...SELECT works expected -SET client_min_messages TO INFO; -SELECT - raw_events_first.user_id -FROM - raw_events_first, raw_events_second -WHERE - raw_events_first.user_id = raw_events_second.user_id -ORDER BY - user_id DESC; - user_id ---------------------------------------------------------------------- - 6 - 5 - 4 - 3 - 2 - 1 -(6 rows) - --- see that we get unique vialitons -\set VERBOSITY TERSE -INSERT INTO raw_events_second SELECT * FROM raw_events_first; -ERROR: duplicate key value violates unique constraint "raw_events_second_user_id_value_1_key_13300004" -\set VERBOSITY DEFAULT --- stable functions should be allowed -INSERT INTO raw_events_second (user_id, time) -SELECT - user_id, now() -FROM - raw_events_first -WHERE - user_id < 0; -INSERT INTO raw_events_second (user_id) -SELECT - user_id -FROM - raw_events_first -WHERE - time > now() + interval '1 day'; --- hide version-dependent PL/pgSQL context messages -\set VERBOSITY terse --- make sure we evaluate stable functions on the master, once -CREATE OR REPLACE FUNCTION evaluate_on_master() -RETURNS int LANGUAGE plpgsql STABLE -AS $function$ -BEGIN - RAISE NOTICE 'evaluating on master'; - RETURN 0; -END; -$function$; -INSERT INTO raw_events_second (user_id, value_1) -SELECT - user_id, evaluate_on_master() -FROM - raw_events_first -WHERE - user_id < 0; -NOTICE: evaluating on master --- make sure we don't evaluate stable functions with column arguments -SET citus.enable_metadata_sync TO OFF; -CREATE OR REPLACE FUNCTION evaluate_on_master(x int) -RETURNS int LANGUAGE plpgsql STABLE -AS $function$ -BEGIN - RAISE NOTICE 'evaluating on master'; - RETURN x; -END; -$function$; -RESET citus.enable_metadata_sync; -INSERT INTO raw_events_second (user_id, value_1) -SELECT - user_id, evaluate_on_master(value_1) -FROM - raw_events_first -WHERE - user_id = 0; -ERROR: function multi_insert_select.evaluate_on_master(integer) does not exist --- add one more row -INSERT INTO raw_events_first (user_id, time) VALUES - (7, now()); --- try a single shard query -SET client_min_messages TO DEBUG2; -INSERT INTO raw_events_second (user_id, time) SELECT user_id, time FROM raw_events_first WHERE user_id = 7; -DEBUG: Creating router plan -DEBUG: Skipping target shard interval 13300004 since SELECT query for it pruned away -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300005 AS citus_table_alias (user_id, "time") SELECT user_id, "time" FROM multi_insert_select.raw_events_first_13300001 raw_events_first WHERE ((user_id OPERATOR(pg_catalog.=) 7) AND (user_id IS NOT NULL)) -DEBUG: Skipping target shard interval 13300006 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300007 since SELECT query for it pruned away -SET client_min_messages TO INFO; --- add one more row -INSERT INTO raw_events_first (user_id, time, value_1, value_2, value_3, value_4) VALUES - (8, now(), 80, 800, 8000, 80000); --- reorder columns -SET client_min_messages TO DEBUG2; -INSERT INTO raw_events_second (value_2, value_1, value_3, value_4, user_id, time) -SELECT - value_2, value_1, value_3, value_4, user_id, time -FROM - raw_events_first -WHERE - user_id = 8; -DEBUG: Creating router plan -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300004 AS citus_table_alias (user_id, "time", value_1, value_2, value_3, value_4) SELECT user_id, "time", value_1, value_2, value_3, value_4 FROM multi_insert_select.raw_events_first_13300000 raw_events_first WHERE ((user_id OPERATOR(pg_catalog.=) 8) AND (user_id IS NOT NULL)) -DEBUG: Skipping target shard interval 13300005 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300006 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300007 since SELECT query for it pruned away --- a zero shard select -INSERT INTO raw_events_second (value_2, value_1, value_3, value_4, user_id, time) -SELECT - value_2, value_1, value_3, value_4, user_id, time -FROM - raw_events_first -WHERE - false; -DEBUG: Creating router plan -DEBUG: Skipping target shard interval 13300004 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300005 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300006 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300007 since SELECT query for it pruned away --- another zero shard select -INSERT INTO raw_events_second (value_2, value_1, value_3, value_4, user_id, time) -SELECT - value_2, value_1, value_3, value_4, user_id, time -FROM - raw_events_first -WHERE - 0 != 0; -DEBUG: Creating router plan -DEBUG: Skipping target shard interval 13300004 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300005 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300006 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300007 since SELECT query for it pruned away --- add one more row -SET client_min_messages TO INFO; -INSERT INTO raw_events_first (user_id, time, value_1, value_2, value_3, value_4) VALUES - (9, now(), 90, 900, 9000, 90000); --- show that RETURNING also works -SET client_min_messages TO DEBUG2; -INSERT INTO raw_events_second (user_id, value_1, value_3) -SELECT - user_id, value_1, value_3 -FROM - raw_events_first -WHERE - value_3 = 9000 -RETURNING *; -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300004 AS citus_table_alias (user_id, value_1, value_3) SELECT user_id, value_1, value_3 FROM multi_insert_select.raw_events_first_13300000 raw_events_first WHERE ((value_3 OPERATOR(pg_catalog.=) (9000)::double precision) AND (user_id IS NOT NULL)) RETURNING citus_table_alias.user_id, citus_table_alias."time", citus_table_alias.value_1, citus_table_alias.value_2, citus_table_alias.value_3, citus_table_alias.value_4 -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300005 AS citus_table_alias (user_id, value_1, value_3) SELECT user_id, value_1, value_3 FROM multi_insert_select.raw_events_first_13300001 raw_events_first WHERE ((value_3 OPERATOR(pg_catalog.=) (9000)::double precision) AND (user_id IS NOT NULL)) RETURNING citus_table_alias.user_id, citus_table_alias."time", citus_table_alias.value_1, citus_table_alias.value_2, citus_table_alias.value_3, citus_table_alias.value_4 -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300006 AS citus_table_alias (user_id, value_1, value_3) SELECT user_id, value_1, value_3 FROM multi_insert_select.raw_events_first_13300002 raw_events_first WHERE ((value_3 OPERATOR(pg_catalog.=) (9000)::double precision) AND (user_id IS NOT NULL)) RETURNING citus_table_alias.user_id, citus_table_alias."time", citus_table_alias.value_1, citus_table_alias.value_2, citus_table_alias.value_3, citus_table_alias.value_4 -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300007 AS citus_table_alias (user_id, value_1, value_3) SELECT user_id, value_1, value_3 FROM multi_insert_select.raw_events_first_13300003 raw_events_first WHERE ((value_3 OPERATOR(pg_catalog.=) (9000)::double precision) AND (user_id IS NOT NULL)) RETURNING citus_table_alias.user_id, citus_table_alias."time", citus_table_alias.value_1, citus_table_alias.value_2, citus_table_alias.value_3, citus_table_alias.value_4 - user_id | time | value_1 | value_2 | value_3 | value_4 ---------------------------------------------------------------------- - 9 | | 90 | | 9000 | -(1 row) - --- hits two shards -\set VERBOSITY TERSE -INSERT INTO raw_events_second (user_id, value_1, value_3) -SELECT - user_id, value_1, value_3 -FROM - raw_events_first -WHERE - user_id = 9 OR user_id = 16 -RETURNING *; -DEBUG: Skipping target shard interval 13300004 since SELECT query for it pruned away -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300005 AS citus_table_alias (user_id, value_1, value_3) SELECT user_id, value_1, value_3 FROM multi_insert_select.raw_events_first_13300001 raw_events_first WHERE (((user_id OPERATOR(pg_catalog.=) 9) OR (user_id OPERATOR(pg_catalog.=) 16)) AND (user_id IS NOT NULL)) RETURNING citus_table_alias.user_id, citus_table_alias."time", citus_table_alias.value_1, citus_table_alias.value_2, citus_table_alias.value_3, citus_table_alias.value_4 -DEBUG: Skipping target shard interval 13300006 since SELECT query for it pruned away -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300007 AS citus_table_alias (user_id, value_1, value_3) SELECT user_id, value_1, value_3 FROM multi_insert_select.raw_events_first_13300003 raw_events_first WHERE (((user_id OPERATOR(pg_catalog.=) 9) OR (user_id OPERATOR(pg_catalog.=) 16)) AND (user_id IS NOT NULL)) RETURNING citus_table_alias.user_id, citus_table_alias."time", citus_table_alias.value_1, citus_table_alias.value_2, citus_table_alias.value_3, citus_table_alias.value_4 -ERROR: duplicate key value violates unique constraint "raw_events_second_user_id_value_1_key_13300007" --- now do some aggregations -INSERT INTO agg_events -SELECT - user_id, sum(value_1), avg(value_2), sum(value_3), count(value_4) -FROM - raw_events_first -GROUP BY - user_id; -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300008 AS citus_table_alias (user_id, value_1_agg, value_2_agg, value_3_agg, value_4_agg) SELECT user_id, sum(value_1) AS sum, avg(value_2) AS avg, sum(value_3) AS sum, count(value_4) AS count FROM multi_insert_select.raw_events_first_13300000 raw_events_first WHERE (user_id IS NOT NULL) GROUP BY user_id -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300009 AS citus_table_alias (user_id, value_1_agg, value_2_agg, value_3_agg, value_4_agg) SELECT user_id, sum(value_1) AS sum, avg(value_2) AS avg, sum(value_3) AS sum, count(value_4) AS count FROM multi_insert_select.raw_events_first_13300001 raw_events_first WHERE (user_id IS NOT NULL) GROUP BY user_id -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300010 AS citus_table_alias (user_id, value_1_agg, value_2_agg, value_3_agg, value_4_agg) SELECT user_id, sum(value_1) AS sum, avg(value_2) AS avg, sum(value_3) AS sum, count(value_4) AS count FROM multi_insert_select.raw_events_first_13300002 raw_events_first WHERE (user_id IS NOT NULL) GROUP BY user_id -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300011 AS citus_table_alias (user_id, value_1_agg, value_2_agg, value_3_agg, value_4_agg) SELECT user_id, sum(value_1) AS sum, avg(value_2) AS avg, sum(value_3) AS sum, count(value_4) AS count FROM multi_insert_select.raw_events_first_13300003 raw_events_first WHERE (user_id IS NOT NULL) GROUP BY user_id --- group by column not exists on the SELECT target list -INSERT INTO agg_events (value_3_agg, value_4_agg, value_1_agg, user_id) -SELECT - sum(value_3), count(value_4), sum(value_1), user_id -FROM - raw_events_first -GROUP BY - value_2, user_id -RETURNING *; -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300008 AS citus_table_alias (user_id, value_1_agg, value_3_agg, value_4_agg) SELECT user_id, sum(value_1) AS sum, sum(value_3) AS sum, count(value_4) AS count FROM multi_insert_select.raw_events_first_13300000 raw_events_first WHERE (user_id IS NOT NULL) GROUP BY value_2, user_id RETURNING citus_table_alias.user_id, citus_table_alias.value_1_agg, citus_table_alias.value_2_agg, citus_table_alias.value_3_agg, citus_table_alias.value_4_agg, citus_table_alias.agg_time -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300009 AS citus_table_alias (user_id, value_1_agg, value_3_agg, value_4_agg) SELECT user_id, sum(value_1) AS sum, sum(value_3) AS sum, count(value_4) AS count FROM multi_insert_select.raw_events_first_13300001 raw_events_first WHERE (user_id IS NOT NULL) GROUP BY value_2, user_id RETURNING citus_table_alias.user_id, citus_table_alias.value_1_agg, citus_table_alias.value_2_agg, citus_table_alias.value_3_agg, citus_table_alias.value_4_agg, citus_table_alias.agg_time -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300010 AS citus_table_alias (user_id, value_1_agg, value_3_agg, value_4_agg) SELECT user_id, sum(value_1) AS sum, sum(value_3) AS sum, count(value_4) AS count FROM multi_insert_select.raw_events_first_13300002 raw_events_first WHERE (user_id IS NOT NULL) GROUP BY value_2, user_id RETURNING citus_table_alias.user_id, citus_table_alias.value_1_agg, citus_table_alias.value_2_agg, citus_table_alias.value_3_agg, citus_table_alias.value_4_agg, citus_table_alias.agg_time -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300011 AS citus_table_alias (user_id, value_1_agg, value_3_agg, value_4_agg) SELECT user_id, sum(value_1) AS sum, sum(value_3) AS sum, count(value_4) AS count FROM multi_insert_select.raw_events_first_13300003 raw_events_first WHERE (user_id IS NOT NULL) GROUP BY value_2, user_id RETURNING citus_table_alias.user_id, citus_table_alias.value_1_agg, citus_table_alias.value_2_agg, citus_table_alias.value_3_agg, citus_table_alias.value_4_agg, citus_table_alias.agg_time -ERROR: duplicate key value violates unique constraint "agg_events_user_id_value_1_agg_key_13300008" --- some subquery tests -INSERT INTO agg_events - (value_1_agg, - user_id) -SELECT SUM(value_1), - id -FROM (SELECT raw_events_second.user_id AS id, - raw_events_second.value_1 - FROM raw_events_first, - raw_events_second - WHERE raw_events_first.user_id = raw_events_second.user_id) AS foo -GROUP BY id -ORDER BY id; -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300008 AS citus_table_alias (user_id, value_1_agg) SELECT id, sum(value_1) AS sum FROM (SELECT raw_events_second.user_id AS id, raw_events_second.value_1 FROM multi_insert_select.raw_events_first_13300000 raw_events_first, multi_insert_select.raw_events_second_13300004 raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id)) foo WHERE (id IS NOT NULL) GROUP BY id ORDER BY id -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300009 AS citus_table_alias (user_id, value_1_agg) SELECT id, sum(value_1) AS sum FROM (SELECT raw_events_second.user_id AS id, raw_events_second.value_1 FROM multi_insert_select.raw_events_first_13300001 raw_events_first, multi_insert_select.raw_events_second_13300005 raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id)) foo WHERE (id IS NOT NULL) GROUP BY id ORDER BY id -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300010 AS citus_table_alias (user_id, value_1_agg) SELECT id, sum(value_1) AS sum FROM (SELECT raw_events_second.user_id AS id, raw_events_second.value_1 FROM multi_insert_select.raw_events_first_13300002 raw_events_first, multi_insert_select.raw_events_second_13300006 raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id)) foo WHERE (id IS NOT NULL) GROUP BY id ORDER BY id -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300011 AS citus_table_alias (user_id, value_1_agg) SELECT id, sum(value_1) AS sum FROM (SELECT raw_events_second.user_id AS id, raw_events_second.value_1 FROM multi_insert_select.raw_events_first_13300003 raw_events_first, multi_insert_select.raw_events_second_13300007 raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id)) foo WHERE (id IS NOT NULL) GROUP BY id ORDER BY id -ERROR: duplicate key value violates unique constraint "agg_events_user_id_value_1_agg_key_13300008" --- subquery one more level depth -INSERT INTO agg_events - (value_4_agg, - value_1_agg, - user_id) -SELECT v4, - v1, - id -FROM (SELECT SUM(raw_events_second.value_4) AS v4, - SUM(raw_events_first.value_1) AS v1, - raw_events_second.user_id AS id - FROM raw_events_first, - raw_events_second - WHERE raw_events_first.user_id = raw_events_second.user_id - GROUP BY raw_events_second.user_id) AS foo -ORDER BY id; -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300008 AS citus_table_alias (user_id, value_1_agg, value_4_agg) SELECT id, v1, v4 FROM (SELECT sum(raw_events_second.value_4) AS v4, sum(raw_events_first.value_1) AS v1, raw_events_second.user_id AS id FROM multi_insert_select.raw_events_first_13300000 raw_events_first, multi_insert_select.raw_events_second_13300004 raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.user_id) foo WHERE (id IS NOT NULL) ORDER BY id -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300009 AS citus_table_alias (user_id, value_1_agg, value_4_agg) SELECT id, v1, v4 FROM (SELECT sum(raw_events_second.value_4) AS v4, sum(raw_events_first.value_1) AS v1, raw_events_second.user_id AS id FROM multi_insert_select.raw_events_first_13300001 raw_events_first, multi_insert_select.raw_events_second_13300005 raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.user_id) foo WHERE (id IS NOT NULL) ORDER BY id -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300010 AS citus_table_alias (user_id, value_1_agg, value_4_agg) SELECT id, v1, v4 FROM (SELECT sum(raw_events_second.value_4) AS v4, sum(raw_events_first.value_1) AS v1, raw_events_second.user_id AS id FROM multi_insert_select.raw_events_first_13300002 raw_events_first, multi_insert_select.raw_events_second_13300006 raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.user_id) foo WHERE (id IS NOT NULL) ORDER BY id -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300011 AS citus_table_alias (user_id, value_1_agg, value_4_agg) SELECT id, v1, v4 FROM (SELECT sum(raw_events_second.value_4) AS v4, sum(raw_events_first.value_1) AS v1, raw_events_second.user_id AS id FROM multi_insert_select.raw_events_first_13300003 raw_events_first, multi_insert_select.raw_events_second_13300007 raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.user_id) foo WHERE (id IS NOT NULL) ORDER BY id -ERROR: duplicate key value violates unique constraint "agg_events_user_id_value_1_agg_key_13300008" -\set VERBOSITY DEFAULT --- join between subqueries -INSERT INTO agg_events - (user_id) -SELECT f2.id FROM -(SELECT - id -FROM (SELECT reference_table.user_id AS id - FROM raw_events_first, - reference_table - WHERE raw_events_first.user_id = reference_table.user_id ) AS foo) as f -INNER JOIN -(SELECT v4, - v1, - id -FROM (SELECT SUM(raw_events_second.value_4) AS v4, - SUM(raw_events_first.value_1) AS v1, - raw_events_second.user_id AS id - FROM raw_events_first, - raw_events_second - WHERE raw_events_first.user_id = raw_events_second.user_id - GROUP BY raw_events_second.user_id - HAVING SUM(raw_events_second.value_4) > 10) AS foo2 ) as f2 -ON (f.id = f2.id); -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300008 AS citus_table_alias (user_id) SELECT f2.id FROM ((SELECT foo.id FROM (SELECT reference_table.user_id AS id FROM multi_insert_select.raw_events_first_13300000 raw_events_first, multi_insert_select.reference_table_13300012 reference_table WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) reference_table.user_id)) foo) f JOIN (SELECT foo2.v4, foo2.v1, foo2.id FROM (SELECT sum(raw_events_second.value_4) AS v4, sum(raw_events_first.value_1) AS v1, raw_events_second.user_id AS id FROM multi_insert_select.raw_events_first_13300000 raw_events_first, multi_insert_select.raw_events_second_13300004 raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.user_id HAVING (sum(raw_events_second.value_4) OPERATOR(pg_catalog.>) (10)::numeric)) foo2) f2 ON ((f.id OPERATOR(pg_catalog.=) f2.id))) WHERE (f2.id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300009 AS citus_table_alias (user_id) SELECT f2.id FROM ((SELECT foo.id FROM (SELECT reference_table.user_id AS id FROM multi_insert_select.raw_events_first_13300001 raw_events_first, multi_insert_select.reference_table_13300012 reference_table WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) reference_table.user_id)) foo) f JOIN (SELECT foo2.v4, foo2.v1, foo2.id FROM (SELECT sum(raw_events_second.value_4) AS v4, sum(raw_events_first.value_1) AS v1, raw_events_second.user_id AS id FROM multi_insert_select.raw_events_first_13300001 raw_events_first, multi_insert_select.raw_events_second_13300005 raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.user_id HAVING (sum(raw_events_second.value_4) OPERATOR(pg_catalog.>) (10)::numeric)) foo2) f2 ON ((f.id OPERATOR(pg_catalog.=) f2.id))) WHERE (f2.id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300010 AS citus_table_alias (user_id) SELECT f2.id FROM ((SELECT foo.id FROM (SELECT reference_table.user_id AS id FROM multi_insert_select.raw_events_first_13300002 raw_events_first, multi_insert_select.reference_table_13300012 reference_table WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) reference_table.user_id)) foo) f JOIN (SELECT foo2.v4, foo2.v1, foo2.id FROM (SELECT sum(raw_events_second.value_4) AS v4, sum(raw_events_first.value_1) AS v1, raw_events_second.user_id AS id FROM multi_insert_select.raw_events_first_13300002 raw_events_first, multi_insert_select.raw_events_second_13300006 raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.user_id HAVING (sum(raw_events_second.value_4) OPERATOR(pg_catalog.>) (10)::numeric)) foo2) f2 ON ((f.id OPERATOR(pg_catalog.=) f2.id))) WHERE (f2.id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300011 AS citus_table_alias (user_id) SELECT f2.id FROM ((SELECT foo.id FROM (SELECT reference_table.user_id AS id FROM multi_insert_select.raw_events_first_13300003 raw_events_first, multi_insert_select.reference_table_13300012 reference_table WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) reference_table.user_id)) foo) f JOIN (SELECT foo2.v4, foo2.v1, foo2.id FROM (SELECT sum(raw_events_second.value_4) AS v4, sum(raw_events_first.value_1) AS v1, raw_events_second.user_id AS id FROM multi_insert_select.raw_events_first_13300003 raw_events_first, multi_insert_select.raw_events_second_13300007 raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.user_id HAVING (sum(raw_events_second.value_4) OPERATOR(pg_catalog.>) (10)::numeric)) foo2) f2 ON ((f.id OPERATOR(pg_catalog.=) f2.id))) WHERE (f2.id IS NOT NULL) --- add one more level subqueris on top of subquery JOINs -INSERT INTO agg_events - (user_id, value_4_agg) -SELECT - outer_most.id, max(outer_most.value) -FROM -( - SELECT f2.id as id, f2.v4 as value FROM - (SELECT - id - FROM (SELECT reference_table.user_id AS id - FROM raw_events_first, - reference_table - WHERE raw_events_first.user_id = reference_table.user_id ) AS foo) as f - INNER JOIN - (SELECT v4, - v1, - id - FROM (SELECT SUM(raw_events_second.value_4) AS v4, - SUM(raw_events_first.value_1) AS v1, - raw_events_second.user_id AS id - FROM raw_events_first, - raw_events_second - WHERE raw_events_first.user_id = raw_events_second.user_id - GROUP BY raw_events_second.user_id - HAVING SUM(raw_events_second.value_4) > 10) AS foo2 ) as f2 -ON (f.id = f2.id)) as outer_most -GROUP BY - outer_most.id; -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300008 AS citus_table_alias (user_id, value_4_agg) SELECT id, max(value) AS max FROM (SELECT f2.id, f2.v4 AS value FROM ((SELECT foo.id FROM (SELECT reference_table.user_id AS id FROM multi_insert_select.raw_events_first_13300000 raw_events_first, multi_insert_select.reference_table_13300012 reference_table WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) reference_table.user_id)) foo) f JOIN (SELECT foo2.v4, foo2.v1, foo2.id FROM (SELECT sum(raw_events_second.value_4) AS v4, sum(raw_events_first.value_1) AS v1, raw_events_second.user_id AS id FROM multi_insert_select.raw_events_first_13300000 raw_events_first, multi_insert_select.raw_events_second_13300004 raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.user_id HAVING (sum(raw_events_second.value_4) OPERATOR(pg_catalog.>) (10)::numeric)) foo2) f2 ON ((f.id OPERATOR(pg_catalog.=) f2.id)))) outer_most WHERE (id IS NOT NULL) GROUP BY id -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300009 AS citus_table_alias (user_id, value_4_agg) SELECT id, max(value) AS max FROM (SELECT f2.id, f2.v4 AS value FROM ((SELECT foo.id FROM (SELECT reference_table.user_id AS id FROM multi_insert_select.raw_events_first_13300001 raw_events_first, multi_insert_select.reference_table_13300012 reference_table WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) reference_table.user_id)) foo) f JOIN (SELECT foo2.v4, foo2.v1, foo2.id FROM (SELECT sum(raw_events_second.value_4) AS v4, sum(raw_events_first.value_1) AS v1, raw_events_second.user_id AS id FROM multi_insert_select.raw_events_first_13300001 raw_events_first, multi_insert_select.raw_events_second_13300005 raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.user_id HAVING (sum(raw_events_second.value_4) OPERATOR(pg_catalog.>) (10)::numeric)) foo2) f2 ON ((f.id OPERATOR(pg_catalog.=) f2.id)))) outer_most WHERE (id IS NOT NULL) GROUP BY id -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300010 AS citus_table_alias (user_id, value_4_agg) SELECT id, max(value) AS max FROM (SELECT f2.id, f2.v4 AS value FROM ((SELECT foo.id FROM (SELECT reference_table.user_id AS id FROM multi_insert_select.raw_events_first_13300002 raw_events_first, multi_insert_select.reference_table_13300012 reference_table WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) reference_table.user_id)) foo) f JOIN (SELECT foo2.v4, foo2.v1, foo2.id FROM (SELECT sum(raw_events_second.value_4) AS v4, sum(raw_events_first.value_1) AS v1, raw_events_second.user_id AS id FROM multi_insert_select.raw_events_first_13300002 raw_events_first, multi_insert_select.raw_events_second_13300006 raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.user_id HAVING (sum(raw_events_second.value_4) OPERATOR(pg_catalog.>) (10)::numeric)) foo2) f2 ON ((f.id OPERATOR(pg_catalog.=) f2.id)))) outer_most WHERE (id IS NOT NULL) GROUP BY id -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300011 AS citus_table_alias (user_id, value_4_agg) SELECT id, max(value) AS max FROM (SELECT f2.id, f2.v4 AS value FROM ((SELECT foo.id FROM (SELECT reference_table.user_id AS id FROM multi_insert_select.raw_events_first_13300003 raw_events_first, multi_insert_select.reference_table_13300012 reference_table WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) reference_table.user_id)) foo) f JOIN (SELECT foo2.v4, foo2.v1, foo2.id FROM (SELECT sum(raw_events_second.value_4) AS v4, sum(raw_events_first.value_1) AS v1, raw_events_second.user_id AS id FROM multi_insert_select.raw_events_first_13300003 raw_events_first, multi_insert_select.raw_events_second_13300007 raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.user_id HAVING (sum(raw_events_second.value_4) OPERATOR(pg_catalog.>) (10)::numeric)) foo2) f2 ON ((f.id OPERATOR(pg_catalog.=) f2.id)))) outer_most WHERE (id IS NOT NULL) GROUP BY id --- subqueries in WHERE clause -INSERT INTO raw_events_second - (user_id) -SELECT user_id -FROM raw_events_first -WHERE user_id IN (SELECT user_id - FROM raw_events_second - WHERE user_id = 2); -DEBUG: Creating router plan -DEBUG: Skipping target shard interval 13300004 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300005 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300006 since SELECT query for it pruned away -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300007 AS citus_table_alias (user_id) SELECT user_id FROM multi_insert_select.raw_events_first_13300003 raw_events_first WHERE ((user_id OPERATOR(pg_catalog.=) ANY (SELECT raw_events_second.user_id FROM multi_insert_select.raw_events_second_13300007 raw_events_second WHERE (raw_events_second.user_id OPERATOR(pg_catalog.=) 2))) AND (user_id IS NOT NULL)) -INSERT INTO raw_events_second - (user_id) -SELECT user_id -FROM raw_events_first -WHERE user_id IN (SELECT user_id - FROM raw_events_second - WHERE user_id != 2 AND value_1 = 2000) -ON conflict (user_id, value_1) DO NOTHING; -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300004 AS citus_table_alias (user_id) SELECT user_id FROM multi_insert_select.raw_events_first_13300000 raw_events_first WHERE ((user_id OPERATOR(pg_catalog.=) ANY (SELECT raw_events_second.user_id FROM multi_insert_select.raw_events_second_13300004 raw_events_second WHERE ((raw_events_second.user_id OPERATOR(pg_catalog.<>) 2) AND (raw_events_second.value_1 OPERATOR(pg_catalog.=) 2000)))) AND (user_id IS NOT NULL)) ON CONFLICT(user_id, value_1) DO NOTHING -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300005 AS citus_table_alias (user_id) SELECT user_id FROM multi_insert_select.raw_events_first_13300001 raw_events_first WHERE ((user_id OPERATOR(pg_catalog.=) ANY (SELECT raw_events_second.user_id FROM multi_insert_select.raw_events_second_13300005 raw_events_second WHERE ((raw_events_second.user_id OPERATOR(pg_catalog.<>) 2) AND (raw_events_second.value_1 OPERATOR(pg_catalog.=) 2000)))) AND (user_id IS NOT NULL)) ON CONFLICT(user_id, value_1) DO NOTHING -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300006 AS citus_table_alias (user_id) SELECT user_id FROM multi_insert_select.raw_events_first_13300002 raw_events_first WHERE ((user_id OPERATOR(pg_catalog.=) ANY (SELECT raw_events_second.user_id FROM multi_insert_select.raw_events_second_13300006 raw_events_second WHERE ((raw_events_second.user_id OPERATOR(pg_catalog.<>) 2) AND (raw_events_second.value_1 OPERATOR(pg_catalog.=) 2000)))) AND (user_id IS NOT NULL)) ON CONFLICT(user_id, value_1) DO NOTHING -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300007 AS citus_table_alias (user_id) SELECT user_id FROM multi_insert_select.raw_events_first_13300003 raw_events_first WHERE ((user_id OPERATOR(pg_catalog.=) ANY (SELECT raw_events_second.user_id FROM multi_insert_select.raw_events_second_13300007 raw_events_second WHERE ((raw_events_second.user_id OPERATOR(pg_catalog.<>) 2) AND (raw_events_second.value_1 OPERATOR(pg_catalog.=) 2000)))) AND (user_id IS NOT NULL)) ON CONFLICT(user_id, value_1) DO NOTHING -INSERT INTO raw_events_second - (user_id) -SELECT user_id -FROM raw_events_first -WHERE user_id IN (SELECT user_id - FROM raw_events_second WHERE false); -DEBUG: Creating router plan -DEBUG: Skipping target shard interval 13300004 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300005 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300006 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300007 since SELECT query for it pruned away -INSERT INTO raw_events_second - (user_id) -SELECT user_id -FROM raw_events_first -WHERE user_id IN (SELECT user_id - FROM raw_events_second - WHERE value_1 = 1000 OR value_1 = 2000 OR value_1 = 3000); -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300004 AS citus_table_alias (user_id) SELECT user_id FROM multi_insert_select.raw_events_first_13300000 raw_events_first WHERE ((user_id OPERATOR(pg_catalog.=) ANY (SELECT raw_events_second.user_id FROM multi_insert_select.raw_events_second_13300004 raw_events_second WHERE ((raw_events_second.value_1 OPERATOR(pg_catalog.=) 1000) OR (raw_events_second.value_1 OPERATOR(pg_catalog.=) 2000) OR (raw_events_second.value_1 OPERATOR(pg_catalog.=) 3000)))) AND (user_id IS NOT NULL)) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300005 AS citus_table_alias (user_id) SELECT user_id FROM multi_insert_select.raw_events_first_13300001 raw_events_first WHERE ((user_id OPERATOR(pg_catalog.=) ANY (SELECT raw_events_second.user_id FROM multi_insert_select.raw_events_second_13300005 raw_events_second WHERE ((raw_events_second.value_1 OPERATOR(pg_catalog.=) 1000) OR (raw_events_second.value_1 OPERATOR(pg_catalog.=) 2000) OR (raw_events_second.value_1 OPERATOR(pg_catalog.=) 3000)))) AND (user_id IS NOT NULL)) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300006 AS citus_table_alias (user_id) SELECT user_id FROM multi_insert_select.raw_events_first_13300002 raw_events_first WHERE ((user_id OPERATOR(pg_catalog.=) ANY (SELECT raw_events_second.user_id FROM multi_insert_select.raw_events_second_13300006 raw_events_second WHERE ((raw_events_second.value_1 OPERATOR(pg_catalog.=) 1000) OR (raw_events_second.value_1 OPERATOR(pg_catalog.=) 2000) OR (raw_events_second.value_1 OPERATOR(pg_catalog.=) 3000)))) AND (user_id IS NOT NULL)) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300007 AS citus_table_alias (user_id) SELECT user_id FROM multi_insert_select.raw_events_first_13300003 raw_events_first WHERE ((user_id OPERATOR(pg_catalog.=) ANY (SELECT raw_events_second.user_id FROM multi_insert_select.raw_events_second_13300007 raw_events_second WHERE ((raw_events_second.value_1 OPERATOR(pg_catalog.=) 1000) OR (raw_events_second.value_1 OPERATOR(pg_catalog.=) 2000) OR (raw_events_second.value_1 OPERATOR(pg_catalog.=) 3000)))) AND (user_id IS NOT NULL)) --- lets mix subqueries in FROM clause and subqueries in WHERE -INSERT INTO agg_events - (user_id) -SELECT f2.id FROM -(SELECT - id -FROM (SELECT reference_table.user_id AS id - FROM raw_events_first, - reference_table - WHERE raw_events_first.user_id = reference_table.user_id ) AS foo) as f -INNER JOIN -(SELECT v4, - v1, - id -FROM (SELECT SUM(raw_events_second.value_4) AS v4, - SUM(raw_events_first.value_1) AS v1, - raw_events_second.user_id AS id - FROM raw_events_first, - raw_events_second - WHERE raw_events_first.user_id = raw_events_second.user_id - GROUP BY raw_events_second.user_id - HAVING SUM(raw_events_second.value_4) > 1000) AS foo2 ) as f2 -ON (f.id = f2.id) -WHERE f.id IN (SELECT user_id - FROM raw_events_second); -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300008 AS citus_table_alias (user_id) SELECT f2.id FROM ((SELECT foo.id FROM (SELECT reference_table.user_id AS id FROM multi_insert_select.raw_events_first_13300000 raw_events_first, multi_insert_select.reference_table_13300012 reference_table WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) reference_table.user_id)) foo) f JOIN (SELECT foo2.v4, foo2.v1, foo2.id FROM (SELECT sum(raw_events_second.value_4) AS v4, sum(raw_events_first.value_1) AS v1, raw_events_second.user_id AS id FROM multi_insert_select.raw_events_first_13300000 raw_events_first, multi_insert_select.raw_events_second_13300004 raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.user_id HAVING (sum(raw_events_second.value_4) OPERATOR(pg_catalog.>) (1000)::numeric)) foo2) f2 ON ((f.id OPERATOR(pg_catalog.=) f2.id))) WHERE ((f.id OPERATOR(pg_catalog.=) ANY (SELECT raw_events_second.user_id FROM multi_insert_select.raw_events_second_13300004 raw_events_second)) AND (f2.id IS NOT NULL)) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300009 AS citus_table_alias (user_id) SELECT f2.id FROM ((SELECT foo.id FROM (SELECT reference_table.user_id AS id FROM multi_insert_select.raw_events_first_13300001 raw_events_first, multi_insert_select.reference_table_13300012 reference_table WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) reference_table.user_id)) foo) f JOIN (SELECT foo2.v4, foo2.v1, foo2.id FROM (SELECT sum(raw_events_second.value_4) AS v4, sum(raw_events_first.value_1) AS v1, raw_events_second.user_id AS id FROM multi_insert_select.raw_events_first_13300001 raw_events_first, multi_insert_select.raw_events_second_13300005 raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.user_id HAVING (sum(raw_events_second.value_4) OPERATOR(pg_catalog.>) (1000)::numeric)) foo2) f2 ON ((f.id OPERATOR(pg_catalog.=) f2.id))) WHERE ((f.id OPERATOR(pg_catalog.=) ANY (SELECT raw_events_second.user_id FROM multi_insert_select.raw_events_second_13300005 raw_events_second)) AND (f2.id IS NOT NULL)) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300010 AS citus_table_alias (user_id) SELECT f2.id FROM ((SELECT foo.id FROM (SELECT reference_table.user_id AS id FROM multi_insert_select.raw_events_first_13300002 raw_events_first, multi_insert_select.reference_table_13300012 reference_table WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) reference_table.user_id)) foo) f JOIN (SELECT foo2.v4, foo2.v1, foo2.id FROM (SELECT sum(raw_events_second.value_4) AS v4, sum(raw_events_first.value_1) AS v1, raw_events_second.user_id AS id FROM multi_insert_select.raw_events_first_13300002 raw_events_first, multi_insert_select.raw_events_second_13300006 raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.user_id HAVING (sum(raw_events_second.value_4) OPERATOR(pg_catalog.>) (1000)::numeric)) foo2) f2 ON ((f.id OPERATOR(pg_catalog.=) f2.id))) WHERE ((f.id OPERATOR(pg_catalog.=) ANY (SELECT raw_events_second.user_id FROM multi_insert_select.raw_events_second_13300006 raw_events_second)) AND (f2.id IS NOT NULL)) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300011 AS citus_table_alias (user_id) SELECT f2.id FROM ((SELECT foo.id FROM (SELECT reference_table.user_id AS id FROM multi_insert_select.raw_events_first_13300003 raw_events_first, multi_insert_select.reference_table_13300012 reference_table WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) reference_table.user_id)) foo) f JOIN (SELECT foo2.v4, foo2.v1, foo2.id FROM (SELECT sum(raw_events_second.value_4) AS v4, sum(raw_events_first.value_1) AS v1, raw_events_second.user_id AS id FROM multi_insert_select.raw_events_first_13300003 raw_events_first, multi_insert_select.raw_events_second_13300007 raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.user_id HAVING (sum(raw_events_second.value_4) OPERATOR(pg_catalog.>) (1000)::numeric)) foo2) f2 ON ((f.id OPERATOR(pg_catalog.=) f2.id))) WHERE ((f.id OPERATOR(pg_catalog.=) ANY (SELECT raw_events_second.user_id FROM multi_insert_select.raw_events_second_13300007 raw_events_second)) AND (f2.id IS NOT NULL)) --- some UPSERTS -INSERT INTO agg_events AS ae - ( - user_id, - value_1_agg, - agg_time - ) -SELECT user_id, - value_1, - time -FROM raw_events_first -ON conflict (user_id, value_1_agg) -DO UPDATE - SET agg_time = EXCLUDED.agg_time - WHERE ae.agg_time < EXCLUDED.agg_time; -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300008 AS ae (user_id, value_1_agg, agg_time) SELECT user_id, value_1, "time" FROM multi_insert_select.raw_events_first_13300000 raw_events_first WHERE (user_id IS NOT NULL) ON CONFLICT(user_id, value_1_agg) DO UPDATE SET agg_time = excluded.agg_time WHERE (ae.agg_time OPERATOR(pg_catalog.<) excluded.agg_time) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300009 AS ae (user_id, value_1_agg, agg_time) SELECT user_id, value_1, "time" FROM multi_insert_select.raw_events_first_13300001 raw_events_first WHERE (user_id IS NOT NULL) ON CONFLICT(user_id, value_1_agg) DO UPDATE SET agg_time = excluded.agg_time WHERE (ae.agg_time OPERATOR(pg_catalog.<) excluded.agg_time) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300010 AS ae (user_id, value_1_agg, agg_time) SELECT user_id, value_1, "time" FROM multi_insert_select.raw_events_first_13300002 raw_events_first WHERE (user_id IS NOT NULL) ON CONFLICT(user_id, value_1_agg) DO UPDATE SET agg_time = excluded.agg_time WHERE (ae.agg_time OPERATOR(pg_catalog.<) excluded.agg_time) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300011 AS ae (user_id, value_1_agg, agg_time) SELECT user_id, value_1, "time" FROM multi_insert_select.raw_events_first_13300003 raw_events_first WHERE (user_id IS NOT NULL) ON CONFLICT(user_id, value_1_agg) DO UPDATE SET agg_time = excluded.agg_time WHERE (ae.agg_time OPERATOR(pg_catalog.<) excluded.agg_time) --- upserts with returning -INSERT INTO agg_events AS ae - ( - user_id, - value_1_agg, - agg_time - ) -SELECT user_id, - value_1, - time -FROM raw_events_first -ON conflict (user_id, value_1_agg) -DO UPDATE - SET agg_time = EXCLUDED.agg_time - WHERE ae.agg_time < EXCLUDED.agg_time -RETURNING user_id, value_1_agg; -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300008 AS ae (user_id, value_1_agg, agg_time) SELECT user_id, value_1, "time" FROM multi_insert_select.raw_events_first_13300000 raw_events_first WHERE (user_id IS NOT NULL) ON CONFLICT(user_id, value_1_agg) DO UPDATE SET agg_time = excluded.agg_time WHERE (ae.agg_time OPERATOR(pg_catalog.<) excluded.agg_time) RETURNING ae.user_id, ae.value_1_agg -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300009 AS ae (user_id, value_1_agg, agg_time) SELECT user_id, value_1, "time" FROM multi_insert_select.raw_events_first_13300001 raw_events_first WHERE (user_id IS NOT NULL) ON CONFLICT(user_id, value_1_agg) DO UPDATE SET agg_time = excluded.agg_time WHERE (ae.agg_time OPERATOR(pg_catalog.<) excluded.agg_time) RETURNING ae.user_id, ae.value_1_agg -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300010 AS ae (user_id, value_1_agg, agg_time) SELECT user_id, value_1, "time" FROM multi_insert_select.raw_events_first_13300002 raw_events_first WHERE (user_id IS NOT NULL) ON CONFLICT(user_id, value_1_agg) DO UPDATE SET agg_time = excluded.agg_time WHERE (ae.agg_time OPERATOR(pg_catalog.<) excluded.agg_time) RETURNING ae.user_id, ae.value_1_agg -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300011 AS ae (user_id, value_1_agg, agg_time) SELECT user_id, value_1, "time" FROM multi_insert_select.raw_events_first_13300003 raw_events_first WHERE (user_id IS NOT NULL) ON CONFLICT(user_id, value_1_agg) DO UPDATE SET agg_time = excluded.agg_time WHERE (ae.agg_time OPERATOR(pg_catalog.<) excluded.agg_time) RETURNING ae.user_id, ae.value_1_agg - user_id | value_1_agg ---------------------------------------------------------------------- - 7 | -(1 row) - -INSERT INTO agg_events (user_id, value_1_agg) -SELECT - user_id, sum(value_1 + value_2) -FROM - raw_events_first GROUP BY user_id; -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300008 AS citus_table_alias (user_id, value_1_agg) SELECT user_id, sum((value_1 OPERATOR(pg_catalog.+) value_2)) AS sum FROM multi_insert_select.raw_events_first_13300000 raw_events_first WHERE (user_id IS NOT NULL) GROUP BY user_id -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300009 AS citus_table_alias (user_id, value_1_agg) SELECT user_id, sum((value_1 OPERATOR(pg_catalog.+) value_2)) AS sum FROM multi_insert_select.raw_events_first_13300001 raw_events_first WHERE (user_id IS NOT NULL) GROUP BY user_id -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300010 AS citus_table_alias (user_id, value_1_agg) SELECT user_id, sum((value_1 OPERATOR(pg_catalog.+) value_2)) AS sum FROM multi_insert_select.raw_events_first_13300002 raw_events_first WHERE (user_id IS NOT NULL) GROUP BY user_id -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300011 AS citus_table_alias (user_id, value_1_agg) SELECT user_id, sum((value_1 OPERATOR(pg_catalog.+) value_2)) AS sum FROM multi_insert_select.raw_events_first_13300003 raw_events_first WHERE (user_id IS NOT NULL) GROUP BY user_id --- FILTER CLAUSE -INSERT INTO agg_events (user_id, value_1_agg) -SELECT - user_id, sum(value_1 + value_2) FILTER (where value_3 = 15) -FROM - raw_events_first GROUP BY user_id; -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300008 AS citus_table_alias (user_id, value_1_agg) SELECT user_id, sum((value_1 OPERATOR(pg_catalog.+) value_2)) FILTER (WHERE (value_3 OPERATOR(pg_catalog.=) (15)::double precision)) AS sum FROM multi_insert_select.raw_events_first_13300000 raw_events_first WHERE (user_id IS NOT NULL) GROUP BY user_id -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300009 AS citus_table_alias (user_id, value_1_agg) SELECT user_id, sum((value_1 OPERATOR(pg_catalog.+) value_2)) FILTER (WHERE (value_3 OPERATOR(pg_catalog.=) (15)::double precision)) AS sum FROM multi_insert_select.raw_events_first_13300001 raw_events_first WHERE (user_id IS NOT NULL) GROUP BY user_id -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300010 AS citus_table_alias (user_id, value_1_agg) SELECT user_id, sum((value_1 OPERATOR(pg_catalog.+) value_2)) FILTER (WHERE (value_3 OPERATOR(pg_catalog.=) (15)::double precision)) AS sum FROM multi_insert_select.raw_events_first_13300002 raw_events_first WHERE (user_id IS NOT NULL) GROUP BY user_id -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300011 AS citus_table_alias (user_id, value_1_agg) SELECT user_id, sum((value_1 OPERATOR(pg_catalog.+) value_2)) FILTER (WHERE (value_3 OPERATOR(pg_catalog.=) (15)::double precision)) AS sum FROM multi_insert_select.raw_events_first_13300003 raw_events_first WHERE (user_id IS NOT NULL) GROUP BY user_id --- a test with reference table JOINs -INSERT INTO - agg_events (user_id, value_1_agg) -SELECT - raw_events_first.user_id, sum(value_1) -FROM - reference_table, raw_events_first -WHERE - raw_events_first.user_id = reference_table.user_id -GROUP BY - raw_events_first.user_id; -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300008 AS citus_table_alias (user_id, value_1_agg) SELECT raw_events_first.user_id, sum(raw_events_first.value_1) AS sum FROM multi_insert_select.reference_table_13300012 reference_table, multi_insert_select.raw_events_first_13300000 raw_events_first WHERE ((raw_events_first.user_id OPERATOR(pg_catalog.=) reference_table.user_id) AND (raw_events_first.user_id IS NOT NULL)) GROUP BY raw_events_first.user_id -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300009 AS citus_table_alias (user_id, value_1_agg) SELECT raw_events_first.user_id, sum(raw_events_first.value_1) AS sum FROM multi_insert_select.reference_table_13300012 reference_table, multi_insert_select.raw_events_first_13300001 raw_events_first WHERE ((raw_events_first.user_id OPERATOR(pg_catalog.=) reference_table.user_id) AND (raw_events_first.user_id IS NOT NULL)) GROUP BY raw_events_first.user_id -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300010 AS citus_table_alias (user_id, value_1_agg) SELECT raw_events_first.user_id, sum(raw_events_first.value_1) AS sum FROM multi_insert_select.reference_table_13300012 reference_table, multi_insert_select.raw_events_first_13300002 raw_events_first WHERE ((raw_events_first.user_id OPERATOR(pg_catalog.=) reference_table.user_id) AND (raw_events_first.user_id IS NOT NULL)) GROUP BY raw_events_first.user_id -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300011 AS citus_table_alias (user_id, value_1_agg) SELECT raw_events_first.user_id, sum(raw_events_first.value_1) AS sum FROM multi_insert_select.reference_table_13300012 reference_table, multi_insert_select.raw_events_first_13300003 raw_events_first WHERE ((raw_events_first.user_id OPERATOR(pg_catalog.=) reference_table.user_id) AND (raw_events_first.user_id IS NOT NULL)) GROUP BY raw_events_first.user_id --- a note on the outer joins is that --- we filter out outer join results --- where partition column returns --- NULL. Thus, we could INSERT less rows --- than we expect from subquery result. --- see the following tests -SET client_min_messages TO INFO; --- we don't want to see constraint violations, so truncate first -TRUNCATE agg_events; --- add a row to first table to make table contents different -INSERT INTO raw_events_second (user_id, time, value_1, value_2, value_3, value_4) VALUES - (10, now(), 100, 10000, 10000, 100000); -DELETE FROM raw_events_second WHERE user_id = 2; --- we select 11 rows -SELECT t1.user_id AS col1, - t2.user_id AS col2 - FROM raw_events_first t1 - FULL JOIN raw_events_second t2 - ON t1.user_id = t2.user_id - ORDER BY t1.user_id, - t2.user_id; - col1 | col2 ---------------------------------------------------------------------- - 1 | 1 - 2 | - 3 | 3 - 4 | 4 - 5 | 5 - 6 | 6 - 7 | 7 - 8 | 8 - 9 | 9 - | 10 -(10 rows) - -SET client_min_messages TO DEBUG2; --- we insert 10 rows since we filtered out --- NULL partition column values -INSERT INTO agg_events (user_id, value_1_agg) -SELECT t1.user_id AS col1, - t2.user_id AS col2 -FROM raw_events_first t1 - FULL JOIN raw_events_second t2 - ON t1.user_id = t2.user_id; -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300008 AS citus_table_alias (user_id, value_1_agg) SELECT t1.user_id AS col1, t2.user_id AS col2 FROM (multi_insert_select.raw_events_first_13300000 t1 FULL JOIN multi_insert_select.raw_events_second_13300004 t2 ON ((t1.user_id OPERATOR(pg_catalog.=) t2.user_id))) WHERE (t1.user_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300009 AS citus_table_alias (user_id, value_1_agg) SELECT t1.user_id AS col1, t2.user_id AS col2 FROM (multi_insert_select.raw_events_first_13300001 t1 FULL JOIN multi_insert_select.raw_events_second_13300005 t2 ON ((t1.user_id OPERATOR(pg_catalog.=) t2.user_id))) WHERE (t1.user_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300010 AS citus_table_alias (user_id, value_1_agg) SELECT t1.user_id AS col1, t2.user_id AS col2 FROM (multi_insert_select.raw_events_first_13300002 t1 FULL JOIN multi_insert_select.raw_events_second_13300006 t2 ON ((t1.user_id OPERATOR(pg_catalog.=) t2.user_id))) WHERE (t1.user_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300011 AS citus_table_alias (user_id, value_1_agg) SELECT t1.user_id AS col1, t2.user_id AS col2 FROM (multi_insert_select.raw_events_first_13300003 t1 FULL JOIN multi_insert_select.raw_events_second_13300007 t2 ON ((t1.user_id OPERATOR(pg_catalog.=) t2.user_id))) WHERE (t1.user_id IS NOT NULL) -SET client_min_messages TO INFO; --- see that the results are different from the SELECT query -SELECT - user_id, value_1_agg -FROM - agg_events -ORDER BY - user_id, value_1_agg; - user_id | value_1_agg ---------------------------------------------------------------------- - 1 | 1 - 2 | - 3 | 3 - 4 | 4 - 5 | 5 - 6 | 6 - 7 | 7 - 8 | 8 - 9 | 9 -(9 rows) - --- we don't want to see constraint violations, so truncate first -SET client_min_messages TO INFO; -TRUNCATE agg_events; -SET client_min_messages TO DEBUG2; --- DISTINCT clause -INSERT INTO agg_events (value_1_agg, user_id) - SELECT - DISTINCT value_1, user_id - FROM - raw_events_first; -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300008 AS citus_table_alias (user_id, value_1_agg) SELECT DISTINCT user_id, value_1 FROM multi_insert_select.raw_events_first_13300000 raw_events_first WHERE (user_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300009 AS citus_table_alias (user_id, value_1_agg) SELECT DISTINCT user_id, value_1 FROM multi_insert_select.raw_events_first_13300001 raw_events_first WHERE (user_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300010 AS citus_table_alias (user_id, value_1_agg) SELECT DISTINCT user_id, value_1 FROM multi_insert_select.raw_events_first_13300002 raw_events_first WHERE (user_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300011 AS citus_table_alias (user_id, value_1_agg) SELECT DISTINCT user_id, value_1 FROM multi_insert_select.raw_events_first_13300003 raw_events_first WHERE (user_id IS NOT NULL) --- we don't want to see constraint violations, so truncate first -SET client_min_messages TO INFO; -truncate agg_events; -SET client_min_messages TO DEBUG2; --- DISTINCT ON clauses are supported --- distinct on(non-partition column) --- values are pulled to master -INSERT INTO agg_events (value_1_agg, user_id) - SELECT - DISTINCT ON (value_1) value_1, user_id - FROM - raw_events_first; -DEBUG: cannot push down this subquery -DETAIL: Distinct on columns without partition column is currently unsupported -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Collecting INSERT ... SELECT results on coordinator -SELECT user_id, value_1_agg FROM agg_events ORDER BY 1,2; -DEBUG: Router planner cannot handle multi-shard select queries - user_id | value_1_agg ---------------------------------------------------------------------- - 1 | 10 - 2 | 20 - 3 | 30 - 4 | 40 - 5 | 50 - 6 | 60 - 7 | - 8 | 80 - 9 | 90 -(9 rows) - --- we don't want to see constraint violations, so truncate first -SET client_min_messages TO INFO; -truncate agg_events; -SET client_min_messages TO DEBUG2; --- distinct on(partition column) --- queries are forwared to workers -INSERT INTO agg_events (value_1_agg, user_id) - SELECT - DISTINCT ON (user_id) value_1, user_id - FROM - raw_events_first; -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300008 AS citus_table_alias (user_id, value_1_agg) SELECT DISTINCT ON (user_id) user_id, value_1 FROM multi_insert_select.raw_events_first_13300000 raw_events_first WHERE (user_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300009 AS citus_table_alias (user_id, value_1_agg) SELECT DISTINCT ON (user_id) user_id, value_1 FROM multi_insert_select.raw_events_first_13300001 raw_events_first WHERE (user_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300010 AS citus_table_alias (user_id, value_1_agg) SELECT DISTINCT ON (user_id) user_id, value_1 FROM multi_insert_select.raw_events_first_13300002 raw_events_first WHERE (user_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300011 AS citus_table_alias (user_id, value_1_agg) SELECT DISTINCT ON (user_id) user_id, value_1 FROM multi_insert_select.raw_events_first_13300003 raw_events_first WHERE (user_id IS NOT NULL) -SELECT user_id, value_1_agg FROM agg_events ORDER BY 1,2; -DEBUG: Router planner cannot handle multi-shard select queries - user_id | value_1_agg ---------------------------------------------------------------------- - 1 | 10 - 2 | 20 - 3 | 30 - 4 | 40 - 5 | 50 - 6 | 60 - 7 | - 8 | 80 - 9 | 90 -(9 rows) - --- We support CTEs -BEGIN; -WITH fist_table_agg AS MATERIALIZED - (SELECT max(value_1)+1 as v1_agg, user_id FROM raw_events_first GROUP BY user_id) -INSERT INTO agg_events - (value_1_agg, user_id) - SELECT - v1_agg, user_id - FROM - fist_table_agg; -DEBUG: distributed INSERT ... SELECT can only select from distributed tables -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for CTE fist_table_agg: SELECT (max(value_1) OPERATOR(pg_catalog.+) 1) AS v1_agg, user_id FROM multi_insert_select.raw_events_first GROUP BY user_id -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT user_id, v1_agg AS value_1_agg FROM (SELECT fist_table_agg.user_id, fist_table_agg.v1_agg FROM (SELECT intermediate_result.v1_agg, intermediate_result.user_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(v1_agg integer, user_id integer)) fist_table_agg) citus_insert_select_subquery -DEBUG: Creating router plan -DEBUG: Collecting INSERT ... SELECT results on coordinator -ROLLBACK; --- We do support CTEs that are referenced in the target list -INSERT INTO agg_events - WITH sub_cte AS (SELECT 1) - SELECT - raw_events_first.user_id, (SELECT * FROM sub_cte) - FROM - raw_events_first; -DEBUG: CTE sub_cte is going to be inlined via distributed planning -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300008 AS citus_table_alias (user_id, value_1_agg) SELECT user_id, (SELECT sub_cte."?column?" FROM (SELECT 1) sub_cte("?column?")) FROM multi_insert_select.raw_events_first_13300000 raw_events_first WHERE (user_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300009 AS citus_table_alias (user_id, value_1_agg) SELECT user_id, (SELECT sub_cte."?column?" FROM (SELECT 1) sub_cte("?column?")) FROM multi_insert_select.raw_events_first_13300001 raw_events_first WHERE (user_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300010 AS citus_table_alias (user_id, value_1_agg) SELECT user_id, (SELECT sub_cte."?column?" FROM (SELECT 1) sub_cte("?column?")) FROM multi_insert_select.raw_events_first_13300002 raw_events_first WHERE (user_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300011 AS citus_table_alias (user_id, value_1_agg) SELECT user_id, (SELECT sub_cte."?column?" FROM (SELECT 1) sub_cte("?column?")) FROM multi_insert_select.raw_events_first_13300003 raw_events_first WHERE (user_id IS NOT NULL) --- We support set operations -BEGIN; -INSERT INTO - raw_events_first(user_id) -SELECT - user_id -FROM - ((SELECT user_id FROM raw_events_first) UNION - (SELECT user_id FROM raw_events_second)) as foo; -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_first_13300000 AS citus_table_alias (user_id) SELECT user_id FROM (SELECT raw_events_first.user_id FROM multi_insert_select.raw_events_first_13300000 raw_events_first UNION SELECT raw_events_second.user_id FROM multi_insert_select.raw_events_second_13300004 raw_events_second) foo WHERE (user_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_first_13300001 AS citus_table_alias (user_id) SELECT user_id FROM (SELECT raw_events_first.user_id FROM multi_insert_select.raw_events_first_13300001 raw_events_first UNION SELECT raw_events_second.user_id FROM multi_insert_select.raw_events_second_13300005 raw_events_second) foo WHERE (user_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_first_13300002 AS citus_table_alias (user_id) SELECT user_id FROM (SELECT raw_events_first.user_id FROM multi_insert_select.raw_events_first_13300002 raw_events_first UNION SELECT raw_events_second.user_id FROM multi_insert_select.raw_events_second_13300006 raw_events_second) foo WHERE (user_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_first_13300003 AS citus_table_alias (user_id) SELECT user_id FROM (SELECT raw_events_first.user_id FROM multi_insert_select.raw_events_first_13300003 raw_events_first UNION SELECT raw_events_second.user_id FROM multi_insert_select.raw_events_second_13300007 raw_events_second) foo WHERE (user_id IS NOT NULL) -ROLLBACK; --- We do support set operations through recursive planning -BEGIN; -SET LOCAL client_min_messages TO DEBUG; -INSERT INTO - raw_events_first(user_id) - (SELECT user_id FROM raw_events_first) INTERSECT - (SELECT user_id FROM raw_events_first); -DEBUG: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for subquery SELECT user_id FROM multi_insert_select.raw_events_first -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_2 for subquery SELECT user_id FROM multi_insert_select.raw_events_first -DEBUG: Creating router plan -DEBUG: generating subplan XXX_3 for subquery SELECT intermediate_result.user_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(user_id integer) INTERSECT SELECT intermediate_result.user_id FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(user_id integer) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT user_id FROM (SELECT intermediate_result.user_id FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(user_id integer)) citus_insert_select_subquery -DEBUG: Creating router plan -DEBUG: Collecting INSERT ... SELECT results on coordinator -ROLLBACK; --- If the query is router plannable then it is executed via the coordinator -INSERT INTO - raw_events_first(user_id) -SELECT - user_id -FROM - ((SELECT user_id FROM raw_events_first WHERE user_id = 15) EXCEPT - (SELECT user_id FROM raw_events_second where user_id = 17)) as foo; -DEBUG: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns -DEBUG: router planner does not support queries that reference non-colocated distributed tables -DEBUG: Distributed planning for a fast-path router query -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 15 -DEBUG: generating subplan XXX_1 for subquery SELECT user_id FROM multi_insert_select.raw_events_first WHERE (user_id OPERATOR(pg_catalog.=) 15) -DEBUG: Distributed planning for a fast-path router query -DEBUG: Creating router plan -DEBUG: query has a single distribution column value: 17 -DEBUG: generating subplan XXX_2 for subquery SELECT user_id FROM multi_insert_select.raw_events_second WHERE (user_id OPERATOR(pg_catalog.=) 17) -DEBUG: Creating router plan -DEBUG: generating subplan XXX_3 for subquery SELECT intermediate_result.user_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(user_id integer) EXCEPT SELECT intermediate_result.user_id FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(user_id integer) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT user_id FROM (SELECT intermediate_result.user_id FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(user_id integer)) foo -DEBUG: Creating router plan -DEBUG: Collecting INSERT ... SELECT results on coordinator --- some supported LEFT joins - INSERT INTO agg_events (user_id) - SELECT - raw_events_first.user_id - FROM - raw_events_first LEFT JOIN raw_events_second ON raw_events_first.user_id = raw_events_second.user_id; -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300008 AS citus_table_alias (user_id) SELECT raw_events_first.user_id FROM (multi_insert_select.raw_events_first_13300000 raw_events_first LEFT JOIN multi_insert_select.raw_events_second_13300004 raw_events_second ON ((raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id))) WHERE (raw_events_first.user_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300009 AS citus_table_alias (user_id) SELECT raw_events_first.user_id FROM (multi_insert_select.raw_events_first_13300001 raw_events_first LEFT JOIN multi_insert_select.raw_events_second_13300005 raw_events_second ON ((raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id))) WHERE (raw_events_first.user_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300010 AS citus_table_alias (user_id) SELECT raw_events_first.user_id FROM (multi_insert_select.raw_events_first_13300002 raw_events_first LEFT JOIN multi_insert_select.raw_events_second_13300006 raw_events_second ON ((raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id))) WHERE (raw_events_first.user_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300011 AS citus_table_alias (user_id) SELECT raw_events_first.user_id FROM (multi_insert_select.raw_events_first_13300003 raw_events_first LEFT JOIN multi_insert_select.raw_events_second_13300007 raw_events_second ON ((raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id))) WHERE (raw_events_first.user_id IS NOT NULL) - INSERT INTO agg_events (user_id) - SELECT - raw_events_second.user_id - FROM - reference_table LEFT JOIN raw_events_second ON reference_table.user_id = raw_events_second.user_id; -DEBUG: cannot perform a lateral outer join when a distributed subquery references a reference table -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: recursively planning right side of the left join since the outer side is a recurring rel -DEBUG: recursively planning distributed relation "raw_events_second" since it is part of a distributed join node that is outer joined with a recurring rel -DEBUG: Wrapping relation "raw_events_second" to a subquery -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: generating subplan XXX_1 for subquery SELECT user_id FROM multi_insert_select.raw_events_second WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT raw_events_second.user_id FROM (multi_insert_select.reference_table LEFT JOIN (SELECT raw_events_second_1.user_id, NULL::timestamp without time zone AS "time", NULL::integer AS value_1, NULL::integer AS value_2, NULL::double precision AS value_3, NULL::bigint AS value_4 FROM (SELECT intermediate_result.user_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(user_id integer)) raw_events_second_1) raw_events_second ON ((reference_table.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id))) -DEBUG: Creating router plan -DEBUG: Collecting INSERT ... SELECT results on coordinator - INSERT INTO agg_events (user_id) - SELECT - raw_events_first.user_id - FROM - raw_events_first LEFT JOIN raw_events_second ON raw_events_first.user_id = raw_events_second.user_id - WHERE raw_events_first.user_id = 10; -DEBUG: Creating router plan -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300008 AS citus_table_alias (user_id) SELECT raw_events_first.user_id FROM (multi_insert_select.raw_events_first_13300000 raw_events_first LEFT JOIN multi_insert_select.raw_events_second_13300004 raw_events_second ON ((raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id))) WHERE ((raw_events_first.user_id OPERATOR(pg_catalog.=) 10) AND (raw_events_first.user_id IS NOT NULL)) -DEBUG: Skipping target shard interval 13300009 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300010 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300011 since SELECT query for it pruned away - INSERT INTO agg_events (user_id) - SELECT - raw_events_first.user_id - FROM - raw_events_first LEFT JOIN raw_events_second ON raw_events_first.user_id = raw_events_second.user_id - WHERE raw_events_second.user_id = 10 OR raw_events_second.user_id = 11; -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300008 AS citus_table_alias (user_id) SELECT raw_events_first.user_id FROM (multi_insert_select.raw_events_first_13300000 raw_events_first LEFT JOIN multi_insert_select.raw_events_second_13300004 raw_events_second ON ((raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id))) WHERE (((raw_events_second.user_id OPERATOR(pg_catalog.=) 10) OR (raw_events_second.user_id OPERATOR(pg_catalog.=) 11)) AND (raw_events_first.user_id IS NOT NULL)) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300009 AS citus_table_alias (user_id) SELECT raw_events_first.user_id FROM (multi_insert_select.raw_events_first_13300001 raw_events_first LEFT JOIN (SELECT NULL::integer AS user_id, NULL::timestamp without time zone AS "time", NULL::integer AS value_1, NULL::integer AS value_2, NULL::double precision AS value_3, NULL::bigint AS value_4 WHERE false) raw_events_second(user_id, "time", value_1, value_2, value_3, value_4) ON ((raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id))) WHERE (((raw_events_second.user_id OPERATOR(pg_catalog.=) 10) OR (raw_events_second.user_id OPERATOR(pg_catalog.=) 11)) AND (raw_events_first.user_id IS NOT NULL)) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300010 AS citus_table_alias (user_id) SELECT raw_events_first.user_id FROM (multi_insert_select.raw_events_first_13300002 raw_events_first LEFT JOIN (SELECT NULL::integer AS user_id, NULL::timestamp without time zone AS "time", NULL::integer AS value_1, NULL::integer AS value_2, NULL::double precision AS value_3, NULL::bigint AS value_4 WHERE false) raw_events_second(user_id, "time", value_1, value_2, value_3, value_4) ON ((raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id))) WHERE (((raw_events_second.user_id OPERATOR(pg_catalog.=) 10) OR (raw_events_second.user_id OPERATOR(pg_catalog.=) 11)) AND (raw_events_first.user_id IS NOT NULL)) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300011 AS citus_table_alias (user_id) SELECT raw_events_first.user_id FROM (multi_insert_select.raw_events_first_13300003 raw_events_first LEFT JOIN multi_insert_select.raw_events_second_13300007 raw_events_second ON ((raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id))) WHERE (((raw_events_second.user_id OPERATOR(pg_catalog.=) 10) OR (raw_events_second.user_id OPERATOR(pg_catalog.=) 11)) AND (raw_events_first.user_id IS NOT NULL)) - INSERT INTO agg_events (user_id) - SELECT - raw_events_first.user_id - FROM - raw_events_first INNER JOIN raw_events_second ON raw_events_first.user_id = raw_events_second.user_id - WHERE raw_events_first.user_id = 10 AND raw_events_first.user_id = 20; -DEBUG: Creating router plan -DEBUG: Skipping target shard interval 13300008 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300009 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300010 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300011 since SELECT query for it pruned away - INSERT INTO agg_events (user_id) - SELECT - raw_events_first.user_id - FROM - raw_events_first LEFT JOIN raw_events_second ON raw_events_first.user_id = raw_events_second.user_id - WHERE raw_events_first.user_id = 10 AND raw_events_second.user_id = 20; -DEBUG: Creating router plan -DEBUG: Skipping target shard interval 13300008 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300009 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300010 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300011 since SELECT query for it pruned away - INSERT INTO agg_events (user_id) - SELECT - raw_events_first.user_id - FROM - raw_events_first LEFT JOIN raw_events_second ON raw_events_first.user_id = raw_events_second.user_id - WHERE raw_events_first.user_id IN (19, 20, 21); -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300008 AS citus_table_alias (user_id) SELECT raw_events_first.user_id FROM (multi_insert_select.raw_events_first_13300000 raw_events_first LEFT JOIN multi_insert_select.raw_events_second_13300004 raw_events_second ON ((raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id))) WHERE ((raw_events_first.user_id OPERATOR(pg_catalog.=) ANY (ARRAY[19, 20, 21])) AND (raw_events_first.user_id IS NOT NULL)) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300009 AS citus_table_alias (user_id) SELECT raw_events_first.user_id FROM (multi_insert_select.raw_events_first_13300001 raw_events_first LEFT JOIN multi_insert_select.raw_events_second_13300005 raw_events_second ON ((raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id))) WHERE ((raw_events_first.user_id OPERATOR(pg_catalog.=) ANY (ARRAY[19, 20, 21])) AND (raw_events_first.user_id IS NOT NULL)) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300010 AS citus_table_alias (user_id) SELECT raw_events_first.user_id FROM (multi_insert_select.raw_events_first_13300002 raw_events_first LEFT JOIN multi_insert_select.raw_events_second_13300006 raw_events_second ON ((raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id))) WHERE ((raw_events_first.user_id OPERATOR(pg_catalog.=) ANY (ARRAY[19, 20, 21])) AND (raw_events_first.user_id IS NOT NULL)) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300011 AS citus_table_alias (user_id) SELECT raw_events_first.user_id FROM ((SELECT NULL::integer AS user_id, NULL::timestamp without time zone AS "time", NULL::integer AS value_1, NULL::integer AS value_2, NULL::double precision AS value_3, NULL::bigint AS value_4 WHERE false) raw_events_first(user_id, "time", value_1, value_2, value_3, value_4) LEFT JOIN multi_insert_select.raw_events_second_13300007 raw_events_second ON ((raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id))) WHERE ((raw_events_first.user_id OPERATOR(pg_catalog.=) ANY (ARRAY[19, 20, 21])) AND (raw_events_first.user_id IS NOT NULL)) - INSERT INTO agg_events (user_id) - SELECT - raw_events_first.user_id - FROM - raw_events_first INNER JOIN raw_events_second ON raw_events_first.user_id = raw_events_second.user_id - WHERE raw_events_second.user_id IN (19, 20, 21); -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300008 AS citus_table_alias (user_id) SELECT raw_events_first.user_id FROM (multi_insert_select.raw_events_first_13300000 raw_events_first JOIN multi_insert_select.raw_events_second_13300004 raw_events_second ON ((raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id))) WHERE ((raw_events_second.user_id OPERATOR(pg_catalog.=) ANY (ARRAY[19, 20, 21])) AND (raw_events_first.user_id IS NOT NULL)) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300009 AS citus_table_alias (user_id) SELECT raw_events_first.user_id FROM (multi_insert_select.raw_events_first_13300001 raw_events_first JOIN multi_insert_select.raw_events_second_13300005 raw_events_second ON ((raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id))) WHERE ((raw_events_second.user_id OPERATOR(pg_catalog.=) ANY (ARRAY[19, 20, 21])) AND (raw_events_first.user_id IS NOT NULL)) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300010 AS citus_table_alias (user_id) SELECT raw_events_first.user_id FROM (multi_insert_select.raw_events_first_13300002 raw_events_first JOIN multi_insert_select.raw_events_second_13300006 raw_events_second ON ((raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id))) WHERE ((raw_events_second.user_id OPERATOR(pg_catalog.=) ANY (ARRAY[19, 20, 21])) AND (raw_events_first.user_id IS NOT NULL)) -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300011 AS citus_table_alias (user_id) SELECT raw_events_first.user_id FROM (multi_insert_select.raw_events_first_13300003 raw_events_first JOIN (SELECT NULL::integer AS user_id, NULL::timestamp without time zone AS "time", NULL::integer AS value_1, NULL::integer AS value_2, NULL::double precision AS value_3, NULL::bigint AS value_4 WHERE false) raw_events_second(user_id, "time", value_1, value_2, value_3, value_4) ON ((raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id))) WHERE ((raw_events_second.user_id OPERATOR(pg_catalog.=) ANY (ARRAY[19, 20, 21])) AND (raw_events_first.user_id IS NOT NULL)) -SET client_min_messages TO WARNING; - -- following query should use repartitioned joins and results should - -- be routed via coordinator - SET citus.enable_repartition_joins TO true; - INSERT INTO agg_events - (user_id) - SELECT raw_events_first.user_id - FROM raw_events_first, - raw_events_second - WHERE raw_events_second.user_id = raw_events_first.value_1 - AND raw_events_first.value_1 = 12; - -- some unsupported LEFT/INNER JOINs - -- JOIN on one table with partition column other is not - INSERT INTO agg_events (user_id) - SELECT - raw_events_first.user_id - FROM - raw_events_first LEFT JOIN raw_events_second ON raw_events_first.user_id = raw_events_second.value_1; -ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns - -- same as the above with INNER JOIN - INSERT INTO agg_events (user_id) - SELECT - raw_events_first.user_id - FROM - raw_events_first INNER JOIN raw_events_second ON raw_events_first.user_id = raw_events_second.value_1; - -- a not meaningful query - INSERT INTO agg_events - (user_id) - SELECT raw_events_second.user_id - FROM raw_events_first, - raw_events_second - WHERE raw_events_first.user_id = raw_events_first.value_1; -ERROR: cannot perform distributed planning on this query -DETAIL: Cartesian products are currently unsupported - -- both tables joined on non-partition columns - INSERT INTO agg_events (user_id) - SELECT - raw_events_first.user_id - FROM - raw_events_first LEFT JOIN raw_events_second ON raw_events_first.value_1 = raw_events_second.value_1; -ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns - -- same as the above with INNER JOIN - -- we support this with route to coordinator - SELECT coordinator_plan($Q$ - EXPLAIN (costs off) - INSERT INTO agg_events (user_id) - SELECT - raw_events_first.user_id - FROM - raw_events_first INNER JOIN raw_events_second ON raw_events_first.value_1 = raw_events_second.value_1; -$Q$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> Custom Scan (Citus Adaptive) - Task Count: 6 -(4 rows) - --- EXPLAIN ANALYZE is not supported for INSERT ... SELECT via coordinator -EXPLAIN (costs off, analyze on) - INSERT INTO agg_events (user_id) - SELECT - raw_events_first.user_id - FROM - raw_events_first INNER JOIN raw_events_second ON raw_events_first.value_1 = raw_events_second.value_1; -ERROR: EXPLAIN ANALYZE is currently not supported for INSERT ... SELECT commands via coordinator --- even if there is a filter on the partition key, since the join is not on the partition key we reject --- this query -INSERT INTO agg_events (user_id) -SELECT - raw_events_first.user_id -FROM - raw_events_first LEFT JOIN raw_events_second ON raw_events_first.user_id = raw_events_second.value_1 -WHERE - raw_events_first.user_id = 10; -ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns - -- same as the above with INNER JOIN - -- we support this with route to coordinator - SELECT coordinator_plan($Q$ - EXPLAIN (costs off) - INSERT INTO agg_events (user_id) - SELECT - raw_events_first.user_id - FROM - raw_events_first INNER JOIN raw_events_second ON raw_events_first.user_id = raw_events_second.value_1 - WHERE raw_events_first.user_id = 10; -$Q$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> Custom Scan (Citus Adaptive) - Task Count: 6 -(4 rows) - - -- make things a bit more complicate with IN clauses - -- we support this with route to coordinator - SELECT coordinator_plan($Q$ - EXPLAIN (costs off) - INSERT INTO agg_events (user_id) - SELECT - raw_events_first.user_id - FROM - raw_events_first INNER JOIN raw_events_second ON raw_events_first.user_id = raw_events_second.value_1 - WHERE raw_events_first.value_1 IN (10, 11,12) OR raw_events_second.user_id IN (1,2,3,4); -$Q$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> Custom Scan (Citus Adaptive) - Task Count: 6 -(4 rows) - - -- implicit join on non partition column should also not be pushed down, - -- so we fall back to route via coordinator - SELECT coordinator_plan($Q$ - EXPLAIN (costs off) - INSERT INTO agg_events - (user_id) - SELECT raw_events_first.user_id - FROM raw_events_first, - raw_events_second - WHERE raw_events_second.user_id = raw_events_first.value_1; -$Q$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> Custom Scan (Citus Adaptive) - Task Count: 6 -(4 rows) - -RESET client_min_messages; - -- The following is again a tricky query for Citus. If the given filter was - -- on value_1 as shown in the above, Citus could push it down and use - -- distributed INSERT/SELECT. But we instead fall back to route via coordinator. - SELECT coordinator_plan($Q$ - EXPLAIN (costs off) - INSERT INTO agg_events - (user_id) - SELECT raw_events_first.user_id - FROM raw_events_first, - raw_events_second - WHERE raw_events_second.user_id = raw_events_first.value_1 - AND raw_events_first.value_2 = 12; -$Q$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> Custom Scan (Citus Adaptive) - Task Count: 6 -(4 rows) - - -- foo is not joined on the partition key so the query is not - -- pushed down. So instead we route via coordinator. - SELECT coordinator_plan($Q$ - EXPLAIN (costs off) - INSERT INTO agg_events - (user_id, value_4_agg) - SELECT - outer_most.id, max(outer_most.value) - FROM - ( - SELECT f2.id as id, f2.v4 as value FROM - (SELECT - id - FROM (SELECT reference_table.user_id AS id - FROM raw_events_first LEFT JOIN - reference_table - ON (raw_events_first.value_1 = reference_table.user_id)) AS foo) as f - INNER JOIN - (SELECT v4, - v1, - id - FROM (SELECT SUM(raw_events_second.value_4) AS v4, - SUM(raw_events_first.value_1) AS v1, - raw_events_second.user_id AS id - FROM raw_events_first, - raw_events_second - WHERE raw_events_first.user_id = raw_events_second.user_id - GROUP BY raw_events_second.user_id - HAVING SUM(raw_events_second.value_4) > 10) AS foo2 ) as f2 - ON (f.id = f2.id)) as outer_most - GROUP BY - outer_most.id; -$Q$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> HashAggregate - Group Key: remote_scan.user_id - -> Custom Scan (Citus Adaptive) - -> Distributed Subplan XXX_1 - -> Custom Scan (Citus Adaptive) - Task Count: 4 -(8 rows) - - -- if the given filter was on value_1 as shown in the above, Citus could - -- push it down. But here the query falls back to route via coordinator. - SELECT coordinator_plan($Q$ - EXPLAIN (costs off) - INSERT INTO agg_events - (user_id) - SELECT raw_events_first.user_id - FROM raw_events_first, - raw_events_second - WHERE raw_events_second.user_id = raw_events_first.value_1 - AND raw_events_first.value_2 = 12; -$Q$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> Custom Scan (Citus Adaptive) - Task Count: 6 -(4 rows) - - -- foo is not joined on the partition key so the query is not - -- pushed down, and it falls back to route via coordinator -SELECT coordinator_plan($Q$ -EXPLAIN (costs off) - INSERT INTO agg_events - (user_id, value_4_agg) - SELECT - outer_most.id, max(outer_most.value) - FROM - ( - SELECT f2.id as id, f2.v4 as value FROM - (SELECT - id - FROM (SELECT reference_table.user_id AS id - FROM raw_events_first LEFT JOIN - reference_table - ON (raw_events_first.value_1 = reference_table.user_id)) AS foo) as f - INNER JOIN - (SELECT v4, - v1, - id - FROM (SELECT SUM(raw_events_second.value_4) AS v4, - SUM(raw_events_first.value_1) AS v1, - raw_events_second.user_id AS id - FROM raw_events_first, - raw_events_second - WHERE raw_events_first.user_id = raw_events_second.user_id - GROUP BY raw_events_second.user_id - HAVING SUM(raw_events_second.value_4) > 10) AS foo2 ) as f2 - ON (f.id = f2.id)) as outer_most - GROUP BY - outer_most.id; -$Q$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> HashAggregate - Group Key: remote_scan.user_id - -> Custom Scan (Citus Adaptive) - -> Distributed Subplan XXX_1 - -> Custom Scan (Citus Adaptive) - Task Count: 4 -(8 rows) - -INSERT INTO agg_events - (value_4_agg, - value_1_agg, - user_id) -SELECT v4, - v1, - id -FROM (SELECT SUM(raw_events_second.value_4) AS v4, - SUM(raw_events_first.value_1) AS v1, - raw_events_second.user_id AS id - FROM raw_events_first, - raw_events_second - WHERE raw_events_first.user_id != raw_events_second.user_id - GROUP BY raw_events_second.user_id) AS foo; -ERROR: complex joins are only supported when all distributed tables are joined on their distribution columns with equal operator -SET client_min_messages TO DEBUG2; --- INSERT returns NULL partition key value via coordinator -INSERT INTO agg_events - (value_4_agg, - value_1_agg, - user_id) -SELECT v4, - v1, - id -FROM (SELECT SUM(raw_events_second.value_4) AS v4, - SUM(raw_events_first.value_1) AS v1, - raw_events_second.value_3 AS id - FROM raw_events_first, - raw_events_second - WHERE raw_events_first.user_id = raw_events_second.user_id - GROUP BY raw_events_second.value_3) AS foo; -DEBUG: cannot push down this subquery -DETAIL: Group by list without partition column is currently unsupported when a subquery references a column from another query -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: join prunable for intervals [-2147483648,-1073741825] and [-1073741824,-1] -DEBUG: join prunable for intervals [-2147483648,-1073741825] and [0,1073741823] -DEBUG: join prunable for intervals [-2147483648,-1073741825] and [1073741824,2147483647] -DEBUG: join prunable for intervals [-1073741824,-1] and [-2147483648,-1073741825] -DEBUG: join prunable for intervals [-1073741824,-1] and [0,1073741823] -DEBUG: join prunable for intervals [-1073741824,-1] and [1073741824,2147483647] -DEBUG: join prunable for intervals [0,1073741823] and [-2147483648,-1073741825] -DEBUG: join prunable for intervals [0,1073741823] and [-1073741824,-1] -DEBUG: join prunable for intervals [0,1073741823] and [1073741824,2147483647] -DEBUG: join prunable for intervals [1073741824,2147483647] and [-2147483648,-1073741825] -DEBUG: join prunable for intervals [1073741824,2147483647] and [-1073741824,-1] -DEBUG: join prunable for intervals [1073741824,2147483647] and [0,1073741823] -DEBUG: generating subplan XXX_1 for subquery SELECT sum(raw_events_second.value_4) AS v4, sum(raw_events_first.value_1) AS v1, raw_events_second.value_3 AS id FROM multi_insert_select.raw_events_first, multi_insert_select.raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.value_3 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT int4(id) AS user_id, int4(v1) AS value_1_agg, int8(v4) AS value_4_agg FROM (SELECT intermediate_result.v4, intermediate_result.v1, intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(v4 numeric, v1 bigint, id double precision)) foo -DEBUG: Creating router plan -DEBUG: Collecting INSERT ... SELECT results on coordinator -ERROR: the partition column of table multi_insert_select.agg_events cannot be NULL --- error cases --- no part column at all -INSERT INTO raw_events_second - (value_1) -SELECT value_1 -FROM raw_events_first; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: the query doesn't include the target table's partition column -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -ERROR: the partition column of table multi_insert_select.raw_events_second should have a value -INSERT INTO raw_events_second - (value_1) -SELECT user_id -FROM raw_events_first; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: the query doesn't include the target table's partition column -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -ERROR: the partition column of table multi_insert_select.raw_events_second should have a value -INSERT INTO raw_events_second - (user_id) -SELECT value_1 -FROM raw_events_first; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: The target table's partition column should correspond to a partition column in the subquery. -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 0 with name 'user_id' -ERROR: the partition column value cannot be NULL -CONTEXT: while executing command on localhost:xxxxx -INSERT INTO raw_events_second - (user_id) -SELECT user_id * 2 -FROM raw_events_first; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: Subquery contains an operator in the same position as the target table's partition column. -HINT: Ensure the target table's partition column has a corresponding simple column reference to a distributed table's partition column in the subquery. -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 0 with name 'user_id' -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300004 AS citus_table_alias (user_id) SELECT user_id FROM read_intermediate_results('{repartitioned_results_xxxxx_from_13300000_to_0,repartitioned_results_xxxxx_from_13300001_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(user_id integer) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300005 AS citus_table_alias (user_id) SELECT user_id FROM read_intermediate_results('{repartitioned_results_xxxxx_from_13300000_to_1,repartitioned_results_xxxxx_from_13300001_to_1,repartitioned_results_xxxxx_from_13300003_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(user_id integer) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300006 AS citus_table_alias (user_id) SELECT user_id FROM read_intermediate_results('{repartitioned_results_xxxxx_from_13300001_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(user_id integer) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300007 AS citus_table_alias (user_id) SELECT user_id FROM read_intermediate_results('{repartitioned_results_xxxxx_from_13300000_to_3,repartitioned_results_xxxxx_from_13300002_to_3,repartitioned_results_xxxxx_from_13300003_to_3}'::text[], 'binary'::citus_copy_format) intermediate_result(user_id integer) -INSERT INTO raw_events_second - (user_id) -SELECT user_id :: bigint -FROM raw_events_first; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: Subquery contains an explicit cast in the same position as the target table's partition column. -HINT: Ensure the target table's partition column has a corresponding simple column reference to a distributed table's partition column in the subquery. -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 0 with name 'user_id' -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300004 AS citus_table_alias (user_id) SELECT user_id FROM read_intermediate_results('{repartitioned_results_xxxxx_from_13300000_to_0}'::text[], 'binary'::citus_copy_format) intermediate_result(user_id integer) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300005 AS citus_table_alias (user_id) SELECT user_id FROM read_intermediate_results('{repartitioned_results_xxxxx_from_13300001_to_1}'::text[], 'binary'::citus_copy_format) intermediate_result(user_id integer) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300006 AS citus_table_alias (user_id) SELECT user_id FROM read_intermediate_results('{repartitioned_results_xxxxx_from_13300002_to_2}'::text[], 'binary'::citus_copy_format) intermediate_result(user_id integer) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300007 AS citus_table_alias (user_id) SELECT user_id FROM read_intermediate_results('{repartitioned_results_xxxxx_from_13300003_to_3}'::text[], 'binary'::citus_copy_format) intermediate_result(user_id integer) -INSERT INTO agg_events - (value_3_agg, - value_4_agg, - value_1_agg, - value_2_agg, - user_id) -SELECT SUM(value_3), - Count(value_4), - user_id, - SUM(value_1), - Avg(value_2) -FROM raw_events_first -GROUP BY user_id; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: Subquery contains an aggregation in the same position as the target table's partition column. -HINT: Ensure the target table's partition column has a corresponding simple column reference to a distributed table's partition column in the subquery. -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 0 with name 'user_id' -ERROR: the partition column value cannot be NULL -CONTEXT: while executing command on localhost:xxxxx -INSERT INTO agg_events - (value_3_agg, - value_4_agg, - value_1_agg, - value_2_agg, - user_id) -SELECT SUM(value_3), - Count(value_4), - user_id, - SUM(value_1), - value_2 -FROM raw_events_first -GROUP BY user_id, - value_2; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: The target table's partition column should correspond to a partition column in the subquery. -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 0 with name 'user_id' -ERROR: the partition column value cannot be NULL -CONTEXT: while executing command on localhost:xxxxx --- tables should be co-located -INSERT INTO agg_events (user_id) -SELECT - user_id -FROM - reference_table; -DEBUG: Creating router plan -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: The target table's partition column should correspond to a partition column in the subquery. -DEBUG: Distributed planning for a fast-path router query -DEBUG: Creating router plan -DEBUG: Collecting INSERT ... SELECT results on coordinator --- foo2 is recursively planned and INSERT...SELECT is done via coordinator -INSERT INTO agg_events - (user_id) -SELECT f2.id FROM -(SELECT - id -FROM (SELECT reference_table.user_id AS id - FROM raw_events_first, - reference_table - WHERE raw_events_first.user_id = reference_table.user_id ) AS foo) as f -INNER JOIN -(SELECT v4, - v1, - id -FROM (SELECT SUM(raw_events_second.value_4) AS v4, - raw_events_second.value_1 AS v1, - SUM(raw_events_second.user_id) AS id - FROM raw_events_first, - raw_events_second - WHERE raw_events_first.user_id = raw_events_second.user_id - GROUP BY raw_events_second.value_1 - HAVING SUM(raw_events_second.value_4) > 10) AS foo2 ) as f2 -ON (f.id = f2.id); -DEBUG: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: join prunable for intervals [-2147483648,-1073741825] and [-1073741824,-1] -DEBUG: join prunable for intervals [-2147483648,-1073741825] and [0,1073741823] -DEBUG: join prunable for intervals [-2147483648,-1073741825] and [1073741824,2147483647] -DEBUG: join prunable for intervals [-1073741824,-1] and [-2147483648,-1073741825] -DEBUG: join prunable for intervals [-1073741824,-1] and [0,1073741823] -DEBUG: join prunable for intervals [-1073741824,-1] and [1073741824,2147483647] -DEBUG: join prunable for intervals [0,1073741823] and [-2147483648,-1073741825] -DEBUG: join prunable for intervals [0,1073741823] and [-1073741824,-1] -DEBUG: join prunable for intervals [0,1073741823] and [1073741824,2147483647] -DEBUG: join prunable for intervals [1073741824,2147483647] and [-2147483648,-1073741825] -DEBUG: join prunable for intervals [1073741824,2147483647] and [-1073741824,-1] -DEBUG: join prunable for intervals [1073741824,2147483647] and [0,1073741823] -DEBUG: generating subplan XXX_1 for subquery SELECT sum(raw_events_second.value_4) AS v4, raw_events_second.value_1 AS v1, sum(raw_events_second.user_id) AS id FROM multi_insert_select.raw_events_first, multi_insert_select.raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.value_1 HAVING (sum(raw_events_second.value_4) OPERATOR(pg_catalog.>) (10)::numeric) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT int4(f2.id) AS user_id FROM ((SELECT foo.id FROM (SELECT reference_table.user_id AS id FROM multi_insert_select.raw_events_first, multi_insert_select.reference_table WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) reference_table.user_id)) foo) f JOIN (SELECT foo2.v4, foo2.v1, foo2.id FROM (SELECT intermediate_result.v4, intermediate_result.v1, intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(v4 numeric, v1 integer, id bigint)) foo2) f2 ON ((f.id OPERATOR(pg_catalog.=) f2.id))) -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 0 with name 'user_id' --- the second part of the query is not routable since --- GROUP BY not on the partition column (i.e., value_1) and thus join --- on f.id = f2.id is not on the partition key (instead on the sum of partition key) --- but we still recursively plan foo2 and run the query -INSERT INTO agg_events - (user_id) -SELECT f.id FROM -(SELECT - id -FROM (SELECT raw_events_first.user_id AS id - FROM raw_events_first, - reference_table - WHERE raw_events_first.user_id = reference_table.user_id ) AS foo) as f -INNER JOIN -(SELECT v4, - v1, - id -FROM (SELECT SUM(raw_events_second.value_4) AS v4, - raw_events_second.value_1 AS v1, - SUM(raw_events_second.user_id) AS id - FROM raw_events_first, - raw_events_second - WHERE raw_events_first.user_id = raw_events_second.user_id - GROUP BY raw_events_second.value_1 - HAVING SUM(raw_events_second.value_4) > 10) AS foo2 ) as f2 -ON (f.id = f2.id); -DEBUG: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: join prunable for intervals [-2147483648,-1073741825] and [-1073741824,-1] -DEBUG: join prunable for intervals [-2147483648,-1073741825] and [0,1073741823] -DEBUG: join prunable for intervals [-2147483648,-1073741825] and [1073741824,2147483647] -DEBUG: join prunable for intervals [-1073741824,-1] and [-2147483648,-1073741825] -DEBUG: join prunable for intervals [-1073741824,-1] and [0,1073741823] -DEBUG: join prunable for intervals [-1073741824,-1] and [1073741824,2147483647] -DEBUG: join prunable for intervals [0,1073741823] and [-2147483648,-1073741825] -DEBUG: join prunable for intervals [0,1073741823] and [-1073741824,-1] -DEBUG: join prunable for intervals [0,1073741823] and [1073741824,2147483647] -DEBUG: join prunable for intervals [1073741824,2147483647] and [-2147483648,-1073741825] -DEBUG: join prunable for intervals [1073741824,2147483647] and [-1073741824,-1] -DEBUG: join prunable for intervals [1073741824,2147483647] and [0,1073741823] -DEBUG: generating subplan XXX_1 for subquery SELECT sum(raw_events_second.value_4) AS v4, raw_events_second.value_1 AS v1, sum(raw_events_second.user_id) AS id FROM multi_insert_select.raw_events_first, multi_insert_select.raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.value_1 HAVING (sum(raw_events_second.value_4) OPERATOR(pg_catalog.>) (10)::numeric) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT f.id AS user_id FROM ((SELECT foo.id FROM (SELECT raw_events_first.user_id AS id FROM multi_insert_select.raw_events_first, multi_insert_select.reference_table WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) reference_table.user_id)) foo) f JOIN (SELECT foo2.v4, foo2.v1, foo2.id FROM (SELECT intermediate_result.v4, intermediate_result.v1, intermediate_result.id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(v4 numeric, v1 integer, id bigint)) foo2) f2 ON ((f.id OPERATOR(pg_catalog.=) f2.id))) -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 0 with name 'user_id' -SET client_min_messages TO WARNING; --- cannot pushdown the query since the JOIN is not equi JOIN --- falls back to route via coordinator -SELECT coordinator_plan($Q$ -EXPLAIN (costs off) -INSERT INTO agg_events - (user_id, value_4_agg) -SELECT -outer_most.id, max(outer_most.value) - FROM -( - SELECT f2.id as id, f2.v4 as value FROM - (SELECT - id - FROM (SELECT reference_table.user_id AS id - FROM raw_events_first, - reference_table - WHERE raw_events_first.user_id = reference_table.user_id ) AS foo) as f - INNER JOIN - (SELECT v4, - v1, - id - FROM (SELECT SUM(raw_events_second.value_4) AS v4, - SUM(raw_events_first.value_1) AS v1, - raw_events_second.user_id AS id - FROM raw_events_first, - raw_events_second - WHERE raw_events_first.user_id = raw_events_second.user_id - GROUP BY raw_events_second.user_id - HAVING SUM(raw_events_second.value_4) > 10) AS foo2 ) as f2 -ON (f.id != f2.id)) as outer_most -GROUP BY outer_most.id; -$Q$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> HashAggregate - Group Key: remote_scan.user_id - -> Custom Scan (Citus Adaptive) - -> Distributed Subplan XXX_1 - -> Custom Scan (Citus Adaptive) - Task Count: 4 -(8 rows) - --- cannot pushdown since foo2 is not join on partition key --- falls back to route via coordinator -SELECT coordinator_plan($Q$ -EXPLAIN (costs off) -INSERT INTO agg_events - (user_id, value_4_agg) -SELECT - outer_most.id, max(outer_most.value) -FROM -( - SELECT f2.id as id, f2.v4 as value FROM - (SELECT - id - FROM (SELECT reference_table.user_id AS id - FROM raw_events_first, - reference_table - WHERE raw_events_first.user_id = reference_table.user_id ) AS foo) as f - INNER JOIN - (SELECT v4, - v1, - id - FROM (SELECT SUM(raw_events_second.value_4) AS v4, - SUM(raw_events_first.value_1) AS v1, - raw_events_second.user_id AS id - FROM raw_events_first, - raw_events_second - WHERE raw_events_first.user_id = raw_events_second.value_1 - GROUP BY raw_events_second.user_id - HAVING SUM(raw_events_second.value_4) > 10) AS foo2 ) as f2 -ON (f.id = f2.id)) as outer_most -GROUP BY - outer_most.id; -$Q$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> HashAggregate - Group Key: remote_scan.user_id - -> Custom Scan (Citus Adaptive) - -> Distributed Subplan XXX_1 - -> HashAggregate - Group Key: remote_scan.id - Filter: (pg_catalog.sum(remote_scan.worker_column_4) > '10'::numeric) - -> Custom Scan (Citus Adaptive) - Task Count: 6 -(11 rows) - --- cannot push down since foo doesn't have en equi join --- falls back to route via coordinator -SELECT coordinator_plan($Q$ -EXPLAIN (costs off) -INSERT INTO agg_events - (user_id, value_4_agg) -SELECT - outer_most.id, max(outer_most.value) -FROM -( - SELECT f2.id as id, f2.v4 as value FROM - (SELECT - id - FROM (SELECT reference_table.user_id AS id - FROM raw_events_first, - reference_table - WHERE raw_events_first.user_id != reference_table.user_id ) AS foo) as f - INNER JOIN - (SELECT v4, - v1, - id - FROM (SELECT SUM(raw_events_second.value_4) AS v4, - SUM(raw_events_first.value_1) AS v1, - raw_events_second.user_id AS id - FROM raw_events_first, - raw_events_second - WHERE raw_events_first.user_id = raw_events_second.user_id - GROUP BY raw_events_second.user_id - HAVING SUM(raw_events_second.value_4) > 10) AS foo2 ) as f2 -ON (f.id = f2.id)) as outer_most -GROUP BY - outer_most.id; -$Q$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> HashAggregate - Group Key: remote_scan.user_id - -> Custom Scan (Citus Adaptive) - -> Distributed Subplan XXX_1 - -> Custom Scan (Citus Adaptive) - Task Count: 4 -(8 rows) - --- some unsupported LATERAL JOINs --- join on averages is not on the partition key --- should fall back to route via coordinator -SELECT coordinator_plan($Q$ -EXPLAIN (costs off) -INSERT INTO agg_events (user_id, value_4_agg) -SELECT - averages.user_id, avg(averages.value_4) -FROM - (SELECT - raw_events_second.user_id - FROM - reference_table JOIN raw_events_second on (reference_table.user_id = raw_events_second.user_id) - ) reference_ids - JOIN LATERAL - (SELECT - user_id, value_4 - FROM - raw_events_first WHERE - value_4 = reference_ids.user_id) as averages ON true - GROUP BY averages.user_id; -$Q$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> HashAggregate - Group Key: remote_scan.user_id - -> Custom Scan (Citus Adaptive) - Task Count: 6 -(6 rows) - --- join among reference_ids and averages is not on the partition key --- should fall back to route via coordinator -SELECT coordinator_plan($Q$ -EXPLAIN (costs off) -INSERT INTO agg_events (user_id, value_4_agg) -SELECT - averages.user_id, avg(averages.value_4) -FROM - (SELECT - raw_events_second.user_id - FROM - reference_table JOIN raw_events_second on (reference_table.user_id = raw_events_second.user_id) - ) reference_ids - JOIN LATERAL - (SELECT - user_id, value_4 - FROM - raw_events_first) as averages ON averages.value_4 = reference_ids.user_id - GROUP BY averages.user_id; -$Q$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> HashAggregate - Group Key: remote_scan.user_id - -> Custom Scan (Citus Adaptive) - -> Distributed Subplan XXX_1 - -> Custom Scan (Citus Adaptive) - Task Count: 4 -(8 rows) - --- join among the agg_ids and averages is not on the partition key --- should fall back to route via coordinator -SELECT coordinator_plan($Q$ -EXPLAIN (costs off) -INSERT INTO agg_events (user_id, value_4_agg) -SELECT - averages.user_id, avg(averages.value_4) -FROM - (SELECT - raw_events_second.user_id - FROM - reference_table JOIN raw_events_second on (reference_table.user_id = raw_events_second.user_id) - ) reference_ids - JOIN LATERAL - (SELECT - user_id, value_4 - FROM - raw_events_first) as averages ON averages.user_id = reference_ids.user_id -JOIN LATERAL - (SELECT user_id, value_4 FROM agg_events) as agg_ids ON (agg_ids.value_4 = averages.user_id) - GROUP BY averages.user_id; -$Q$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> Custom Scan (Citus Adaptive) - Task Count: 6 -(4 rows) - --- Selected value in the WHERE is not partition key, so we cannot use distributed --- INSERT/SELECT and falls back route via coordinator -SELECT coordinator_plan($Q$ -EXPLAIN (costs off) -INSERT INTO raw_events_second - (user_id) -SELECT user_id -FROM raw_events_first -WHERE user_id IN (SELECT value_1 - FROM raw_events_second); -$Q$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: repartition - -> Custom Scan (Citus Adaptive) - -> Distributed Subplan XXX_1 - -> Custom Scan (Citus Adaptive) - Task Count: 4 -(6 rows) - --- same as above but slightly more complex --- since it also includes subquery in FROM as well -SELECT coordinator_plan($Q$ -EXPLAIN (costs off) -INSERT INTO agg_events - (user_id) -SELECT f2.id FROM - -(SELECT - id -FROM (SELECT reference_table.user_id AS id - FROM raw_events_first, - reference_table - WHERE raw_events_first.user_id = reference_table.user_id ) AS foo) as f -INNER JOIN -(SELECT v4, - v1, - id -FROM (SELECT SUM(raw_events_second.value_4) AS v4, - SUM(raw_events_first.value_1) AS v1, - raw_events_second.user_id AS id - FROM raw_events_first, - raw_events_second - WHERE raw_events_first.user_id = raw_events_second.user_id - GROUP BY raw_events_second.user_id - HAVING SUM(raw_events_second.value_4) > 10) AS foo2 ) as f2 -ON (f.id = f2.id) -WHERE f.id IN (SELECT value_1 - FROM raw_events_second); -$Q$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: repartition - -> Custom Scan (Citus Adaptive) - -> Distributed Subplan XXX_1 - -> Custom Scan (Citus Adaptive) - Task Count: 4 -(6 rows) - --- some more semi-anti join tests -SET client_min_messages TO DEBUG2; --- join in where -INSERT INTO raw_events_second - (user_id) -SELECT user_id -FROM raw_events_first -WHERE user_id IN (SELECT raw_events_second.user_id - FROM raw_events_second, raw_events_first - WHERE raw_events_second.user_id = raw_events_first.user_id AND raw_events_first.user_id = 200); -DEBUG: Creating router plan -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300004 AS citus_table_alias (user_id) SELECT user_id FROM multi_insert_select.raw_events_first_13300000 raw_events_first WHERE ((user_id OPERATOR(pg_catalog.=) ANY (SELECT raw_events_second.user_id FROM multi_insert_select.raw_events_second_13300004 raw_events_second, multi_insert_select.raw_events_first_13300000 raw_events_first_1 WHERE ((raw_events_second.user_id OPERATOR(pg_catalog.=) raw_events_first_1.user_id) AND (raw_events_first_1.user_id OPERATOR(pg_catalog.=) 200)))) AND (user_id IS NOT NULL)) -DEBUG: Skipping target shard interval 13300005 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300006 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300007 since SELECT query for it pruned away -RESET client_min_messages; --- we cannot push this down since it is NOT IN --- we use repartition insert/select instead -SELECT coordinator_plan($Q$ -EXPLAIN (costs off) -INSERT INTO raw_events_second - (user_id) -SELECT user_id -FROM raw_events_first -WHERE user_id NOT IN (SELECT raw_events_second.user_id - FROM raw_events_second, raw_events_first - WHERE raw_events_second.user_id = raw_events_first.user_id AND raw_events_first.user_id = 200); -$Q$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: repartition - -> Custom Scan (Citus Adaptive) - -> Distributed Subplan XXX_1 - -> Custom Scan (Citus Adaptive) - Task Count: 1 -(6 rows) - -SET client_min_messages TO DEBUG2; --- safe to push down -INSERT INTO raw_events_second - (user_id) -SELECT user_id -FROM raw_events_first -WHERE EXISTS (SELECT 1 - FROM raw_events_second - WHERE raw_events_second.user_id =raw_events_first.user_id); -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300004 AS citus_table_alias (user_id) SELECT user_id FROM multi_insert_select.raw_events_first_13300000 raw_events_first WHERE ((EXISTS (SELECT 1 FROM multi_insert_select.raw_events_second_13300004 raw_events_second WHERE (raw_events_second.user_id OPERATOR(pg_catalog.=) raw_events_first.user_id))) AND (user_id IS NOT NULL)) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300005 AS citus_table_alias (user_id) SELECT user_id FROM multi_insert_select.raw_events_first_13300001 raw_events_first WHERE ((EXISTS (SELECT 1 FROM multi_insert_select.raw_events_second_13300005 raw_events_second WHERE (raw_events_second.user_id OPERATOR(pg_catalog.=) raw_events_first.user_id))) AND (user_id IS NOT NULL)) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300006 AS citus_table_alias (user_id) SELECT user_id FROM multi_insert_select.raw_events_first_13300002 raw_events_first WHERE ((EXISTS (SELECT 1 FROM multi_insert_select.raw_events_second_13300006 raw_events_second WHERE (raw_events_second.user_id OPERATOR(pg_catalog.=) raw_events_first.user_id))) AND (user_id IS NOT NULL)) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300007 AS citus_table_alias (user_id) SELECT user_id FROM multi_insert_select.raw_events_first_13300003 raw_events_first WHERE ((EXISTS (SELECT 1 FROM multi_insert_select.raw_events_second_13300007 raw_events_second WHERE (raw_events_second.user_id OPERATOR(pg_catalog.=) raw_events_first.user_id))) AND (user_id IS NOT NULL)) --- we cannot push down -INSERT INTO raw_events_second - (user_id) -SELECT user_id -FROM raw_events_first -WHERE NOT EXISTS (SELECT 1 - FROM raw_events_second - WHERE raw_events_second.user_id =raw_events_first.user_id); -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300004 AS citus_table_alias (user_id) SELECT user_id FROM multi_insert_select.raw_events_first_13300000 raw_events_first WHERE ((NOT (EXISTS (SELECT 1 FROM multi_insert_select.raw_events_second_13300004 raw_events_second WHERE (raw_events_second.user_id OPERATOR(pg_catalog.=) raw_events_first.user_id)))) AND (user_id IS NOT NULL)) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300005 AS citus_table_alias (user_id) SELECT user_id FROM multi_insert_select.raw_events_first_13300001 raw_events_first WHERE ((NOT (EXISTS (SELECT 1 FROM multi_insert_select.raw_events_second_13300005 raw_events_second WHERE (raw_events_second.user_id OPERATOR(pg_catalog.=) raw_events_first.user_id)))) AND (user_id IS NOT NULL)) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300006 AS citus_table_alias (user_id) SELECT user_id FROM multi_insert_select.raw_events_first_13300002 raw_events_first WHERE ((NOT (EXISTS (SELECT 1 FROM multi_insert_select.raw_events_second_13300006 raw_events_second WHERE (raw_events_second.user_id OPERATOR(pg_catalog.=) raw_events_first.user_id)))) AND (user_id IS NOT NULL)) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300007 AS citus_table_alias (user_id) SELECT user_id FROM multi_insert_select.raw_events_first_13300003 raw_events_first WHERE ((NOT (EXISTS (SELECT 1 FROM multi_insert_select.raw_events_second_13300007 raw_events_second WHERE (raw_events_second.user_id OPERATOR(pg_catalog.=) raw_events_first.user_id)))) AND (user_id IS NOT NULL)) --- more complex LEFT JOINs - INSERT INTO agg_events - (user_id, value_4_agg) - SELECT - outer_most.id, max(outer_most.value) - FROM - ( - SELECT f2.id as id, f2.v4 as value FROM - (SELECT - id - FROM (SELECT raw_events_first.user_id AS id - FROM raw_events_first LEFT JOIN - reference_table - ON (raw_events_first.user_id = reference_table.user_id)) AS foo) as f - LEFT JOIN - (SELECT v4, - v1, - id - FROM (SELECT SUM(raw_events_second.value_4) AS v4, - SUM(raw_events_first.value_1) AS v1, - raw_events_second.user_id AS id - FROM raw_events_first, - raw_events_second - WHERE raw_events_first.user_id = raw_events_second.user_id - GROUP BY raw_events_second.user_id - HAVING SUM(raw_events_second.value_4) > 10) AS foo2 ) as f2 - ON (f.id = f2.id)) as outer_most - GROUP BY - outer_most.id; -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300008 AS citus_table_alias (user_id, value_4_agg) SELECT id, max(value) AS max FROM (SELECT f2.id, f2.v4 AS value FROM ((SELECT foo.id FROM (SELECT raw_events_first.user_id AS id FROM (multi_insert_select.raw_events_first_13300000 raw_events_first LEFT JOIN multi_insert_select.reference_table_13300012 reference_table ON ((raw_events_first.user_id OPERATOR(pg_catalog.=) reference_table.user_id)))) foo) f LEFT JOIN (SELECT foo2.v4, foo2.v1, foo2.id FROM (SELECT sum(raw_events_second.value_4) AS v4, sum(raw_events_first.value_1) AS v1, raw_events_second.user_id AS id FROM multi_insert_select.raw_events_first_13300000 raw_events_first, multi_insert_select.raw_events_second_13300004 raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.user_id HAVING (sum(raw_events_second.value_4) OPERATOR(pg_catalog.>) (10)::numeric)) foo2) f2 ON ((f.id OPERATOR(pg_catalog.=) f2.id)))) outer_most WHERE (id IS NOT NULL) GROUP BY id -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300009 AS citus_table_alias (user_id, value_4_agg) SELECT id, max(value) AS max FROM (SELECT f2.id, f2.v4 AS value FROM ((SELECT foo.id FROM (SELECT raw_events_first.user_id AS id FROM (multi_insert_select.raw_events_first_13300001 raw_events_first LEFT JOIN multi_insert_select.reference_table_13300012 reference_table ON ((raw_events_first.user_id OPERATOR(pg_catalog.=) reference_table.user_id)))) foo) f LEFT JOIN (SELECT foo2.v4, foo2.v1, foo2.id FROM (SELECT sum(raw_events_second.value_4) AS v4, sum(raw_events_first.value_1) AS v1, raw_events_second.user_id AS id FROM multi_insert_select.raw_events_first_13300001 raw_events_first, multi_insert_select.raw_events_second_13300005 raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.user_id HAVING (sum(raw_events_second.value_4) OPERATOR(pg_catalog.>) (10)::numeric)) foo2) f2 ON ((f.id OPERATOR(pg_catalog.=) f2.id)))) outer_most WHERE (id IS NOT NULL) GROUP BY id -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300010 AS citus_table_alias (user_id, value_4_agg) SELECT id, max(value) AS max FROM (SELECT f2.id, f2.v4 AS value FROM ((SELECT foo.id FROM (SELECT raw_events_first.user_id AS id FROM (multi_insert_select.raw_events_first_13300002 raw_events_first LEFT JOIN multi_insert_select.reference_table_13300012 reference_table ON ((raw_events_first.user_id OPERATOR(pg_catalog.=) reference_table.user_id)))) foo) f LEFT JOIN (SELECT foo2.v4, foo2.v1, foo2.id FROM (SELECT sum(raw_events_second.value_4) AS v4, sum(raw_events_first.value_1) AS v1, raw_events_second.user_id AS id FROM multi_insert_select.raw_events_first_13300002 raw_events_first, multi_insert_select.raw_events_second_13300006 raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.user_id HAVING (sum(raw_events_second.value_4) OPERATOR(pg_catalog.>) (10)::numeric)) foo2) f2 ON ((f.id OPERATOR(pg_catalog.=) f2.id)))) outer_most WHERE (id IS NOT NULL) GROUP BY id -DEBUG: distributed statement: INSERT INTO multi_insert_select.agg_events_13300011 AS citus_table_alias (user_id, value_4_agg) SELECT id, max(value) AS max FROM (SELECT f2.id, f2.v4 AS value FROM ((SELECT foo.id FROM (SELECT raw_events_first.user_id AS id FROM (multi_insert_select.raw_events_first_13300003 raw_events_first LEFT JOIN multi_insert_select.reference_table_13300012 reference_table ON ((raw_events_first.user_id OPERATOR(pg_catalog.=) reference_table.user_id)))) foo) f LEFT JOIN (SELECT foo2.v4, foo2.v1, foo2.id FROM (SELECT sum(raw_events_second.value_4) AS v4, sum(raw_events_first.value_1) AS v1, raw_events_second.user_id AS id FROM multi_insert_select.raw_events_first_13300003 raw_events_first, multi_insert_select.raw_events_second_13300007 raw_events_second WHERE (raw_events_first.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.user_id HAVING (sum(raw_events_second.value_4) OPERATOR(pg_catalog.>) (10)::numeric)) foo2) f2 ON ((f.id OPERATOR(pg_catalog.=) f2.id)))) outer_most WHERE (id IS NOT NULL) GROUP BY id -RESET client_min_messages; --- cannot push down since the f.id IN is matched with value_1 --- we use repartition insert/select instead -SELECT coordinator_plan($Q$ -EXPLAIN (costs off) -INSERT INTO raw_events_second - (user_id) -SELECT user_id -FROM raw_events_first -WHERE user_id IN ( -SELECT f2.id FROM -(SELECT - id -FROM (SELECT reference_table.user_id AS id - FROM raw_events_first, - reference_table - WHERE raw_events_first.user_id = reference_table.user_id ) AS foo) as f -INNER JOIN -(SELECT v4, - v1, - id -FROM (SELECT SUM(raw_events_second.value_4) AS v4, - SUM(raw_events_first.value_1) AS v1, - raw_events_second.user_id AS id - FROM raw_events_first, - raw_events_second - WHERE raw_events_first.user_id = raw_events_second.user_id - GROUP BY raw_events_second.user_id - HAVING SUM(raw_events_second.value_4) > 10) AS foo2 ) as f2 -ON (f.id = f2.id) -WHERE f.id IN (SELECT value_1 - FROM raw_events_second)); -$Q$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: repartition - -> Custom Scan (Citus Adaptive) - -> Distributed Subplan XXX_1 - -> Custom Scan (Citus Adaptive) - Task Count: 4 -(6 rows) - -SET client_min_messages TO DEBUG2; --- same as above, but this time is it safe to push down since --- f.id IN is matched with user_id -INSERT INTO raw_events_second - (user_id) -SELECT user_id -FROM raw_events_first -WHERE user_id IN ( -SELECT f2.id FROM -(SELECT - id -FROM (SELECT reference_table.user_id AS id - FROM raw_events_first, - reference_table - WHERE raw_events_first.user_id = reference_table.user_id ) AS foo) as f -INNER JOIN -(SELECT v4, - v1, - id -FROM (SELECT SUM(raw_events_second.value_4) AS v4, - SUM(raw_events_first.value_1) AS v1, - raw_events_second.user_id AS id - FROM raw_events_first, - raw_events_second - WHERE raw_events_first.user_id = raw_events_second.user_id - GROUP BY raw_events_second.user_id - HAVING SUM(raw_events_second.value_4) > 10) AS foo2 ) as f2 -ON (f.id = f2.id) -WHERE f.id IN (SELECT user_id - FROM raw_events_second)); -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300004 AS citus_table_alias (user_id) SELECT user_id FROM multi_insert_select.raw_events_first_13300000 raw_events_first WHERE ((user_id OPERATOR(pg_catalog.=) ANY (SELECT f2.id FROM ((SELECT foo.id FROM (SELECT reference_table.user_id AS id FROM multi_insert_select.raw_events_first_13300000 raw_events_first_1, multi_insert_select.reference_table_13300012 reference_table WHERE (raw_events_first_1.user_id OPERATOR(pg_catalog.=) reference_table.user_id)) foo) f JOIN (SELECT foo2.v4, foo2.v1, foo2.id FROM (SELECT sum(raw_events_second.value_4) AS v4, sum(raw_events_first_1.value_1) AS v1, raw_events_second.user_id AS id FROM multi_insert_select.raw_events_first_13300000 raw_events_first_1, multi_insert_select.raw_events_second_13300004 raw_events_second WHERE (raw_events_first_1.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.user_id HAVING (sum(raw_events_second.value_4) OPERATOR(pg_catalog.>) (10)::numeric)) foo2) f2 ON ((f.id OPERATOR(pg_catalog.=) f2.id))) WHERE (f.id OPERATOR(pg_catalog.=) ANY (SELECT raw_events_second.user_id FROM multi_insert_select.raw_events_second_13300004 raw_events_second)))) AND (user_id IS NOT NULL)) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300005 AS citus_table_alias (user_id) SELECT user_id FROM multi_insert_select.raw_events_first_13300001 raw_events_first WHERE ((user_id OPERATOR(pg_catalog.=) ANY (SELECT f2.id FROM ((SELECT foo.id FROM (SELECT reference_table.user_id AS id FROM multi_insert_select.raw_events_first_13300001 raw_events_first_1, multi_insert_select.reference_table_13300012 reference_table WHERE (raw_events_first_1.user_id OPERATOR(pg_catalog.=) reference_table.user_id)) foo) f JOIN (SELECT foo2.v4, foo2.v1, foo2.id FROM (SELECT sum(raw_events_second.value_4) AS v4, sum(raw_events_first_1.value_1) AS v1, raw_events_second.user_id AS id FROM multi_insert_select.raw_events_first_13300001 raw_events_first_1, multi_insert_select.raw_events_second_13300005 raw_events_second WHERE (raw_events_first_1.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.user_id HAVING (sum(raw_events_second.value_4) OPERATOR(pg_catalog.>) (10)::numeric)) foo2) f2 ON ((f.id OPERATOR(pg_catalog.=) f2.id))) WHERE (f.id OPERATOR(pg_catalog.=) ANY (SELECT raw_events_second.user_id FROM multi_insert_select.raw_events_second_13300005 raw_events_second)))) AND (user_id IS NOT NULL)) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300006 AS citus_table_alias (user_id) SELECT user_id FROM multi_insert_select.raw_events_first_13300002 raw_events_first WHERE ((user_id OPERATOR(pg_catalog.=) ANY (SELECT f2.id FROM ((SELECT foo.id FROM (SELECT reference_table.user_id AS id FROM multi_insert_select.raw_events_first_13300002 raw_events_first_1, multi_insert_select.reference_table_13300012 reference_table WHERE (raw_events_first_1.user_id OPERATOR(pg_catalog.=) reference_table.user_id)) foo) f JOIN (SELECT foo2.v4, foo2.v1, foo2.id FROM (SELECT sum(raw_events_second.value_4) AS v4, sum(raw_events_first_1.value_1) AS v1, raw_events_second.user_id AS id FROM multi_insert_select.raw_events_first_13300002 raw_events_first_1, multi_insert_select.raw_events_second_13300006 raw_events_second WHERE (raw_events_first_1.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.user_id HAVING (sum(raw_events_second.value_4) OPERATOR(pg_catalog.>) (10)::numeric)) foo2) f2 ON ((f.id OPERATOR(pg_catalog.=) f2.id))) WHERE (f.id OPERATOR(pg_catalog.=) ANY (SELECT raw_events_second.user_id FROM multi_insert_select.raw_events_second_13300006 raw_events_second)))) AND (user_id IS NOT NULL)) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_second_13300007 AS citus_table_alias (user_id) SELECT user_id FROM multi_insert_select.raw_events_first_13300003 raw_events_first WHERE ((user_id OPERATOR(pg_catalog.=) ANY (SELECT f2.id FROM ((SELECT foo.id FROM (SELECT reference_table.user_id AS id FROM multi_insert_select.raw_events_first_13300003 raw_events_first_1, multi_insert_select.reference_table_13300012 reference_table WHERE (raw_events_first_1.user_id OPERATOR(pg_catalog.=) reference_table.user_id)) foo) f JOIN (SELECT foo2.v4, foo2.v1, foo2.id FROM (SELECT sum(raw_events_second.value_4) AS v4, sum(raw_events_first_1.value_1) AS v1, raw_events_second.user_id AS id FROM multi_insert_select.raw_events_first_13300003 raw_events_first_1, multi_insert_select.raw_events_second_13300007 raw_events_second WHERE (raw_events_first_1.user_id OPERATOR(pg_catalog.=) raw_events_second.user_id) GROUP BY raw_events_second.user_id HAVING (sum(raw_events_second.value_4) OPERATOR(pg_catalog.>) (10)::numeric)) foo2) f2 ON ((f.id OPERATOR(pg_catalog.=) f2.id))) WHERE (f.id OPERATOR(pg_catalog.=) ANY (SELECT raw_events_second.user_id FROM multi_insert_select.raw_events_second_13300007 raw_events_second)))) AND (user_id IS NOT NULL)) -RESET client_min_messages; --- cannot push down since top level user_id is matched with NOT IN -INSERT INTO raw_events_second - (user_id) -SELECT user_id -FROM raw_events_first -WHERE user_id NOT IN ( -SELECT f2.id FROM -(SELECT - id -FROM (SELECT reference_table.user_id AS id - FROM raw_events_first, - reference_table - WHERE raw_events_first.user_id = reference_table.user_id ) AS foo) as f -INNER JOIN -(SELECT v4, - v1, - id -FROM (SELECT SUM(raw_events_second.value_4) AS v4, - SUM(raw_events_first.value_1) AS v1, - raw_events_second.user_id AS id - FROM raw_events_first, - raw_events_second - WHERE raw_events_first.user_id = raw_events_second.user_id - GROUP BY raw_events_second.user_id - HAVING SUM(raw_events_second.value_4) > 10) AS foo2 ) as f2 -ON (f.id = f2.id) -WHERE f.id IN (SELECT user_id - FROM raw_events_second)); --- cannot push down since join is not equi join (f.id > f2.id) -INSERT INTO raw_events_second - (user_id) -SELECT user_id -FROM raw_events_first -WHERE user_id IN ( -SELECT f2.id FROM -(SELECT - id -FROM (SELECT reference_table.user_id AS id - FROM raw_events_first, - reference_table - WHERE raw_events_first.user_id = reference_table.user_id ) AS foo) as f -INNER JOIN -(SELECT v4, - v1, - id -FROM (SELECT SUM(raw_events_second.value_4) AS v4, - SUM(raw_events_first.value_1) AS v1, - raw_events_second.user_id AS id - FROM raw_events_first, - raw_events_second - WHERE raw_events_first.user_id = raw_events_second.user_id - GROUP BY raw_events_second.user_id - HAVING SUM(raw_events_second.value_4) > 10) AS foo2 ) as f2 -ON (f.id > f2.id) -WHERE f.id IN (SELECT user_id - FROM raw_events_second)); --- we currently not support grouping sets -INSERT INTO agg_events - (user_id, - value_1_agg, - value_2_agg) -SELECT user_id, - Sum(value_1) AS sum_val1, - Sum(value_2) AS sum_val2 -FROM raw_events_second -GROUP BY grouping sets ( ( user_id ), ( value_1 ), ( user_id, value_1 ), ( ) ); -ERROR: could not run distributed query with GROUPING SETS, CUBE, or ROLLUP -HINT: Consider using an equality filter on the distributed table's partition column. --- set back to INFO -SET client_min_messages TO INFO; --- avoid constraint violations -TRUNCATE raw_events_first; --- we don't support LIMIT for subquery pushdown, but --- we recursively plan the query and run it via coordinator -INSERT INTO agg_events(user_id) -SELECT user_id -FROM users_table -WHERE user_id - IN (SELECT - user_id - FROM ( - ( - SELECT - user_id - FROM - ( - SELECT - e1.user_id - FROM - users_table u1, events_table e1 - WHERE - e1.user_id = u1.user_id LIMIT 3 - ) as f_inner - ) - ) AS f2); --- Altering a table and selecting from it using a multi-shard statement --- in the same transaction is allowed because we will use the same --- connections for all co-located placements. -BEGIN; -ALTER TABLE raw_events_second DROP COLUMN value_4; -INSERT INTO raw_events_first SELECT * FROM raw_events_second; -ROLLBACK; --- Alterating a table and selecting from it using a single-shard statement --- in the same transaction is disallowed because we will use a different --- connection. -BEGIN; -ALTER TABLE raw_events_second DROP COLUMN value_4; -INSERT INTO raw_events_first SELECT * FROM raw_events_second WHERE user_id = 100; -ROLLBACK; --- Altering a reference table and then performing an INSERT ... SELECT which --- joins with the reference table is allowed, since the INSERT ... SELECT --- would read from the reference table over the same connections with the ones --- that performed the parallel DDL. -BEGIN; -ALTER TABLE reference_table ADD COLUMN z int; -INSERT INTO raw_events_first (user_id) -SELECT user_id FROM raw_events_second JOIN reference_table USING (user_id); -ROLLBACK; --- the same test with sequential DDL should work fine -BEGIN; -SET LOCAL citus.multi_shard_modify_mode TO 'sequential'; -ALTER TABLE reference_table ADD COLUMN z int; -INSERT INTO raw_events_first (user_id) -SELECT user_id FROM raw_events_second JOIN reference_table USING (user_id); -ROLLBACK; --- Insert after copy is allowed -BEGIN; -COPY raw_events_second (user_id, value_1) FROM STDIN DELIMITER ','; -INSERT INTO raw_events_first SELECT * FROM raw_events_second; -ROLLBACK; --- Insert after copy is currently allowed for single-shard operation. --- Both insert and copy are rolled back successfully. -BEGIN; -COPY raw_events_second (user_id, value_1) FROM STDIN DELIMITER ','; -INSERT INTO raw_events_first SELECT * FROM raw_events_second WHERE user_id = 101; -SELECT user_id FROM raw_events_first WHERE user_id = 101; - user_id ---------------------------------------------------------------------- - 101 -(1 row) - -ROLLBACK; -BEGIN; -INSERT INTO raw_events_first SELECT * FROM raw_events_second; -COPY raw_events_first (user_id, value_1) FROM STDIN DELIMITER ','; -ROLLBACK; -BEGIN; -INSERT INTO raw_events_first SELECT * FROM raw_events_second WHERE user_id = 100; -COPY raw_events_first (user_id, value_1) FROM STDIN DELIMITER ','; -ROLLBACK; --- Similarly, multi-row INSERTs will take part in transactions and reuse connections... -BEGIN; -INSERT INTO raw_events_first SELECT * FROM raw_events_second WHERE user_id = 100; -COPY raw_events_first (user_id, value_1) FROM STDIN DELIMITER ','; -INSERT INTO raw_events_first (user_id, value_1) VALUES (105, 105), (106, 106); -ROLLBACK; --- selecting from views works -CREATE VIEW test_view AS SELECT * FROM raw_events_first; -INSERT INTO raw_events_first (user_id, time, value_1, value_2, value_3, value_4) VALUES - (16, now(), 60, 600, 6000.1, 60000); -SELECT count(*) FROM raw_events_second; - count ---------------------------------------------------------------------- - 45 -(1 row) - -INSERT INTO raw_events_second SELECT * FROM test_view; -INSERT INTO raw_events_first (user_id, time, value_1, value_2, value_3, value_4) VALUES - (17, now(), 60, 600, 6000.1, 60000); -INSERT INTO raw_events_second SELECT * FROM test_view WHERE user_id = 17 GROUP BY 1,2,3,4,5,6; -SELECT count(*) FROM raw_events_second; - count ---------------------------------------------------------------------- - 47 -(1 row) - --- intermediate results (CTEs) should be allowed when doing INSERT...SELECT within a CTE -WITH series AS ( - SELECT s AS val FROM generate_series(60,70) s -), -inserts AS ( - INSERT INTO raw_events_second (user_id) - SELECT - user_id - FROM - raw_events_first JOIN series ON (value_1 = val) - RETURNING - NULL -) -SELECT count(*) FROM inserts; - count ---------------------------------------------------------------------- - 2 -(1 row) - --- we need this in our next test -truncate raw_events_first; -SET client_min_messages TO DEBUG2; --- first show that the query works now -INSERT INTO raw_events_first SELECT * FROM raw_events_second; -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_first_13300000 AS citus_table_alias (user_id, "time", value_1, value_2, value_3, value_4) SELECT user_id, "time", value_1, value_2, value_3, value_4 FROM multi_insert_select.raw_events_second_13300004 raw_events_second WHERE (user_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_first_13300001 AS citus_table_alias (user_id, "time", value_1, value_2, value_3, value_4) SELECT user_id, "time", value_1, value_2, value_3, value_4 FROM multi_insert_select.raw_events_second_13300005 raw_events_second WHERE (user_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_first_13300002 AS citus_table_alias (user_id, "time", value_1, value_2, value_3, value_4) SELECT user_id, "time", value_1, value_2, value_3, value_4 FROM multi_insert_select.raw_events_second_13300006 raw_events_second WHERE (user_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_first_13300003 AS citus_table_alias (user_id, "time", value_1, value_2, value_3, value_4) SELECT user_id, "time", value_1, value_2, value_3, value_4 FROM multi_insert_select.raw_events_second_13300007 raw_events_second WHERE (user_id IS NOT NULL) -SET client_min_messages TO INFO; -truncate raw_events_first; -SET client_min_messages TO DEBUG2; --- now show that it works for a single shard query as well -INSERT INTO raw_events_first SELECT * FROM raw_events_second WHERE user_id = 5; -DEBUG: Creating router plan -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_first_13300000 AS citus_table_alias (user_id, "time", value_1, value_2, value_3, value_4) SELECT user_id, "time", value_1, value_2, value_3, value_4 FROM multi_insert_select.raw_events_second_13300004 raw_events_second WHERE ((user_id OPERATOR(pg_catalog.=) 5) AND (user_id IS NOT NULL)) -DEBUG: Skipping target shard interval 13300001 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300002 since SELECT query for it pruned away -DEBUG: Skipping target shard interval 13300003 since SELECT query for it pruned away -SET client_min_messages TO INFO; --- now do some tests with varchars -INSERT INTO insert_select_varchar_test VALUES ('test_1', 10); -INSERT INTO insert_select_varchar_test VALUES ('test_2', 30); -INSERT INTO insert_select_varchar_test (key, value) -SELECT *, 100 -FROM (SELECT f1.key - FROM (SELECT key - FROM insert_select_varchar_test - GROUP BY 1 - HAVING Count(key) < 3) AS f1, - (SELECT key - FROM insert_select_varchar_test - GROUP BY 1 - HAVING Sum(COALESCE(insert_select_varchar_test.value, 0)) > - 20.0) - AS f2 - WHERE f1.key = f2.key - GROUP BY 1) AS foo; -SELECT * FROM insert_select_varchar_test ORDER BY 1 DESC, 2 DESC; - key | value ---------------------------------------------------------------------- - test_2 | 100 - test_2 | 30 - test_1 | 10 -(3 rows) - --- some tests with DEFAULT columns and constant values --- this test is mostly importantly intended for deparsing the query correctly --- but still it is preferable to have this test here instead of multi_deparse_shard_query -CREATE TABLE table_with_defaults -( - store_id int, - first_name text, - default_1 int DEFAULT 1, - last_name text, - default_2 text DEFAULT '2' -); --- we don't need many shards -SET citus.shard_count = 2; -SELECT create_distributed_table('table_with_defaults', 'store_id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - --- let's see the queries -SET client_min_messages TO DEBUG2; --- a very simple query -INSERT INTO table_with_defaults SELECT * FROM table_with_defaults; -DEBUG: distributed statement: INSERT INTO multi_insert_select.table_with_defaults_13300017 AS citus_table_alias (store_id, first_name, default_1, last_name, default_2) SELECT store_id, first_name, default_1, last_name, default_2 FROM multi_insert_select.table_with_defaults_13300017 table_with_defaults WHERE (store_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.table_with_defaults_13300018 AS citus_table_alias (store_id, first_name, default_1, last_name, default_2) SELECT store_id, first_name, default_1, last_name, default_2 FROM multi_insert_select.table_with_defaults_13300018 table_with_defaults WHERE (store_id IS NOT NULL) --- see that defaults are filled -INSERT INTO table_with_defaults (store_id, first_name) -SELECT - store_id, first_name -FROM - table_with_defaults; -DEBUG: distributed statement: INSERT INTO multi_insert_select.table_with_defaults_13300017 AS citus_table_alias (store_id, first_name, default_1, default_2) SELECT store_id, first_name, 1 AS default_1, '2'::text AS default_2 FROM multi_insert_select.table_with_defaults_13300017 table_with_defaults WHERE (store_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.table_with_defaults_13300018 AS citus_table_alias (store_id, first_name, default_1, default_2) SELECT store_id, first_name, 1 AS default_1, '2'::text AS default_2 FROM multi_insert_select.table_with_defaults_13300018 table_with_defaults WHERE (store_id IS NOT NULL) --- shuffle one of the defaults and skip the other -INSERT INTO table_with_defaults (default_2, store_id, first_name) -SELECT - default_2, store_id, first_name -FROM - table_with_defaults; -DEBUG: distributed statement: INSERT INTO multi_insert_select.table_with_defaults_13300017 AS citus_table_alias (store_id, first_name, default_1, default_2) SELECT store_id, first_name, 1 AS default_1, default_2 FROM multi_insert_select.table_with_defaults_13300017 table_with_defaults WHERE (store_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.table_with_defaults_13300018 AS citus_table_alias (store_id, first_name, default_1, default_2) SELECT store_id, first_name, 1 AS default_1, default_2 FROM multi_insert_select.table_with_defaults_13300018 table_with_defaults WHERE (store_id IS NOT NULL) --- shuffle both defaults -INSERT INTO table_with_defaults (default_2, store_id, default_1, first_name) -SELECT - default_2, store_id, default_1, first_name -FROM - table_with_defaults; -DEBUG: distributed statement: INSERT INTO multi_insert_select.table_with_defaults_13300017 AS citus_table_alias (store_id, first_name, default_1, default_2) SELECT store_id, first_name, default_1, default_2 FROM multi_insert_select.table_with_defaults_13300017 table_with_defaults WHERE (store_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.table_with_defaults_13300018 AS citus_table_alias (store_id, first_name, default_1, default_2) SELECT store_id, first_name, default_1, default_2 FROM multi_insert_select.table_with_defaults_13300018 table_with_defaults WHERE (store_id IS NOT NULL) --- use constants instead of non-default column -INSERT INTO table_with_defaults (default_2, last_name, store_id, first_name) -SELECT - default_2, 'Freund', store_id, 'Andres' -FROM - table_with_defaults; -DEBUG: distributed statement: INSERT INTO multi_insert_select.table_with_defaults_13300017 AS citus_table_alias (store_id, first_name, default_1, last_name, default_2) SELECT store_id, 'Andres'::text AS first_name, 1 AS default_1, 'Freund'::text AS last_name, default_2 FROM multi_insert_select.table_with_defaults_13300017 table_with_defaults WHERE (store_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.table_with_defaults_13300018 AS citus_table_alias (store_id, first_name, default_1, last_name, default_2) SELECT store_id, 'Andres'::text AS first_name, 1 AS default_1, 'Freund'::text AS last_name, default_2 FROM multi_insert_select.table_with_defaults_13300018 table_with_defaults WHERE (store_id IS NOT NULL) --- use constants instead of non-default column and skip both defauls -INSERT INTO table_with_defaults (last_name, store_id, first_name) -SELECT - 'Freund', store_id, 'Andres' -FROM - table_with_defaults; -DEBUG: distributed statement: INSERT INTO multi_insert_select.table_with_defaults_13300017 AS citus_table_alias (store_id, first_name, default_1, last_name, default_2) SELECT store_id, 'Andres'::text AS first_name, 1 AS default_1, 'Freund'::text AS last_name, '2'::text AS default_2 FROM multi_insert_select.table_with_defaults_13300017 table_with_defaults WHERE (store_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.table_with_defaults_13300018 AS citus_table_alias (store_id, first_name, default_1, last_name, default_2) SELECT store_id, 'Andres'::text AS first_name, 1 AS default_1, 'Freund'::text AS last_name, '2'::text AS default_2 FROM multi_insert_select.table_with_defaults_13300018 table_with_defaults WHERE (store_id IS NOT NULL) --- use constants instead of default columns -INSERT INTO table_with_defaults (default_2, last_name, store_id, first_name, default_1) -SELECT - 20, last_name, store_id, first_name, 10 -FROM - table_with_defaults; -DEBUG: distributed statement: INSERT INTO multi_insert_select.table_with_defaults_13300017 AS citus_table_alias (store_id, first_name, default_1, last_name, default_2) SELECT store_id, first_name, 10, last_name, 20 FROM multi_insert_select.table_with_defaults_13300017 table_with_defaults WHERE (store_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.table_with_defaults_13300018 AS citus_table_alias (store_id, first_name, default_1, last_name, default_2) SELECT store_id, first_name, 10, last_name, 20 FROM multi_insert_select.table_with_defaults_13300018 table_with_defaults WHERE (store_id IS NOT NULL) --- use constants instead of both default columns and non-default columns -INSERT INTO table_with_defaults (default_2, last_name, store_id, first_name, default_1) -SELECT - 20, 'Freund', store_id, 'Andres', 10 -FROM - table_with_defaults; -DEBUG: distributed statement: INSERT INTO multi_insert_select.table_with_defaults_13300017 AS citus_table_alias (store_id, first_name, default_1, last_name, default_2) SELECT store_id, 'Andres'::text AS first_name, 10, 'Freund'::text AS last_name, 20 FROM multi_insert_select.table_with_defaults_13300017 table_with_defaults WHERE (store_id IS NOT NULL) -DEBUG: distributed statement: INSERT INTO multi_insert_select.table_with_defaults_13300018 AS citus_table_alias (store_id, first_name, default_1, last_name, default_2) SELECT store_id, 'Andres'::text AS first_name, 10, 'Freund'::text AS last_name, 20 FROM multi_insert_select.table_with_defaults_13300018 table_with_defaults WHERE (store_id IS NOT NULL) --- some of the ultimate queries where we have constants, --- defaults and group by entry is not on the target entry -INSERT INTO table_with_defaults (default_2, store_id, first_name) -SELECT - '2000', store_id, 'Andres' -FROM - table_with_defaults -GROUP BY - last_name, store_id; -DEBUG: distributed statement: INSERT INTO multi_insert_select.table_with_defaults_13300017 AS citus_table_alias (store_id, first_name, default_1, default_2) SELECT store_id, 'Andres'::text AS first_name, 1 AS default_1, '2000'::text AS default_2 FROM multi_insert_select.table_with_defaults_13300017 table_with_defaults WHERE (store_id IS NOT NULL) GROUP BY last_name, store_id -DEBUG: distributed statement: INSERT INTO multi_insert_select.table_with_defaults_13300018 AS citus_table_alias (store_id, first_name, default_1, default_2) SELECT store_id, 'Andres'::text AS first_name, 1 AS default_1, '2000'::text AS default_2 FROM multi_insert_select.table_with_defaults_13300018 table_with_defaults WHERE (store_id IS NOT NULL) GROUP BY last_name, store_id -INSERT INTO table_with_defaults (default_1, store_id, first_name, default_2) -SELECT - 1000, store_id, 'Andres', '2000' -FROM - table_with_defaults -GROUP BY - last_name, store_id, first_name; -DEBUG: distributed statement: INSERT INTO multi_insert_select.table_with_defaults_13300017 AS citus_table_alias (store_id, first_name, default_1, default_2) SELECT store_id, 'Andres'::text AS first_name, 1000, '2000'::text AS default_2 FROM multi_insert_select.table_with_defaults_13300017 table_with_defaults WHERE (store_id IS NOT NULL) GROUP BY last_name, store_id, first_name -DEBUG: distributed statement: INSERT INTO multi_insert_select.table_with_defaults_13300018 AS citus_table_alias (store_id, first_name, default_1, default_2) SELECT store_id, 'Andres'::text AS first_name, 1000, '2000'::text AS default_2 FROM multi_insert_select.table_with_defaults_13300018 table_with_defaults WHERE (store_id IS NOT NULL) GROUP BY last_name, store_id, first_name -INSERT INTO table_with_defaults (default_1, store_id, first_name, default_2) -SELECT - 1000, store_id, 'Andres', '2000' -FROM - table_with_defaults -GROUP BY - last_name, store_id, first_name, default_2; -DEBUG: distributed statement: INSERT INTO multi_insert_select.table_with_defaults_13300017 AS citus_table_alias (store_id, first_name, default_1, default_2) SELECT store_id, 'Andres'::text AS first_name, 1000, '2000'::text AS default_2 FROM multi_insert_select.table_with_defaults_13300017 table_with_defaults WHERE (store_id IS NOT NULL) GROUP BY last_name, store_id, first_name, default_2 -DEBUG: distributed statement: INSERT INTO multi_insert_select.table_with_defaults_13300018 AS citus_table_alias (store_id, first_name, default_1, default_2) SELECT store_id, 'Andres'::text AS first_name, 1000, '2000'::text AS default_2 FROM multi_insert_select.table_with_defaults_13300018 table_with_defaults WHERE (store_id IS NOT NULL) GROUP BY last_name, store_id, first_name, default_2 -INSERT INTO table_with_defaults (default_1, store_id, first_name) -SELECT - 1000, store_id, 'Andres' -FROM - table_with_defaults -GROUP BY - last_name, store_id, first_name, default_2; -DEBUG: distributed statement: INSERT INTO multi_insert_select.table_with_defaults_13300017 AS citus_table_alias (store_id, first_name, default_1, default_2) SELECT store_id, 'Andres'::text AS first_name, 1000, '2'::text AS default_2 FROM multi_insert_select.table_with_defaults_13300017 table_with_defaults WHERE (store_id IS NOT NULL) GROUP BY last_name, store_id, first_name, default_2 -DEBUG: distributed statement: INSERT INTO multi_insert_select.table_with_defaults_13300018 AS citus_table_alias (store_id, first_name, default_1, default_2) SELECT store_id, 'Andres'::text AS first_name, 1000, '2'::text AS default_2 FROM multi_insert_select.table_with_defaults_13300018 table_with_defaults WHERE (store_id IS NOT NULL) GROUP BY last_name, store_id, first_name, default_2 -RESET client_min_messages; --- Stable function in default should be allowed -ALTER TABLE table_with_defaults ADD COLUMN t timestamptz DEFAULT now(); -INSERT INTO table_with_defaults (store_id, first_name, last_name) -SELECT - store_id, 'first '||store_id, 'last '||store_id -FROM - table_with_defaults -GROUP BY - store_id, first_name, last_name; --- Volatile function in default should be disallowed - SERIAL pseudo-types -CREATE TABLE table_with_serial ( - store_id int, - s bigserial -); -SELECT create_distributed_table('table_with_serial', 'store_id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO table_with_serial (store_id) -SELECT - store_id -FROM - table_with_defaults -GROUP BY - store_id; --- Volatile function in default should be disallowed - user-defined sequence -CREATE SEQUENCE user_defined_sequence; -CREATE TABLE table_with_user_sequence ( - store_id int, - s bigint default nextval('user_defined_sequence') -); -SELECT create_distributed_table('table_with_user_sequence', 'store_id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO table_with_user_sequence (store_id) -SELECT - store_id -FROM - table_with_defaults -GROUP BY - store_id; --- do some more error/error message checks -SET citus.shard_count TO 4; -SET citus.shard_replication_factor TO 1; -CREATE TABLE text_table (part_col text, val int); -CREATE TABLE char_table (part_col char[], val int); -create table table_with_starts_with_defaults (a int DEFAULT 5, b int, c int); -SELECT create_distributed_table('text_table', 'part_col'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -SELECT create_distributed_table('char_table','part_col'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -SELECT create_distributed_table('table_with_starts_with_defaults', 'c'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -SET client_min_messages TO DEBUG; -INSERT INTO text_table (part_col) - SELECT - CASE WHEN part_col = 'onder' THEN 'marco' - END -FROM text_table ; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: Subquery contains a case expression in the same position as the target table's partition column. -HINT: Ensure the target table's partition column has a corresponding simple column reference to a distributed table's partition column in the subquery. -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 0 with name 'part_col' -INSERT INTO text_table (part_col) SELECT COALESCE(part_col, 'onder') FROM text_table; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: Subquery contains a coalesce expression in the same position as the target table's partition column. -HINT: Ensure the target table's partition column has a corresponding simple column reference to a distributed table's partition column in the subquery. -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 0 with name 'part_col' -INSERT INTO text_table (part_col) SELECT GREATEST(part_col, 'jason') FROM text_table; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: Subquery contains a min/max expression in the same position as the target table's partition column. -HINT: Ensure the target table's partition column has a corresponding simple column reference to a distributed table's partition column in the subquery. -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 0 with name 'part_col' -INSERT INTO text_table (part_col) SELECT LEAST(part_col, 'andres') FROM text_table; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: Subquery contains a min/max expression in the same position as the target table's partition column. -HINT: Ensure the target table's partition column has a corresponding simple column reference to a distributed table's partition column in the subquery. -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 0 with name 'part_col' -INSERT INTO text_table (part_col) SELECT NULLIF(part_col, 'metin') FROM text_table; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: Subquery contains an expression that is not a simple column reference in the same position as the target table's partition column. -HINT: Ensure the target table's partition column has a corresponding simple column reference to a distributed table's partition column in the subquery. -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 0 with name 'part_col' -INSERT INTO text_table (part_col) SELECT part_col isnull FROM text_table; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: Subquery contains an expression that is not a simple column reference in the same position as the target table's partition column. -HINT: Ensure the target table's partition column has a corresponding simple column reference to a distributed table's partition column in the subquery. -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 0 with name 'part_col' -INSERT INTO text_table (part_col) SELECT part_col::text from char_table; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: Subquery contains an explicit coercion in the same position as the target table's partition column. -HINT: Ensure the target table's partition column has a corresponding simple column reference to a distributed table's partition column in the subquery. -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 0 with name 'part_col' -INSERT INTO text_table (part_col) SELECT (part_col = 'burak') is true FROM text_table; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: Subquery contains an expression that is not a simple column reference in the same position as the target table's partition column. -HINT: Ensure the target table's partition column has a corresponding simple column reference to a distributed table's partition column in the subquery. -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 0 with name 'part_col' -INSERT INTO text_table (part_col) SELECT val FROM text_table; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: The data type of the target table's partition column should exactly match the data type of the corresponding simple column reference in the subquery. -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 0 with name 'part_col' -INSERT INTO text_table (part_col) SELECT val::text FROM text_table; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: Subquery contains an explicit coercion in the same position as the target table's partition column. -HINT: Ensure the target table's partition column has a corresponding simple column reference to a distributed table's partition column in the subquery. -DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: performing repartitioned INSERT ... SELECT -DEBUG: partitioning SELECT query by column index 0 with name 'part_col' -RESET client_min_messages; -insert into table_with_starts_with_defaults (b,c) select b,c FROM table_with_starts_with_defaults; --- Test on partition column without native hash function -CREATE TABLE raw_table -( - id BIGINT, - time DATE -); -CREATE TABLE summary_table -( - time DATE, - count BIGINT -); -SELECT create_distributed_table('raw_table', 'time'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -SELECT create_distributed_table('summary_table', 'time'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO raw_table VALUES(1, '11-11-1980'); -INSERT INTO summary_table SELECT time, COUNT(*) FROM raw_table GROUP BY time; -SELECT * FROM summary_table; - time | count ---------------------------------------------------------------------- - 11-11-1980 | 1 -(1 row) - --- Test INSERT ... SELECT via coordinator --- Select from constants -TRUNCATE raw_events_first; -INSERT INTO raw_events_first (user_id, value_1) -SELECT * FROM (VALUES (1,2), (3,4), (5,6)) AS v(int,int); -SELECT user_id, value_1 FROM raw_events_first ORDER BY user_id; - user_id | value_1 ---------------------------------------------------------------------- - 1 | 2 - 3 | 4 - 5 | 6 -(3 rows) - --- Select from local functions -TRUNCATE raw_events_first; -CREATE SEQUENCE insert_select_test_seq; -SET client_min_messages TO DEBUG; -INSERT INTO raw_events_first (user_id, value_1, value_2) -SELECT - s, nextval('insert_select_test_seq'), (random()*10)::int -FROM - generate_series(1, 5) s; -DEBUG: Creating router plan -DEBUG: distributed INSERT ... SELECT can only select from distributed tables -DEBUG: Collecting INSERT ... SELECT results on coordinator -SELECT user_id, value_1 FROM raw_events_first ORDER BY user_id, value_1; -DEBUG: Router planner cannot handle multi-shard select queries - user_id | value_1 ---------------------------------------------------------------------- - 1 | 1 - 2 | 2 - 3 | 3 - 4 | 4 - 5 | 5 -(5 rows) - --- ON CONFLICT is supported -INSERT INTO raw_events_first (user_id, value_1) -SELECT s, nextval('insert_select_test_seq') FROM generate_series(1, 5) s -ON CONFLICT DO NOTHING; -DEBUG: Creating router plan -DEBUG: distributed INSERT ... SELECT can only select from distributed tables -DEBUG: Collecting INSERT ... SELECT results on coordinator -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_first_13300000 AS citus_table_alias (user_id, value_1) SELECT user_id, value_1 FROM read_intermediate_result('insert_select_XXX_13300000'::text, 'binary'::citus_copy_format) intermediate_result(user_id integer, value_1 integer) ON CONFLICT DO NOTHING -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_first_13300001 AS citus_table_alias (user_id, value_1) SELECT user_id, value_1 FROM read_intermediate_result('insert_select_XXX_13300001'::text, 'binary'::citus_copy_format) intermediate_result(user_id integer, value_1 integer) ON CONFLICT DO NOTHING -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_first_13300002 AS citus_table_alias (user_id, value_1) SELECT user_id, value_1 FROM read_intermediate_result('insert_select_XXX_13300002'::text, 'binary'::citus_copy_format) intermediate_result(user_id integer, value_1 integer) ON CONFLICT DO NOTHING -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_first_13300003 AS citus_table_alias (user_id, value_1) SELECT user_id, value_1 FROM read_intermediate_result('insert_select_XXX_13300003'::text, 'binary'::citus_copy_format) intermediate_result(user_id integer, value_1 integer) ON CONFLICT DO NOTHING --- RETURNING is supported -INSERT INTO raw_events_first (user_id, value_1) -SELECT s, nextval('insert_select_test_seq') FROM generate_series(1, 5) s -RETURNING *; -DEBUG: Creating router plan -DEBUG: distributed INSERT ... SELECT can only select from distributed tables -DEBUG: Collecting INSERT ... SELECT results on coordinator -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_first_13300000 AS citus_table_alias (user_id, value_1) SELECT user_id, value_1 FROM read_intermediate_result('insert_select_XXX_13300000'::text, 'binary'::citus_copy_format) intermediate_result(user_id integer, value_1 integer) RETURNING citus_table_alias.user_id, citus_table_alias."time", citus_table_alias.value_1, citus_table_alias.value_2, citus_table_alias.value_3, citus_table_alias.value_4 -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_first_13300001 AS citus_table_alias (user_id, value_1) SELECT user_id, value_1 FROM read_intermediate_result('insert_select_XXX_13300001'::text, 'binary'::citus_copy_format) intermediate_result(user_id integer, value_1 integer) RETURNING citus_table_alias.user_id, citus_table_alias."time", citus_table_alias.value_1, citus_table_alias.value_2, citus_table_alias.value_3, citus_table_alias.value_4 -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_first_13300002 AS citus_table_alias (user_id, value_1) SELECT user_id, value_1 FROM read_intermediate_result('insert_select_XXX_13300002'::text, 'binary'::citus_copy_format) intermediate_result(user_id integer, value_1 integer) RETURNING citus_table_alias.user_id, citus_table_alias."time", citus_table_alias.value_1, citus_table_alias.value_2, citus_table_alias.value_3, citus_table_alias.value_4 -DEBUG: distributed statement: INSERT INTO multi_insert_select.raw_events_first_13300003 AS citus_table_alias (user_id, value_1) SELECT user_id, value_1 FROM read_intermediate_result('insert_select_XXX_13300003'::text, 'binary'::citus_copy_format) intermediate_result(user_id integer, value_1 integer) RETURNING citus_table_alias.user_id, citus_table_alias."time", citus_table_alias.value_1, citus_table_alias.value_2, citus_table_alias.value_3, citus_table_alias.value_4 - user_id | time | value_1 | value_2 | value_3 | value_4 ---------------------------------------------------------------------- - 1 | | 11 | | | - 2 | | 12 | | | - 3 | | 13 | | | - 4 | | 14 | | | - 5 | | 15 | | | -(5 rows) - -RESET client_min_messages; --- INSERT ... SELECT and multi-shard SELECT in the same transaction is supported -TRUNCATE raw_events_first; -BEGIN; -INSERT INTO raw_events_first (user_id, value_1) -SELECT s, s FROM generate_series(1, 5) s; -SELECT user_id, value_1 FROM raw_events_first ORDER BY 1; - user_id | value_1 ---------------------------------------------------------------------- - 1 | 1 - 2 | 2 - 3 | 3 - 4 | 4 - 5 | 5 -(5 rows) - -ROLLBACK; --- INSERT ... SELECT and single-shard SELECT in the same transaction is supported -TRUNCATE raw_events_first; -BEGIN; -INSERT INTO raw_events_first (user_id, value_1) -SELECT s, s FROM generate_series(1, 5) s; -SELECT user_id, value_1 FROM raw_events_first WHERE user_id = 1; - user_id | value_1 ---------------------------------------------------------------------- - 1 | 1 -(1 row) - -COMMIT; --- Select from local table -TRUNCATE raw_events_first; -CREATE TEMPORARY TABLE raw_events_first_local AS -SELECT s AS u, 2*s AS v FROM generate_series(1, 5) s; -INSERT INTO raw_events_first (user_id, value_1) -SELECT u, v FROM raw_events_first_local; -SELECT user_id, value_1 FROM raw_events_first ORDER BY user_id, value_1; - user_id | value_1 ---------------------------------------------------------------------- - 1 | 2 - 2 | 4 - 3 | 6 - 4 | 8 - 5 | 10 -(5 rows) - --- Use columns in opposite order -TRUNCATE raw_events_first; -INSERT INTO raw_events_first (value_1, user_id) -SELECT u, v FROM raw_events_first_local; -SELECT user_id, value_1 FROM raw_events_first ORDER BY user_id, value_1; - user_id | value_1 ---------------------------------------------------------------------- - 2 | 1 - 4 | 2 - 6 | 3 - 8 | 4 - 10 | 5 -(5 rows) - --- Set operations can work with opposite column order -TRUNCATE raw_events_first; -INSERT INTO raw_events_first (value_3, user_id) -( SELECT v, u::bigint FROM raw_events_first_local ) -UNION ALL -( SELECT v, u FROM raw_events_first_local ); -SELECT user_id, value_3 FROM raw_events_first ORDER BY user_id, value_3; - user_id | value_3 ---------------------------------------------------------------------- - 1 | 2 - 1 | 2 - 2 | 4 - 2 | 4 - 3 | 6 - 3 | 6 - 4 | 8 - 4 | 8 - 5 | 10 - 5 | 10 -(10 rows) - --- Select from other distributed table with limit -TRUNCATE raw_events_first; -TRUNCATE raw_events_second; -INSERT INTO raw_events_second (user_id, value_4) -SELECT s, 3*s FROM generate_series (1,5) s; -INSERT INTO raw_events_first (user_id, value_1) -SELECT user_id, value_4 FROM raw_events_second LIMIT 5; -SELECT user_id, value_1 FROM raw_events_first ORDER BY user_id, value_1; - user_id | value_1 ---------------------------------------------------------------------- - 1 | 3 - 2 | 6 - 3 | 9 - 4 | 12 - 5 | 15 -(5 rows) - --- CTEs are supported in local queries -TRUNCATE raw_events_first; -WITH removed_rows AS ( - DELETE FROM raw_events_first_local RETURNING u -) -INSERT INTO raw_events_first (user_id, value_1) -WITH value AS (SELECT 1) -SELECT * FROM removed_rows, value; -SELECT user_id, value_1 FROM raw_events_first ORDER BY user_id, value_1; - user_id | value_1 ---------------------------------------------------------------------- - 1 | 1 - 2 | 1 - 3 | 1 - 4 | 1 - 5 | 1 -(5 rows) - --- nested CTEs are also supported -TRUNCATE raw_events_first; -INSERT INTO raw_events_first_local SELECT s, 2*s FROM generate_series(0, 10) s; -WITH rows_to_remove AS ( - SELECT u FROM raw_events_first_local WHERE u > 0 -), -removed_rows AS ( - DELETE FROM raw_events_first_local - WHERE u IN (SELECT * FROM rows_to_remove) - RETURNING u, v -) -INSERT INTO raw_events_first (user_id, value_1) -WITH ultra_rows AS ( - WITH numbers AS ( - SELECT s FROM generate_series(1,10) s - ), - super_rows AS ( - SELECT u, v FROM removed_rows JOIN numbers ON (u = s) - ) - SELECT * FROM super_rows LIMIT 5 -) -SELECT u, v FROM ultra_rows; -SELECT user_id, value_1 FROM raw_events_first ORDER BY user_id, value_1; - user_id | value_1 ---------------------------------------------------------------------- - 1 | 2 - 2 | 4 - 3 | 6 - 4 | 8 - 5 | 10 -(5 rows) - --- CTEs with duplicate names are also supported -TRUNCATE raw_events_first; -WITH super_rows AS ( - SELECT u FROM raw_events_first_local -) -INSERT INTO raw_events_first (user_id, value_1) -WITH super_rows AS ( - SELECT * FROM super_rows GROUP BY u -) -SELECT u, 5 FROM super_rows; -SELECT user_id, value_1 FROM raw_events_first ORDER BY user_id, value_1; - user_id | value_1 ---------------------------------------------------------------------- - 0 | 5 -(1 row) - --- CTEs are supported in router queries -TRUNCATE raw_events_first; -WITH user_two AS ( - SELECT user_id, value_4 FROM raw_events_second WHERE user_id = 2 -) -INSERT INTO raw_events_first (user_id, value_1) -SELECT * FROM user_two; -SELECT user_id, value_1 FROM raw_events_first ORDER BY user_id, value_1; - user_id | value_1 ---------------------------------------------------------------------- - 2 | 6 -(1 row) - --- CTEs are supported when there are name collisions -WITH numbers AS ( - SELECT s FROM generate_series(1,10) s -) -INSERT INTO raw_events_first(user_id, value_1) -WITH numbers AS ( - SELECT s, s FROM generate_series(1,5) s -) -SELECT * FROM numbers; --- Select into distributed table with a sequence -CREATE TABLE "CaseSensitiveTable" ("UserID" int, "Value1" int); -SELECT create_distributed_table('"CaseSensitiveTable"', 'UserID'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO "CaseSensitiveTable" -SELECT s, s FROM generate_series(1,10) s; -SELECT * FROM "CaseSensitiveTable" ORDER BY "UserID"; - UserID | Value1 ---------------------------------------------------------------------- - 1 | 1 - 2 | 2 - 3 | 3 - 4 | 4 - 5 | 5 - 6 | 6 - 7 | 7 - 8 | 8 - 9 | 9 - 10 | 10 -(10 rows) - -DROP TABLE "CaseSensitiveTable"; --- Select into distributed table with a sequence -CREATE TABLE dist_table_with_sequence (user_id serial, value_1 serial); -SELECT create_distributed_table('dist_table_with_sequence', 'user_id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - --- from local query -INSERT INTO dist_table_with_sequence (value_1) -SELECT s FROM generate_series(1,5) s; -SELECT * FROM dist_table_with_sequence ORDER BY user_id, value_1; - user_id | value_1 ---------------------------------------------------------------------- - 1 | 1 - 2 | 2 - 3 | 3 - 4 | 4 - 5 | 5 -(5 rows) - --- from a distributed query -INSERT INTO dist_table_with_sequence (value_1) -SELECT value_1 FROM dist_table_with_sequence ORDER BY value_1; -SELECT * FROM dist_table_with_sequence ORDER BY user_id, value_1; - user_id | value_1 ---------------------------------------------------------------------- - 1 | 1 - 2 | 2 - 3 | 3 - 4 | 4 - 5 | 5 - 6 | 1 - 7 | 2 - 8 | 3 - 9 | 4 - 10 | 5 -(10 rows) - -TRUNCATE dist_table_with_sequence; -INSERT INTO dist_table_with_sequence (user_id) -SELECT user_id FROM raw_events_second ORDER BY user_id; -SELECT * FROM dist_table_with_sequence ORDER BY user_id, value_1; - user_id | value_1 ---------------------------------------------------------------------- - 1 | 1 - 2 | 2 - 3 | 3 - 4 | 4 - 5 | 5 -(5 rows) - -WITH top10 AS ( - SELECT user_id FROM raw_events_second WHERE value_1 IS NOT NULL ORDER BY value_1 LIMIT 10 -) -INSERT INTO dist_table_with_sequence (value_1) -SELECT * FROM top10; -SELECT * FROM dist_table_with_sequence ORDER BY user_id, value_1; - user_id | value_1 ---------------------------------------------------------------------- - 1 | 1 - 2 | 2 - 3 | 3 - 4 | 4 - 5 | 5 -(5 rows) - --- router queries become logical planner queries when there is a nextval call -INSERT INTO dist_table_with_sequence (user_id) -SELECT user_id FROM dist_table_with_sequence WHERE user_id = 1; -SELECT * FROM dist_table_with_sequence ORDER BY user_id, value_1; - user_id | value_1 ---------------------------------------------------------------------- - 1 | 1 - 1 | 6 - 2 | 2 - 3 | 3 - 4 | 4 - 5 | 5 -(6 rows) - -DROP TABLE dist_table_with_sequence; --- Select into distributed table with a user-defined sequence -CREATE SEQUENCE seq1; -CREATE SEQUENCE seq2; -CREATE TABLE dist_table_with_user_sequence (user_id int default nextval('seq1'), value_1 bigint default nextval('seq2')); -SELECT create_distributed_table('dist_table_with_user_sequence', 'user_id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - --- from local query -INSERT INTO dist_table_with_user_sequence (value_1) -SELECT s FROM generate_series(1,5) s; -SELECT * FROM dist_table_with_user_sequence ORDER BY user_id, value_1; - user_id | value_1 ---------------------------------------------------------------------- - 1 | 1 - 2 | 2 - 3 | 3 - 4 | 4 - 5 | 5 -(5 rows) - --- from a distributed query -INSERT INTO dist_table_with_user_sequence (value_1) -SELECT value_1 FROM dist_table_with_user_sequence ORDER BY value_1; -SELECT * FROM dist_table_with_user_sequence ORDER BY user_id, value_1; - user_id | value_1 ---------------------------------------------------------------------- - 1 | 1 - 2 | 2 - 3 | 3 - 4 | 4 - 5 | 5 - 6 | 1 - 7 | 2 - 8 | 3 - 9 | 4 - 10 | 5 -(10 rows) - -TRUNCATE dist_table_with_user_sequence; -INSERT INTO dist_table_with_user_sequence (user_id) -SELECT user_id FROM raw_events_second ORDER BY user_id; -SELECT * FROM dist_table_with_user_sequence ORDER BY user_id, value_1; - user_id | value_1 ---------------------------------------------------------------------- - 1 | 1 - 2 | 2 - 3 | 3 - 4 | 4 - 5 | 5 -(5 rows) - -WITH top10 AS ( - SELECT user_id FROM raw_events_second WHERE value_1 IS NOT NULL ORDER BY value_1 LIMIT 10 -) -INSERT INTO dist_table_with_user_sequence (value_1) -SELECT * FROM top10; -SELECT * FROM dist_table_with_user_sequence ORDER BY user_id, value_1; - user_id | value_1 ---------------------------------------------------------------------- - 1 | 1 - 2 | 2 - 3 | 3 - 4 | 4 - 5 | 5 -(5 rows) - --- router queries become logical planner queries when there is a nextval call -INSERT INTO dist_table_with_user_sequence (user_id) -SELECT user_id FROM dist_table_with_user_sequence WHERE user_id = 1; -SELECT * FROM dist_table_with_user_sequence ORDER BY user_id, value_1; - user_id | value_1 ---------------------------------------------------------------------- - 1 | 1 - 1 | 6 - 2 | 2 - 3 | 3 - 4 | 4 - 5 | 5 -(6 rows) - -DROP TABLE dist_table_with_user_sequence; -DROP SEQUENCE seq1, seq2; --- Select from distributed table into reference table -CREATE TABLE ref_table (user_id serial, value_1 int); -SELECT create_reference_table('ref_table'); - create_reference_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO ref_table -SELECT user_id, value_1 FROM raw_events_second; -SELECT * FROM ref_table ORDER BY user_id, value_1; - user_id | value_1 ---------------------------------------------------------------------- - 1 | - 2 | - 3 | - 4 | - 5 | -(5 rows) - -INSERT INTO ref_table (value_1) -SELECT value_1 FROM raw_events_second ORDER BY value_1; -SELECT * FROM ref_table ORDER BY user_id, value_1; - user_id | value_1 ---------------------------------------------------------------------- - 1 | - 1 | - 2 | - 2 | - 3 | - 3 | - 4 | - 4 | - 5 | - 5 | -(10 rows) - -INSERT INTO ref_table SELECT * FROM ref_table; -SELECT * FROM ref_table ORDER BY user_id, value_1; - user_id | value_1 ---------------------------------------------------------------------- - 1 | - 1 | - 1 | - 1 | - 2 | - 2 | - 2 | - 2 | - 3 | - 3 | - 3 | - 3 | - 4 | - 4 | - 4 | - 4 | - 5 | - 5 | - 5 | - 5 | -(20 rows) - -DROP TABLE ref_table; --- Select from distributed table into reference table with user-defined sequence -CREATE SEQUENCE seq1; -CREATE TABLE ref_table_with_user_sequence (user_id int default nextval('seq1'), value_1 int); -SELECT create_reference_table('ref_table_with_user_sequence'); - create_reference_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO ref_table_with_user_sequence -SELECT user_id, value_1 FROM raw_events_second; -SELECT * FROM ref_table_with_user_sequence ORDER BY user_id, value_1; - user_id | value_1 ---------------------------------------------------------------------- - 1 | - 2 | - 3 | - 4 | - 5 | -(5 rows) - -INSERT INTO ref_table_with_user_sequence (value_1) -SELECT value_1 FROM raw_events_second ORDER BY value_1; -SELECT * FROM ref_table_with_user_sequence ORDER BY user_id, value_1; - user_id | value_1 ---------------------------------------------------------------------- - 1 | - 1 | - 2 | - 2 | - 3 | - 3 | - 4 | - 4 | - 5 | - 5 | -(10 rows) - -INSERT INTO ref_table_with_user_sequence SELECT * FROM ref_table_with_user_sequence; -SELECT * FROM ref_table_with_user_sequence ORDER BY user_id, value_1; - user_id | value_1 ---------------------------------------------------------------------- - 1 | - 1 | - 1 | - 1 | - 2 | - 2 | - 2 | - 2 | - 3 | - 3 | - 3 | - 3 | - 4 | - 4 | - 4 | - 4 | - 5 | - 5 | - 5 | - 5 | -(20 rows) - -DROP TABLE ref_table_with_user_sequence; -DROP SEQUENCE seq1; --- Select from reference table into reference table -CREATE TABLE ref1 (d timestamptz); -SELECT create_reference_table('ref1'); - create_reference_table ---------------------------------------------------------------------- - -(1 row) - -CREATE TABLE ref2 (d date); -SELECT create_reference_table('ref2'); - create_reference_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO ref2 VALUES ('2017-10-31'); -INSERT INTO ref1 SELECT * FROM ref2; -SELECT count(*) from ref1; - count ---------------------------------------------------------------------- - 1 -(1 row) - --- also test with now() -INSERT INTO ref1 SELECT now() FROM ref2; -SELECT count(*) from ref1; - count ---------------------------------------------------------------------- - 2 -(1 row) - -DROP TABLE ref1; -DROP TABLE ref2; --- Select into an append-partitioned table is not supported -CREATE TABLE insert_append_table (user_id int, value_4 bigint); -SELECT create_distributed_table('insert_append_table', 'user_id', 'append'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO insert_append_table (user_id, value_4) -SELECT user_id, 1 FROM raw_events_second LIMIT 5; -ERROR: INSERT ... SELECT into an append-distributed table is not supported -DROP TABLE insert_append_table; --- Insert from other distributed table as prepared statement -TRUNCATE raw_events_first; -PREPARE insert_prep(int) AS -INSERT INTO raw_events_first (user_id, value_1) -SELECT $1, value_4 FROM raw_events_second ORDER BY value_4 LIMIT 1; -EXECUTE insert_prep(1); -EXECUTE insert_prep(2); -EXECUTE insert_prep(3); -EXECUTE insert_prep(4); -EXECUTE insert_prep(5); -EXECUTE insert_prep(6); -SELECT user_id, value_1 FROM raw_events_first ORDER BY user_id, value_1; - user_id | value_1 ---------------------------------------------------------------------- - 1 | 3 - 2 | 3 - 3 | 3 - 4 | 3 - 5 | 3 - 6 | 3 -(6 rows) - --- Inserting into views is handled via coordinator -TRUNCATE raw_events_first; -INSERT INTO test_view -SELECT * FROM raw_events_second; -SELECT user_id, value_4 FROM test_view ORDER BY user_id, value_4; - user_id | value_4 ---------------------------------------------------------------------- - 1 | 3 - 2 | 6 - 3 | 9 - 4 | 12 - 5 | 15 -(5 rows) - --- Drop the view now, because the column we are about to drop depends on it -DROP VIEW test_view; --- Make sure we handle dropped columns correctly -CREATE TABLE drop_col_table (col1 text, col2 text, col3 text); -SELECT create_distributed_table('drop_col_table', 'col2'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -ALTER TABLE drop_col_table DROP COLUMN col1; -INSERT INTO drop_col_table (col3, col2) -SELECT value_4, user_id FROM raw_events_second LIMIT 5; -SELECT * FROM drop_col_table ORDER BY col2, col3; - col2 | col3 ---------------------------------------------------------------------- - 1 | 3 - 2 | 6 - 3 | 9 - 4 | 12 - 5 | 15 -(5 rows) - --- make sure the tuple went to the right shard -SELECT * FROM drop_col_table WHERE col2 = '1'; - col2 | col3 ---------------------------------------------------------------------- - 1 | 3 -(1 row) - -RESET client_min_messages; --- make sure casts are handled correctly -CREATE TABLE coerce_events(user_id int, time timestamp, value_1 numeric); -SELECT create_distributed_table('coerce_events', 'user_id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -CREATE TABLE coerce_agg (user_id int, value_1_agg int); -SELECT create_distributed_table('coerce_agg', 'user_id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO coerce_events(user_id, value_1) VALUES (1, 1), (2, 2), (10, 10); --- numeric -> int (straight function) -INSERT INTO coerce_agg(user_id, value_1_agg) -SELECT * -FROM ( - SELECT user_id, value_1 - FROM coerce_events -) AS ftop -ORDER BY 2 DESC, 1 DESC -LIMIT 5; --- int -> text -ALTER TABLE coerce_agg ALTER COLUMN value_1_agg TYPE text; -INSERT INTO coerce_agg(user_id, value_1_agg) -SELECT * -FROM ( - SELECT user_id, value_1 - FROM coerce_events -) AS ftop -LIMIT 5; -SELECT * FROM coerce_agg ORDER BY 1 DESC, 2 DESC; - user_id | value_1_agg ---------------------------------------------------------------------- - 10 | 10 - 10 | 10 - 2 | 2 - 2 | 2 - 1 | 1 - 1 | 1 -(6 rows) - -TRUNCATE coerce_agg; --- int -> char(1) -ALTER TABLE coerce_agg ALTER COLUMN value_1_agg TYPE char(1); -INSERT INTO coerce_agg(user_id, value_1_agg) -SELECT * -FROM ( - SELECT user_id, value_1 - FROM coerce_events -) AS ftop -LIMIT 5; -ERROR: value too long for type character(1) -SELECT * FROM coerce_agg ORDER BY 1 DESC, 2 DESC; - user_id | value_1_agg ---------------------------------------------------------------------- -(0 rows) - -TRUNCATE coerce_agg; -TRUNCATE coerce_events; --- char(5) -> char(1) -ALTER TABLE coerce_events ALTER COLUMN value_1 TYPE char(5); -INSERT INTO coerce_events(user_id, value_1) VALUES (1, 'aaaaa'), (2, 'bbbbb'); -INSERT INTO coerce_agg(user_id, value_1_agg) -SELECT * -FROM ( - SELECT user_id, value_1 - FROM coerce_events -) AS ftop -LIMIT 5; -ERROR: value too long for type character(1) --- char(1) -> char(5) -ALTER TABLE coerce_events ALTER COLUMN value_1 TYPE char(1) USING value_1::char(1); -ALTER TABLE coerce_agg ALTER COLUMN value_1_agg TYPE char(5); -INSERT INTO coerce_agg(user_id, value_1_agg) -SELECT * -FROM ( - SELECT user_id, value_1 - FROM coerce_events -) AS ftop -LIMIT 5; -SELECT * FROM coerce_agg ORDER BY 1 DESC, 2 DESC; - user_id | value_1_agg ---------------------------------------------------------------------- - 2 | b - 1 | a -(2 rows) - -TRUNCATE coerce_agg; -TRUNCATE coerce_events; --- integer -> integer (check VALUE < 5) -ALTER TABLE coerce_events ALTER COLUMN value_1 TYPE integer USING NULL; -ALTER TABLE coerce_agg ALTER COLUMN value_1_agg TYPE integer USING NULL; -ALTER TABLE coerce_agg ADD CONSTRAINT small_number CHECK (value_1_agg < 5); -INSERT INTO coerce_events (user_id, value_1) VALUES (1, 1), (10, 10); -\set VERBOSITY TERSE -INSERT INTO coerce_agg(user_id, value_1_agg) -SELECT * -FROM ( - SELECT user_id, value_1 - FROM coerce_events -) AS ftop; -ERROR: new row for relation "coerce_agg_13300067" violates check constraint "small_number_13300067" -\set VERBOSITY DEFAULT -SELECT * FROM coerce_agg ORDER BY 1 DESC, 2 DESC; - user_id | value_1_agg ---------------------------------------------------------------------- -(0 rows) - --- integer[3] -> text[3] -TRUNCATE coerce_events; -ALTER TABLE coerce_events ALTER COLUMN value_1 TYPE integer[3] USING NULL; -INSERT INTO coerce_events(user_id, value_1) VALUES (1, '{1,1,1}'), (2, '{2,2,2}'); -ALTER TABLE coerce_agg DROP COLUMN value_1_agg; -ALTER TABLE coerce_agg ADD COLUMN value_1_agg text[3]; -INSERT INTO coerce_agg(user_id, value_1_agg) -SELECT * -FROM ( - SELECT user_id, value_1 - FROM coerce_events -) AS ftop -LIMIT 5; -SELECT * FROM coerce_agg ORDER BY 1 DESC, 2 DESC; - user_id | value_1_agg ---------------------------------------------------------------------- - 2 | {2,2,2} - 1 | {1,1,1} -(2 rows) - --- INSERT..SELECT + prepared statements + recursive planning -BEGIN; -PREPARE prepared_recursive_insert_select AS -INSERT INTO users_table -SELECT * FROM users_table -WHERE value_1 IN (SELECT value_2 FROM events_table OFFSET 0); -EXECUTE prepared_recursive_insert_select; -EXECUTE prepared_recursive_insert_select; -EXECUTE prepared_recursive_insert_select; -EXECUTE prepared_recursive_insert_select; -EXECUTE prepared_recursive_insert_select; -EXECUTE prepared_recursive_insert_select; -ROLLBACK; --- upsert with on conflict update distribution column is unsupported -INSERT INTO agg_events AS ae - ( - user_id, - value_1_agg, - agg_time - ) -SELECT user_id, - value_1, - time -FROM raw_events_first -ON conflict (user_id, value_1_agg) -DO UPDATE - SET user_id = 42 -RETURNING user_id, value_1_agg; -ERROR: modifying the partition value of rows is not allowed --- test a small citus.remote_copy_flush_threshold -BEGIN; -SET LOCAL citus.remote_copy_flush_threshold TO 1; -INSERT INTO raw_events_first -SELECT * FROM raw_events_first OFFSET 0 -ON CONFLICT DO NOTHING; -ABORT; --- test fix for issue https://github.com/citusdata/citus/issues/5891 -CREATE TABLE dist_table_1( -dist_col integer, -int_col integer, -text_col_1 text, -text_col_2 text -); -SELECT create_distributed_table('dist_table_1', 'dist_col'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO dist_table_1 VALUES (1, 1, 'string', 'string'); -CREATE TABLE dist_table_2( -dist_col integer, -int_col integer -); -SELECT create_distributed_table('dist_table_2', 'dist_col'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO dist_table_2 VALUES (1, 1); -with a as (select random()) INSERT INTO dist_table_1 -SELECT -t1.dist_col, -1, -'string', -'string' -FROM a, dist_table_1 t1 -join dist_table_2 t2 using (dist_col) -limit 1 -returning text_col_1; - text_col_1 ---------------------------------------------------------------------- - string -(1 row) - -CREATE TABLE dist_table_3( -dist_col bigint, -int_col integer -); -SELECT create_distributed_table('dist_table_3', 'dist_col'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - --- dist_table_2 and dist_table_3 are non-colocated source tables. Repartitioning is also not possible due to --- different types for distribution columns. Citus would not be able to handle this complex insert select. -INSERT INTO dist_table_1 SELECT dist_table_2.dist_col FROM dist_table_2 JOIN dist_table_3 USING(dist_col); -ERROR: complex joins are only supported when all distributed tables are joined on their distribution columns with equal operator -CREATE TABLE dist_table_4( -dist_col integer, -int_col integer -); -SELECT create_distributed_table('dist_table_4', 'dist_col'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - --- Even if target table distribution column is colocated with dist_table_2's distributed column, source tables dist_table_2 and dist_table_4 --- are non-colocated. Hence, SELECT part of the query should be pulled to coordinator. -SELECT coordinator_plan($$ - EXPLAIN (COSTS FALSE) INSERT INTO dist_table_1 SELECT dist_table_2.dist_col FROM dist_table_2 JOIN dist_table_4 ON dist_table_2.dist_col = dist_table_4.int_col; -$$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> Custom Scan (Citus Adaptive) - Task Count: 6 -(4 rows) - --- For INSERT SELECT, when a lateral query references an outer query, push-down is possible even if limit clause exists in the lateral query. --- It is because subquery with limit does not need to be merged at coordinator as it is a lateral query. -SELECT coordinator_plan($$ - EXPLAIN (COSTS FALSE) INSERT INTO dist_table_1 SELECT d1.dist_col FROM dist_table_1 d1 LEFT JOIN LATERAL (SELECT * FROM dist_table_2 d2 WHERE d1.dist_col = d2.dist_col LIMIT 3) dummy USING(dist_col); -$$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus Adaptive) - Task Count: 4 -(2 rows) - --- For INSERT SELECT, when push-down is NOT possible when limit clause exists in a subquery at SELECT part of INSERT SELECT. --- It is because the subquery with limit needs to be merged at coordinator. -SELECT coordinator_plan($$ - EXPLAIN (COSTS FALSE) INSERT INTO dist_table_1 SELECT d1.dist_col FROM dist_table_1 d1 LEFT JOIN (SELECT * FROM dist_table_2 LIMIT 3) dummy USING(dist_col); -$$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: repartition - -> Custom Scan (Citus Adaptive) - -> Distributed Subplan XXX_1 - -> Limit - -> Custom Scan (Citus Adaptive) - Task Count: 4 -(7 rows) - -CREATE TABLE dist_table_5(id int, id2 int); -SELECT create_distributed_table('dist_table_5','id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -CREATE TABLE dist_table_6(id int, id2 int); -SELECT create_distributed_table('dist_table_6','id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - --- verify that insert select with union can be pushed down since UNION clause has FROM clause at top level query. -SELECT coordinator_plan($$ - EXPLAIN (COSTS FALSE) INSERT INTO dist_table_5(id) SELECT id FROM (SELECT id FROM dist_table_5 UNION SELECT id FROM dist_table_6) dummy; -$$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus Adaptive) - Task Count: 4 -(2 rows) - --- verify that insert select with sublink can be pushed down when tables are colocated. -SELECT coordinator_plan($$ - EXPLAIN (COSTS FALSE) INSERT INTO dist_table_5 SELECT id, (SELECT id FROM dist_table_5 WHERE dist_table_5.id = dist_table_6.id) FROM dist_table_6; -$$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus Adaptive) - Task Count: 4 -(2 rows) - -CREATE TABLE ref_table_1(id int); -SELECT create_reference_table('ref_table_1'); - create_reference_table ---------------------------------------------------------------------- - -(1 row) - --- verify that insert select with sublink cannot be pushed down when from clause does not contain any distributed relation. -INSERT INTO dist_table_5 SELECT id, (SELECT id FROM dist_table_5 WHERE dist_table_5.id = ref_table_1.id) FROM ref_table_1; -ERROR: correlated subqueries are not supported when the FROM clause contains a reference table --- verify that insert select cannot be pushed down when we have recurring range table in from clause. -SELECT coordinator_plan($$ - EXPLAIN (COSTS FALSE) INSERT INTO dist_table_5 SELECT id, (SELECT id FROM ref_table_1 WHERE id = 1) FROM ref_table_1; -$$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> Custom Scan (Citus Adaptive) - Task Count: 1 -(4 rows) - --- verify that insert select cannot be pushed down when we have reference table in outside of outer join. -SELECT coordinator_plan($$ - EXPLAIN (COSTS FALSE) INSERT INTO dist_table_5 SELECT a.id FROM dist_table_5 a LEFT JOIN ref_table_1 b ON (true) RIGHT JOIN ref_table_1 c ON (true); -$$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> Custom Scan (Citus Adaptive) - -> Distributed Subplan XXX_1 - -> Custom Scan (Citus Adaptive) - Task Count: 4 -(6 rows) - --- verify that insert select cannot be pushed down when it has a recurring outer join in a subquery. -SELECT coordinator_plan($$ - EXPLAIN (COSTS FALSE) INSERT INTO dist_table_5 SELECT id FROM ref_table_1 LEFT JOIN dist_table_5 USING(id); -$$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> Custom Scan (Citus Adaptive) - -> Distributed Subplan XXX_1 - -> Custom Scan (Citus Adaptive) - Task Count: 4 -(6 rows) - -CREATE TABLE loc_table_1(id int); --- verify that insert select cannot be pushed down when it contains join between local and distributed tables. -SELECT coordinator_plan($$ - EXPLAIN (COSTS FALSE) INSERT INTO dist_table_5 SELECT id FROM dist_table_5 JOIN loc_table_1 USING(id); -$$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: repartition - -> Custom Scan (Citus Adaptive) - -> Distributed Subplan XXX_1 - -> Seq Scan on loc_table_1 - Task Count: 4 -(6 rows) - -CREATE VIEW view_1 AS - SELECT id FROM dist_table_6; -CREATE MATERIALIZED VIEW view_2 AS - SELECT id FROM dist_table_6; --- verify that insert select cannot be pushed down when it contains view. -SELECT coordinator_plan($$ - EXPLAIN (COSTS FALSE) INSERT INTO dist_table_5 SELECT * FROM view_1; -$$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus Adaptive) - Task Count: 4 -(2 rows) - --- verify that insert select cannot be pushed down when it contains materialized view. -SELECT coordinator_plan($$ - EXPLAIN (COSTS FALSE) INSERT INTO dist_table_5 SELECT * FROM view_2; -$$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> Seq Scan on view_2 -(3 rows) - -CREATE TABLE append_table(id integer, data text, int_data int); -SELECT create_distributed_table('append_table', 'id', 'append'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -SELECT master_create_empty_shard('append_table'); - master_create_empty_shard ---------------------------------------------------------------------- - 13300096 -(1 row) - --- verify that insert select push down for append tables are not supported. -INSERT INTO append_table SELECT * FROM append_table; -ERROR: INSERT ... SELECT into an append-distributed table is not supported --- verify that CTEs at top level of INSERT SELECT, that can normally be inlined, would not be inlined by INSERT SELECT pushdown planner --- and handled by pull to coordinator. -SELECT coordinator_plan($$ - EXPLAIN (COSTS FALSE) WITH cte_1 AS (SELECT id FROM dist_table_5 WHERE id > 5) - INSERT INTO dist_table_5 - SELECT id FROM dist_table_5 JOIN cte_1 USING(id) OFFSET 5; -$$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: pull to coordinator - -> Custom Scan (Citus Adaptive) - -> Distributed Subplan XXX_1 - -> Limit - -> Custom Scan (Citus Adaptive) - Task Count: 4 -(7 rows) - --- verify that CTEs at top level of SELECT part, would be inlined by Postgres and pushed down by INSERT SELECT planner. -SELECT coordinator_plan($$ - EXPLAIN (COSTS FALSE) INSERT INTO dist_table_5 - WITH cte_1 AS (SELECT id FROM dist_table_5 WHERE id = 5) - SELECT id FROM dist_table_5 JOIN cte_1 USING(id); -$$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus Adaptive) - Task Count: 1 -(2 rows) - -SET client_min_messages TO ERROR; -DROP SCHEMA multi_insert_select CASCADE; diff --git a/src/test/regress/expected/multi_insert_select_conflict.out b/src/test/regress/expected/multi_insert_select_conflict.out index 5c06719d3..429ff024e 100644 --- a/src/test/regress/expected/multi_insert_select_conflict.out +++ b/src/test/regress/expected/multi_insert_select_conflict.out @@ -1,17 +1,6 @@ -- -- MULTI_INSERT_SELECT_CONFLICT -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - t -(1 row) - CREATE SCHEMA on_conflict; SET search_path TO on_conflict, public; SET citus.next_shard_id TO 1900000; diff --git a/src/test/regress/expected/multi_insert_select_conflict_0.out b/src/test/regress/expected/multi_insert_select_conflict_0.out deleted file mode 100644 index 4c2add1d7..000000000 --- a/src/test/regress/expected/multi_insert_select_conflict_0.out +++ /dev/null @@ -1,600 +0,0 @@ --- --- MULTI_INSERT_SELECT_CONFLICT --- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - f -(1 row) - -CREATE SCHEMA on_conflict; -SET search_path TO on_conflict, public; -SET citus.next_shard_id TO 1900000; -SET citus.shard_replication_factor TO 1; -CREATE TABLE target_table(col_1 int primary key, col_2 int); -SELECT create_distributed_table('target_table','col_1'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO target_table VALUES(1,2),(2,3),(3,4),(4,5),(5,6); -CREATE TABLE source_table_1(col_1 int primary key, col_2 int, col_3 int); -SELECT create_distributed_table('source_table_1','col_1'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO source_table_1 VALUES(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5); -CREATE TABLE source_table_2(col_1 int, col_2 int, col_3 int); -SELECT create_distributed_table('source_table_2','col_1'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO source_table_2 VALUES(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10); -SET client_min_messages to debug1; --- Generate series directly on the coordinator and on conflict do nothing -INSERT INTO target_table (col_1, col_2) -SELECT - s, s -FROM - generate_series(1,10) s -ON CONFLICT DO NOTHING; -DEBUG: distributed INSERT ... SELECT can only select from distributed tables -DEBUG: Collecting INSERT ... SELECT results on coordinator --- Generate series directly on the coordinator and on conflict update the target table -INSERT INTO target_table (col_1, col_2) -SELECT s, s -FROM - generate_series(1,10) s -ON CONFLICT(col_1) DO UPDATE SET col_2 = EXCLUDED.col_2 + 1; -DEBUG: distributed INSERT ... SELECT can only select from distributed tables -DEBUG: Collecting INSERT ... SELECT results on coordinator --- Since partition columns do not match, pull the data to the coordinator --- and do not change conflicted values -INSERT INTO target_table -SELECT - col_2, col_3 -FROM - source_table_1 -ON CONFLICT DO NOTHING; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: The target table's partition column should correspond to a partition column in the subquery. -DEBUG: performing repartitioned INSERT ... SELECT --- Since partition columns do not match, pull the data to the coordinator --- and update the non-partition column. Query is wrapped by CTE to return --- ordered result. -WITH inserted_table AS ( - INSERT INTO target_table - SELECT - col_2, col_3 - FROM - source_table_1 - ON CONFLICT(col_1) DO UPDATE SET col_2 = EXCLUDED.col_2 RETURNING * -) SELECT * FROM inserted_table ORDER BY 1; -DEBUG: generating subplan XXX_1 for CTE inserted_table: INSERT INTO on_conflict.target_table (col_1, col_2) SELECT col_2, col_3 FROM on_conflict.source_table_1 ON CONFLICT(col_1) DO UPDATE SET col_2 = excluded.col_2 RETURNING target_table.col_1, target_table.col_2 -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: The target table's partition column should correspond to a partition column in the subquery. -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT col_1, col_2 FROM (SELECT intermediate_result.col_1, intermediate_result.col_2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer)) inserted_table ORDER BY col_1 -DEBUG: performing repartitioned INSERT ... SELECT - col_1 | col_2 ---------------------------------------------------------------------- - 1 | 1 - 2 | 2 - 3 | 3 - 4 | 4 - 5 | 5 -(5 rows) - --- Subquery should be recursively planned due to the limit and do nothing on conflict -INSERT INTO target_table -SELECT - col_1, col_2 -FROM ( - SELECT - col_1, col_2, col_3 - FROM - source_table_1 - LIMIT 5 -) as foo -ON CONFLICT DO NOTHING; -DEBUG: cannot push down this subquery -DETAIL: Limit clause is currently unsupported when a subquery references a column from another query -DEBUG: push down of limit count: 5 -DEBUG: generating subplan XXX_1 for subquery SELECT col_1, col_2, col_3 FROM on_conflict.source_table_1 LIMIT 5 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT col_1, col_2 FROM (SELECT intermediate_result.col_1, intermediate_result.col_2, intermediate_result.col_3 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer, col_3 integer)) foo -DEBUG: Collecting INSERT ... SELECT results on coordinator --- Subquery should be recursively planned due to the limit and update on conflict --- Query is wrapped by CTE to return ordered result. -WITH inserted_table AS ( - INSERT INTO target_table - SELECT - col_1, col_2 - FROM ( - SELECT - col_1, col_2, col_3 - FROM - source_table_1 - LIMIT 5 - ) as foo - ON CONFLICT(col_1) DO UPDATE SET col_2 = EXCLUDED.col_2 RETURNING * -) SELECT * FROM inserted_table ORDER BY 1; -DEBUG: generating subplan XXX_1 for CTE inserted_table: INSERT INTO on_conflict.target_table (col_1, col_2) SELECT col_1, col_2 FROM (SELECT source_table_1.col_1, source_table_1.col_2, source_table_1.col_3 FROM on_conflict.source_table_1 LIMIT 5) foo ON CONFLICT(col_1) DO UPDATE SET col_2 = excluded.col_2 RETURNING target_table.col_1, target_table.col_2 -DEBUG: cannot push down this subquery -DETAIL: Limit clause is currently unsupported when a subquery references a column from another query -DEBUG: push down of limit count: 5 -DEBUG: generating subplan XXX_1 for subquery SELECT col_1, col_2, col_3 FROM on_conflict.source_table_1 LIMIT 5 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT col_1, col_2 FROM (SELECT intermediate_result.col_1, intermediate_result.col_2, intermediate_result.col_3 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer, col_3 integer)) foo -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT col_1, col_2 FROM (SELECT intermediate_result.col_1, intermediate_result.col_2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer)) inserted_table ORDER BY col_1 -DEBUG: Collecting INSERT ... SELECT results on coordinator - col_1 | col_2 ---------------------------------------------------------------------- - 1 | 1 - 2 | 2 - 3 | 3 - 4 | 4 - 5 | 5 -(5 rows) - --- Test with multiple subqueries. Query is wrapped by CTE to return ordered result. -WITH inserted_table AS ( - INSERT INTO target_table - SELECT - col_1, col_2 - FROM ( - (SELECT - col_1, col_2, col_3 - FROM - source_table_1 - LIMIT 5) - UNION - (SELECT - col_1, col_2, col_3 - FROM - source_table_2 - LIMIT 5) - ) as foo - ON CONFLICT(col_1) DO UPDATE SET col_2 = 0 RETURNING * -) SELECT * FROM inserted_table ORDER BY 1; -DEBUG: generating subplan XXX_1 for CTE inserted_table: INSERT INTO on_conflict.target_table (col_1, col_2) SELECT col_1, col_2 FROM ((SELECT source_table_1.col_1, source_table_1.col_2, source_table_1.col_3 FROM on_conflict.source_table_1 LIMIT 5) UNION (SELECT source_table_2.col_1, source_table_2.col_2, source_table_2.col_3 FROM on_conflict.source_table_2 LIMIT 5)) foo ON CONFLICT(col_1) DO UPDATE SET col_2 = 0 RETURNING target_table.col_1, target_table.col_2 -DEBUG: cannot push down this subquery -DETAIL: Limit clause is currently unsupported when a subquery references a column from another query -DEBUG: push down of limit count: 5 -DEBUG: generating subplan XXX_1 for subquery SELECT col_1, col_2, col_3 FROM on_conflict.source_table_1 LIMIT 5 -DEBUG: push down of limit count: 5 -DEBUG: generating subplan XXX_2 for subquery SELECT col_1, col_2, col_3 FROM on_conflict.source_table_2 LIMIT 5 -DEBUG: generating subplan XXX_3 for subquery SELECT intermediate_result.col_1, intermediate_result.col_2, intermediate_result.col_3 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer, col_3 integer) UNION SELECT intermediate_result.col_1, intermediate_result.col_2, intermediate_result.col_3 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer, col_3 integer) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT col_1, col_2 FROM (SELECT intermediate_result.col_1, intermediate_result.col_2, intermediate_result.col_3 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer, col_3 integer)) foo -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT col_1, col_2 FROM (SELECT intermediate_result.col_1, intermediate_result.col_2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer)) inserted_table ORDER BY col_1 -DEBUG: Collecting INSERT ... SELECT results on coordinator - col_1 | col_2 ---------------------------------------------------------------------- - 1 | 0 - 2 | 0 - 3 | 0 - 4 | 0 - 5 | 0 - 6 | 0 - 7 | 0 - 8 | 0 - 9 | 0 - 10 | 0 -(10 rows) - --- Get the select part from cte and do nothing on conflict -WITH cte AS MATERIALIZED ( - SELECT col_1, col_2 FROM source_table_1 -) -INSERT INTO target_table SELECT * FROM cte ON CONFLICT DO NOTHING; -DEBUG: distributed INSERT ... SELECT can only select from distributed tables -DEBUG: generating subplan XXX_1 for CTE cte: SELECT col_1, col_2 FROM on_conflict.source_table_1 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT col_1, col_2 FROM (SELECT cte.col_1, cte.col_2 FROM (SELECT intermediate_result.col_1, intermediate_result.col_2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer)) cte) citus_insert_select_subquery -DEBUG: Collecting INSERT ... SELECT results on coordinator --- Get the select part from cte and update on conflict -WITH cte AS MATERIALIZED ( - SELECT col_1, col_2 FROM source_table_1 -) -INSERT INTO target_table SELECT * FROM cte ON CONFLICT(col_1) DO UPDATE SET col_2 = EXCLUDED.col_2 + 1; -DEBUG: distributed INSERT ... SELECT can only select from distributed tables -DEBUG: generating subplan XXX_1 for CTE cte: SELECT col_1, col_2 FROM on_conflict.source_table_1 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT col_1, col_2 FROM (SELECT cte.col_1, cte.col_2 FROM (SELECT intermediate_result.col_1, intermediate_result.col_2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer)) cte) citus_insert_select_subquery -DEBUG: Collecting INSERT ... SELECT results on coordinator -SELECT * FROM target_table ORDER BY 1; - col_1 | col_2 ---------------------------------------------------------------------- - 1 | 2 - 2 | 3 - 3 | 4 - 4 | 5 - 5 | 6 - 6 | 0 - 7 | 0 - 8 | 0 - 9 | 0 - 10 | 0 -(10 rows) - --- Test with multiple CTEs -WITH cte AS( - SELECT col_1, col_2 FROM source_table_1 -), cte_2 AS( - SELECT col_1, col_2 FROM source_table_2 -) -INSERT INTO target_table ((SELECT * FROM cte) UNION (SELECT * FROM cte_2)) ON CONFLICT(col_1) DO UPDATE SET col_2 = EXCLUDED.col_2 + 1; -DEBUG: distributed INSERT ... SELECT can only select from distributed tables -DEBUG: CTE cte is going to be inlined via distributed planning -DEBUG: CTE cte_2 is going to be inlined via distributed planning -DEBUG: performing repartitioned INSERT ... SELECT -SELECT * FROM target_table ORDER BY 1; - col_1 | col_2 ---------------------------------------------------------------------- - 1 | 2 - 2 | 3 - 3 | 4 - 4 | 5 - 5 | 6 - 6 | 7 - 7 | 8 - 8 | 9 - 9 | 10 - 10 | 11 -(10 rows) - -WITH inserted_table AS MATERIALIZED ( - WITH cte AS MATERIALIZED ( - SELECT col_1, col_2, col_3 FROM source_table_1 - ), cte_2 AS MATERIALIZED ( - SELECT col_1, col_2 FROM cte - ) - INSERT INTO target_table SELECT * FROM cte_2 ON CONFLICT(col_1) DO UPDATE SET col_2 = EXCLUDED.col_2 + 1 RETURNING * -) SELECT * FROM inserted_table ORDER BY 1; -DEBUG: generating subplan XXX_1 for CTE inserted_table: WITH cte AS MATERIALIZED (SELECT source_table_1.col_1, source_table_1.col_2, source_table_1.col_3 FROM on_conflict.source_table_1), cte_2 AS MATERIALIZED (SELECT cte.col_1, cte.col_2 FROM cte) INSERT INTO on_conflict.target_table (col_1, col_2) SELECT col_1, col_2 FROM cte_2 ON CONFLICT(col_1) DO UPDATE SET col_2 = (excluded.col_2 OPERATOR(pg_catalog.+) 1) RETURNING target_table.col_1, target_table.col_2 -DEBUG: distributed INSERT ... SELECT can only select from distributed tables -DEBUG: generating subplan XXX_1 for CTE cte: SELECT col_1, col_2, col_3 FROM on_conflict.source_table_1 -DEBUG: generating subplan XXX_2 for CTE cte_2: SELECT col_1, col_2 FROM (SELECT intermediate_result.col_1, intermediate_result.col_2, intermediate_result.col_3 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer, col_3 integer)) cte -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT col_1, col_2 FROM (SELECT cte_2.col_1, cte_2.col_2 FROM (SELECT intermediate_result.col_1, intermediate_result.col_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer)) cte_2) citus_insert_select_subquery -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT col_1, col_2 FROM (SELECT intermediate_result.col_1, intermediate_result.col_2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer)) inserted_table ORDER BY col_1 -DEBUG: Collecting INSERT ... SELECT results on coordinator - col_1 | col_2 ---------------------------------------------------------------------- - 1 | 2 - 2 | 3 - 3 | 4 - 4 | 5 - 5 | 6 -(5 rows) - -WITH cte AS MATERIALIZED ( - WITH basic AS MATERIALIZED ( - SELECT col_1, col_2 FROM source_table_1 - ) - INSERT INTO target_table (SELECT * FROM basic) ON CONFLICT DO NOTHING RETURNING * -) -UPDATE target_table SET col_2 = 4 WHERE col_1 IN (SELECT col_1 FROM cte); -DEBUG: generating subplan XXX_1 for CTE cte: WITH basic AS MATERIALIZED (SELECT source_table_1.col_1, source_table_1.col_2 FROM on_conflict.source_table_1) INSERT INTO on_conflict.target_table (col_1, col_2) SELECT col_1, col_2 FROM basic ON CONFLICT DO NOTHING RETURNING target_table.col_1, target_table.col_2 -DEBUG: distributed INSERT ... SELECT can only select from distributed tables -DEBUG: generating subplan XXX_1 for CTE basic: SELECT col_1, col_2 FROM on_conflict.source_table_1 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT col_1, col_2 FROM (SELECT basic.col_1, basic.col_2 FROM (SELECT intermediate_result.col_1, intermediate_result.col_2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer)) basic) citus_insert_select_subquery -DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE on_conflict.target_table SET col_2 = 4 WHERE (col_1 OPERATOR(pg_catalog.=) ANY (SELECT cte.col_1 FROM (SELECT intermediate_result.col_1, intermediate_result.col_2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer)) cte)) -DEBUG: Collecting INSERT ... SELECT results on coordinator -RESET client_min_messages; --- Following query is supported by using repartition join for the insert/select -SELECT coordinator_plan($Q$ -EXPLAIN (costs off) -WITH cte AS ( - SELECT - col_1, col_2 - FROM - source_table_1 -) -INSERT INTO target_table -SELECT - source_table_1.col_1, - source_table_1.col_2 -FROM cte, source_table_1 -WHERE cte.col_1 = source_table_1.col_1 ON CONFLICT DO NOTHING; -$Q$); - coordinator_plan ---------------------------------------------------------------------- - Custom Scan (Citus INSERT ... SELECT) - INSERT/SELECT method: repartition - -> Custom Scan (Citus Adaptive) - Task Count: 4 -(4 rows) - --- Tests with foreign key to reference table -CREATE TABLE test_ref_table (key int PRIMARY KEY); -SELECT create_reference_table('test_ref_table'); - create_reference_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO test_ref_table VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); -ALTER TABLE target_table ADD CONSTRAINT fkey FOREIGN KEY (col_1) REFERENCES test_ref_table(key) ON DELETE CASCADE; -BEGIN; - TRUNCATE test_ref_table CASCADE; -NOTICE: truncate cascades to table "target_table" - INSERT INTO - target_table - SELECT - col_2, - col_1 - FROM source_table_1 ON CONFLICT (col_1) DO UPDATE SET col_2 = 55 RETURNING *; -ERROR: insert or update on table "target_table_xxxxxxx" violates foreign key constraint "fkey_xxxxxxx" -DETAIL: Key (col_1)=(X) is not present in table "test_ref_table_xxxxxxx". -CONTEXT: while executing command on localhost:xxxxx -ROLLBACK; -BEGIN; - DELETE FROM test_ref_table WHERE key > 10; - WITH r AS ( - INSERT INTO - target_table - SELECT - col_2, - col_1 - FROM source_table_1 ON CONFLICT (col_1) DO UPDATE SET col_2 = 1 RETURNING *) - SELECT * FROM r ORDER BY col_1; - col_1 | col_2 ---------------------------------------------------------------------- - 1 | 1 - 2 | 1 - 3 | 1 - 4 | 1 - 5 | 1 -(5 rows) - -ROLLBACK; --- Following two queries are supported since we no not modify but only select from --- the target_table after modification on test_ref_table. -BEGIN; - TRUNCATE test_ref_table CASCADE; -NOTICE: truncate cascades to table "target_table" - INSERT INTO - source_table_1 - SELECT - col_2, - col_1 - FROM target_table ON CONFLICT (col_1) DO UPDATE SET col_2 = 55 RETURNING *; - col_1 | col_2 | col_3 ---------------------------------------------------------------------- -(0 rows) - -ROLLBACK; -BEGIN; - DELETE FROM test_ref_table; - INSERT INTO - source_table_1 - SELECT - col_2, - col_1 - FROM target_table ON CONFLICT (col_1) DO UPDATE SET col_2 = 55 RETURNING *; - col_1 | col_2 | col_3 ---------------------------------------------------------------------- -(0 rows) - -ROLLBACK; --- INSERT .. SELECT with different column types -CREATE TABLE source_table_3(col_1 numeric, col_2 numeric, col_3 numeric); -SELECT create_distributed_table('source_table_3','col_1'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO source_table_3 VALUES(1,11,1),(2,22,2),(3,33,3),(4,44,4),(5,55,5); -CREATE TABLE source_table_4(id int, arr_val text[]); -SELECT create_distributed_table('source_table_4','id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO source_table_4 VALUES(1, '{"abc","cde","efg"}'), (2, '{"xyz","tvu"}'); -CREATE TABLE target_table_2(id int primary key, arr_val char(10)[]); -SELECT create_distributed_table('target_table_2','id'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO target_table_2 VALUES(1, '{"abc","def","gyx"}'); -SET client_min_messages to debug1; -INSERT INTO target_table -SELECT - col_1, col_2 -FROM - source_table_3 -ON CONFLICT(col_1) DO UPDATE SET col_2 = EXCLUDED.col_2; -DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match -DETAIL: The data type of the target table's partition column should exactly match the data type of the corresponding simple column reference in the subquery. -DEBUG: performing repartitioned INSERT ... SELECT -SELECT * FROM target_table ORDER BY 1; - col_1 | col_2 ---------------------------------------------------------------------- - 1 | 11 - 2 | 22 - 3 | 33 - 4 | 44 - 5 | 55 - 6 | 7 - 7 | 8 - 8 | 9 - 9 | 10 - 10 | 11 -(10 rows) - -INSERT INTO target_table_2 -SELECT - * -FROM - source_table_4 -ON CONFLICT DO NOTHING; -SELECT * FROM target_table_2 ORDER BY 1; - id | arr_val ---------------------------------------------------------------------- - 1 | {"abc ","def ","gyx "} - 2 | {"xyz ","tvu "} -(2 rows) - -RESET client_min_messages; --- Test with shard_replication_factor = 2 -SET citus.shard_replication_factor to 2; -DROP TABLE target_table, source_table_1, source_table_2; -CREATE TABLE target_table(col_1 int primary key, col_2 int); -SELECT create_distributed_table('target_table','col_1'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO target_table VALUES(1,2),(2,3),(3,4),(4,5),(5,6); -CREATE TABLE source_table_1(col_1 int, col_2 int, col_3 int); -SELECT create_distributed_table('source_table_1','col_1'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO source_table_1 VALUES(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5); -CREATE TABLE source_table_2(col_1 int, col_2 int, col_3 int); -SELECT create_distributed_table('source_table_2','col_1'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO source_table_2 VALUES(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10); -SET client_min_messages to debug1; --- Generate series directly on the coordinator and on conflict do nothing -INSERT INTO target_table (col_1, col_2) -SELECT - s, s -FROM - generate_series(1,10) s -ON CONFLICT DO NOTHING; -DEBUG: distributed INSERT ... SELECT can only select from distributed tables -DEBUG: Collecting INSERT ... SELECT results on coordinator --- Test with multiple subqueries -INSERT INTO target_table -SELECT - col_1, col_2 -FROM ( - (SELECT - col_1, col_2, col_3 - FROM - source_table_1 - LIMIT 5) - UNION - (SELECT - col_1, col_2, col_3 - FROM - source_table_2 - LIMIT 5) -) as foo -ON CONFLICT(col_1) DO UPDATE SET col_2 = 0; -DEBUG: cannot push down this subquery -DETAIL: Limit clause is currently unsupported when a subquery references a column from another query -DEBUG: push down of limit count: 5 -DEBUG: generating subplan XXX_1 for subquery SELECT col_1, col_2, col_3 FROM on_conflict.source_table_1 LIMIT 5 -DEBUG: push down of limit count: 5 -DEBUG: generating subplan XXX_2 for subquery SELECT col_1, col_2, col_3 FROM on_conflict.source_table_2 LIMIT 5 -DEBUG: generating subplan XXX_3 for subquery SELECT intermediate_result.col_1, intermediate_result.col_2, intermediate_result.col_3 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer, col_3 integer) UNION SELECT intermediate_result.col_1, intermediate_result.col_2, intermediate_result.col_3 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer, col_3 integer) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT col_1, col_2 FROM (SELECT intermediate_result.col_1, intermediate_result.col_2, intermediate_result.col_3 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer, col_3 integer)) foo -DEBUG: Collecting INSERT ... SELECT results on coordinator -SELECT * FROM target_table ORDER BY 1; - col_1 | col_2 ---------------------------------------------------------------------- - 1 | 0 - 2 | 0 - 3 | 0 - 4 | 0 - 5 | 0 - 6 | 0 - 7 | 0 - 8 | 0 - 9 | 0 - 10 | 0 -(10 rows) - -WITH cte AS MATERIALIZED( - SELECT col_1, col_2, col_3 FROM source_table_1 -), cte_2 AS MATERIALIZED( - SELECT col_1, col_2 FROM cte -) -INSERT INTO target_table SELECT * FROM cte_2 ON CONFLICT(col_1) DO UPDATE SET col_2 = EXCLUDED.col_2 + 1; -DEBUG: distributed INSERT ... SELECT can only select from distributed tables -DEBUG: generating subplan XXX_1 for CTE cte: SELECT col_1, col_2, col_3 FROM on_conflict.source_table_1 -DEBUG: generating subplan XXX_2 for CTE cte_2: SELECT col_1, col_2 FROM (SELECT intermediate_result.col_1, intermediate_result.col_2, intermediate_result.col_3 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer, col_3 integer)) cte -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT col_1, col_2 FROM (SELECT cte_2.col_1, cte_2.col_2 FROM (SELECT intermediate_result.col_1, intermediate_result.col_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer)) cte_2) citus_insert_select_subquery -DEBUG: Collecting INSERT ... SELECT results on coordinator -SELECT * FROM target_table ORDER BY 1; - col_1 | col_2 ---------------------------------------------------------------------- - 1 | 2 - 2 | 3 - 3 | 4 - 4 | 5 - 5 | 6 - 6 | 0 - 7 | 0 - 8 | 0 - 9 | 0 - 10 | 0 -(10 rows) - --- make sure that even if COPY switchover happens --- the results are correct -SET citus.copy_switchover_threshold TO 1; -TRUNCATE target_table; --- load some data to make sure copy commands switch over connections -INSERT INTO target_table SELECT i,0 FROM generate_series(0,500)i; -DEBUG: distributed INSERT ... SELECT can only select from distributed tables -DEBUG: Collecting INSERT ... SELECT results on coordinator --- make sure that SELECT only uses 1 connection 1 node --- yet still COPY commands use 1 connection per co-located --- intermediate result file -SET citus.max_adaptive_executor_pool_size TO 1; -INSERT INTO target_table SELECT * FROM target_table LIMIT 10000 ON CONFLICT(col_1) DO UPDATE SET col_2 = EXCLUDED.col_2 + 1; -DEBUG: cannot push down this subquery -DETAIL: Limit clause is currently unsupported when a subquery references a column from another query -DEBUG: push down of limit count: 10000 -DEBUG: Collecting INSERT ... SELECT results on coordinator -SELECT DISTINCT col_2 FROM target_table; - col_2 ---------------------------------------------------------------------- - 1 -(1 row) - -WITH cte_1 AS (INSERT INTO target_table SELECT * FROM target_table LIMIT 10000 ON CONFLICT(col_1) DO UPDATE SET col_2 = EXCLUDED.col_2 + 1 RETURNING *) -SELECT DISTINCT col_2 FROM cte_1; -DEBUG: generating subplan XXX_1 for CTE cte_1: INSERT INTO on_conflict.target_table (col_1, col_2) SELECT col_1, col_2 FROM on_conflict.target_table LIMIT 10000 ON CONFLICT(col_1) DO UPDATE SET col_2 = (excluded.col_2 OPERATOR(pg_catalog.+) 1) RETURNING target_table.col_1, target_table.col_2 -DEBUG: cannot push down this subquery -DETAIL: Limit clause is currently unsupported when a subquery references a column from another query -DEBUG: push down of limit count: 10000 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT DISTINCT col_2 FROM (SELECT intermediate_result.col_1, intermediate_result.col_2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col_1 integer, col_2 integer)) cte_1 -DEBUG: Collecting INSERT ... SELECT results on coordinator - col_2 ---------------------------------------------------------------------- - 2 -(1 row) - -RESET client_min_messages; -DROP SCHEMA on_conflict CASCADE; -NOTICE: drop cascades to 8 other objects -DETAIL: drop cascades to table test_ref_table -drop cascades to table test_ref_table_1900012 -drop cascades to table source_table_3 -drop cascades to table source_table_4 -drop cascades to table target_table_2 -drop cascades to table target_table -drop cascades to table source_table_1 -drop cascades to table source_table_2 diff --git a/src/test/regress/expected/multi_metadata_sync.out b/src/test/regress/expected/multi_metadata_sync.out index d15e7516c..af81428f3 100644 --- a/src/test/regress/expected/multi_metadata_sync.out +++ b/src/test/regress/expected/multi_metadata_sync.out @@ -1,16 +1,6 @@ -- -- MULTI_METADATA_SYNC -- --- this test has different output for PG14 compared to PG15 --- In PG15, public schema is owned by pg_database_owner role --- Relevant PG commit: b073c3ccd06e4cb845e121387a43faa8c68a7b62 -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - t -(1 row) - -- Tests for metadata snapshot functions, metadata syncing functions and propagation of -- metadata changes to MX tables. -- Turn metadata sync off at first diff --git a/src/test/regress/expected/multi_mx_insert_select_repartition.out b/src/test/regress/expected/multi_mx_insert_select_repartition.out index a3912ec8e..0113239ea 100644 --- a/src/test/regress/expected/multi_mx_insert_select_repartition.out +++ b/src/test/regress/expected/multi_mx_insert_select_repartition.out @@ -3,17 +3,6 @@ -- -- Test behaviour of repartitioned INSERT ... SELECT in MX setup -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - t -(1 row) - CREATE SCHEMA multi_mx_insert_select_repartition; SET search_path TO multi_mx_insert_select_repartition; SET citus.next_shard_id TO 4213581; diff --git a/src/test/regress/expected/mx_coordinator_shouldhaveshards.out b/src/test/regress/expected/mx_coordinator_shouldhaveshards.out index 547300460..b985dd330 100644 --- a/src/test/regress/expected/mx_coordinator_shouldhaveshards.out +++ b/src/test/regress/expected/mx_coordinator_shouldhaveshards.out @@ -1,17 +1,6 @@ -- -- MX_COORDINATOR_SHOULDHAVESHARDS -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - t -(1 row) - CREATE SCHEMA mx_coordinator_shouldhaveshards; SET search_path TO mx_coordinator_shouldhaveshards; SET citus.shard_replication_factor to 1; diff --git a/src/test/regress/expected/mx_coordinator_shouldhaveshards_0.out b/src/test/regress/expected/mx_coordinator_shouldhaveshards_0.out deleted file mode 100644 index 15cd69068..000000000 --- a/src/test/regress/expected/mx_coordinator_shouldhaveshards_0.out +++ /dev/null @@ -1,335 +0,0 @@ --- --- MX_COORDINATOR_SHOULDHAVESHARDS --- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - f -(1 row) - -CREATE SCHEMA mx_coordinator_shouldhaveshards; -SET search_path TO mx_coordinator_shouldhaveshards; -SET citus.shard_replication_factor to 1; -SET client_min_messages TO WARNING; -SELECT 1 FROM master_add_node('localhost', :master_port, groupid => 0); - ?column? ---------------------------------------------------------------------- - 1 -(1 row) - -RESET client_min_messages; -SELECT 1 FROM master_set_node_property('localhost', :master_port, 'shouldhaveshards', true); - ?column? ---------------------------------------------------------------------- - 1 -(1 row) - --- issue 4508 table_1 and table_2 are used to test some edge cases --- around intermediate result pruning -CREATE TABLE table_1 (key int, value text); -SELECT create_distributed_table('table_1', 'key', colocate_with := 'none'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -CREATE TABLE table_2 (key int, value text); -SELECT create_distributed_table('table_2', 'key', colocate_with := 'none'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO table_1 VALUES (1, '1'), (2, '2'), (3, '3'), (4, '4'); -INSERT INTO table_2 VALUES (1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5'), (6, '6'); -SET citus.shard_replication_factor to 2; -CREATE TABLE table_1_rep (key int, value text); -SELECT create_distributed_table('table_1_rep', 'key', colocate_with := 'none'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -CREATE TABLE table_2_rep (key int, value text); -SELECT create_distributed_table('table_2_rep', 'key', colocate_with := 'none'); - create_distributed_table ---------------------------------------------------------------------- - -(1 row) - -INSERT INTO table_1_rep VALUES (1, '1'), (2, '2'), (3, '3'), (4, '4'); -INSERT INTO table_2_rep VALUES (1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5'), (6, '6'); -set citus.log_intermediate_results TO ON; -set client_min_messages to debug1; -WITH a AS (SELECT * FROM table_1 ORDER BY 1,2 DESC LIMIT 1) -SELECT count(*), -key -FROM a JOIN table_2 USING (key) -GROUP BY key -HAVING (max(table_2.value) >= (SELECT value FROM a)); -DEBUG: generating subplan XXX_1 for CTE a: SELECT key, value FROM mx_coordinator_shouldhaveshards.table_1 ORDER BY key, value DESC LIMIT 1 -DEBUG: push down of limit count: 1 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count, a.key FROM ((SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a JOIN mx_coordinator_shouldhaveshards.table_2 USING (key)) GROUP BY a.key HAVING (max(table_2.value) OPERATOR(pg_catalog.>=) (SELECT a_1.value FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a_1)) -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx - count | key ---------------------------------------------------------------------- - 1 | 1 -(1 row) - -WITH a AS (SELECT * FROM table_1 ORDER BY 1,2 DESC LIMIT 1) -INSERT INTO table_1 SELECT count(*), -key -FROM a JOIN table_2 USING (key) -GROUP BY key -HAVING (max(table_2.value) >= (SELECT value FROM a)); -DEBUG: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns -DEBUG: generating subplan XXX_1 for CTE a: SELECT key, value FROM mx_coordinator_shouldhaveshards.table_1 ORDER BY key, value DESC LIMIT 1 -DEBUG: push down of limit count: 1 -DEBUG: generating subplan XXX_2 for subquery SELECT int4(count(*)) AS auto_coerced_by_citus_0, (a.key)::text AS auto_coerced_by_citus_1 FROM ((SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a JOIN mx_coordinator_shouldhaveshards.table_2 USING (key)) GROUP BY a.key HAVING (max(table_2.value) OPERATOR(pg_catalog.>=) (SELECT a_1.value FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a_1)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT auto_coerced_by_citus_0 AS key, auto_coerced_by_citus_1 AS value FROM (SELECT intermediate_result.auto_coerced_by_citus_0, intermediate_result.auto_coerced_by_citus_1 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(auto_coerced_by_citus_0 integer, auto_coerced_by_citus_1 text)) citus_insert_select_subquery -DEBUG: Collecting INSERT ... SELECT results on coordinator -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be written to local file -WITH stats AS ( - SELECT count(key) m FROM table_1 -), -inserts AS ( - INSERT INTO table_2 - SELECT key, count(*) - FROM table_1 - WHERE key >= (SELECT m FROM stats) - GROUP BY key - HAVING count(*) <= (SELECT m FROM stats) - LIMIT 1 - RETURNING * -) SELECT count(*) FROM inserts; -DEBUG: generating subplan XXX_1 for CTE stats: SELECT count(key) AS m FROM mx_coordinator_shouldhaveshards.table_1 -DEBUG: generating subplan XXX_2 for CTE inserts: INSERT INTO mx_coordinator_shouldhaveshards.table_2 (key, value) SELECT key, count(*) AS count FROM mx_coordinator_shouldhaveshards.table_1 WHERE (key OPERATOR(pg_catalog.>=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) GROUP BY key HAVING (count(*) OPERATOR(pg_catalog.<=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) LIMIT 1 RETURNING table_2.key, table_2.value -DEBUG: cannot push down this subquery -DETAIL: Limit clause is currently unsupported when a subquery references a column from another query -DEBUG: push down of limit count: 1 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) inserts -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be written to local file -DEBUG: Collecting INSERT ... SELECT results on coordinator - count ---------------------------------------------------------------------- - 0 -(1 row) - -WITH a AS (SELECT * FROM table_1_rep ORDER BY 1,2 DESC LIMIT 1) -SELECT count(*), -key -FROM a JOIN table_2_rep USING (key) -GROUP BY key -HAVING (max(table_2_rep.value) >= (SELECT value FROM a)); -DEBUG: generating subplan XXX_1 for CTE a: SELECT key, value FROM mx_coordinator_shouldhaveshards.table_1_rep ORDER BY key, value DESC LIMIT 1 -DEBUG: push down of limit count: 1 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count, a.key FROM ((SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a JOIN mx_coordinator_shouldhaveshards.table_2_rep USING (key)) GROUP BY a.key HAVING (max(table_2_rep.value) OPERATOR(pg_catalog.>=) (SELECT a_1.value FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a_1)) -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx - count | key ---------------------------------------------------------------------- - 1 | 1 -(1 row) - -WITH a AS (SELECT * FROM table_1_rep ORDER BY 1,2 DESC LIMIT 1) -INSERT INTO table_1_rep SELECT count(*), -key -FROM a JOIN table_2_rep USING (key) -GROUP BY key -HAVING (max(table_2_rep.value) >= (SELECT value FROM a)); -DEBUG: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns -DEBUG: generating subplan XXX_1 for CTE a: SELECT key, value FROM mx_coordinator_shouldhaveshards.table_1_rep ORDER BY key, value DESC LIMIT 1 -DEBUG: push down of limit count: 1 -DEBUG: generating subplan XXX_2 for subquery SELECT int4(count(*)) AS auto_coerced_by_citus_0, (a.key)::text AS auto_coerced_by_citus_1 FROM ((SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a JOIN mx_coordinator_shouldhaveshards.table_2_rep USING (key)) GROUP BY a.key HAVING (max(table_2_rep.value) OPERATOR(pg_catalog.>=) (SELECT a_1.value FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a_1)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT auto_coerced_by_citus_0 AS key, auto_coerced_by_citus_1 AS value FROM (SELECT intermediate_result.auto_coerced_by_citus_0, intermediate_result.auto_coerced_by_citus_1 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(auto_coerced_by_citus_0 integer, auto_coerced_by_citus_1 text)) citus_insert_select_subquery -DEBUG: Collecting INSERT ... SELECT results on coordinator -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be written to local file -WITH stats AS ( - SELECT count(key) m FROM table_1_rep -), -inserts AS ( - INSERT INTO table_2_rep - SELECT key, count(*) - FROM table_1_rep - WHERE key >= (SELECT m FROM stats) - GROUP BY key - HAVING count(*) <= (SELECT m FROM stats) - LIMIT 1 - RETURNING * -) SELECT count(*) FROM inserts; -DEBUG: generating subplan XXX_1 for CTE stats: SELECT count(key) AS m FROM mx_coordinator_shouldhaveshards.table_1_rep -DEBUG: generating subplan XXX_2 for CTE inserts: INSERT INTO mx_coordinator_shouldhaveshards.table_2_rep (key, value) SELECT key, count(*) AS count FROM mx_coordinator_shouldhaveshards.table_1_rep WHERE (key OPERATOR(pg_catalog.>=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) GROUP BY key HAVING (count(*) OPERATOR(pg_catalog.<=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) LIMIT 1 RETURNING table_2_rep.key, table_2_rep.value -DEBUG: cannot push down this subquery -DETAIL: Limit clause is currently unsupported when a subquery references a column from another query -DEBUG: push down of limit count: 1 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) inserts -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be written to local file -DEBUG: Collecting INSERT ... SELECT results on coordinator - count ---------------------------------------------------------------------- - 0 -(1 row) - -\c - - - :worker_1_port -SET search_path TO mx_coordinator_shouldhaveshards; -set citus.log_intermediate_results TO ON; -set client_min_messages to debug1; -WITH a AS (SELECT * FROM table_1 ORDER BY 1,2 DESC LIMIT 1) -SELECT count(*), -key -FROM a JOIN table_2 USING (key) -GROUP BY key -HAVING (max(table_2.value) >= (SELECT value FROM a)); -DEBUG: generating subplan XXX_1 for CTE a: SELECT key, value FROM mx_coordinator_shouldhaveshards.table_1 ORDER BY key, value DESC LIMIT 1 -DEBUG: push down of limit count: 1 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count, a.key FROM ((SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a JOIN mx_coordinator_shouldhaveshards.table_2 USING (key)) GROUP BY a.key HAVING (max(table_2.value) OPERATOR(pg_catalog.>=) (SELECT a_1.value FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a_1)) -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx - count | key ---------------------------------------------------------------------- - 1 | 1 -(1 row) - -WITH a AS (SELECT * FROM table_1 ORDER BY 1,2 DESC LIMIT 1) -INSERT INTO table_1 SELECT count(*), -key -FROM a JOIN table_2 USING (key) -GROUP BY key -HAVING (max(table_2.value) >= (SELECT value FROM a)); -DEBUG: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns -DEBUG: generating subplan XXX_1 for CTE a: SELECT key, value FROM mx_coordinator_shouldhaveshards.table_1 ORDER BY key, value DESC LIMIT 1 -DEBUG: push down of limit count: 1 -DEBUG: generating subplan XXX_2 for subquery SELECT int4(count(*)) AS auto_coerced_by_citus_0, (a.key)::text AS auto_coerced_by_citus_1 FROM ((SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a JOIN mx_coordinator_shouldhaveshards.table_2 USING (key)) GROUP BY a.key HAVING (max(table_2.value) OPERATOR(pg_catalog.>=) (SELECT a_1.value FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a_1)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT auto_coerced_by_citus_0 AS key, auto_coerced_by_citus_1 AS value FROM (SELECT intermediate_result.auto_coerced_by_citus_0, intermediate_result.auto_coerced_by_citus_1 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(auto_coerced_by_citus_0 integer, auto_coerced_by_citus_1 text)) citus_insert_select_subquery -DEBUG: Collecting INSERT ... SELECT results on coordinator -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be written to local file -WITH stats AS ( - SELECT count(key) m FROM table_1 -), -inserts AS ( - INSERT INTO table_2 - SELECT key, count(*) - FROM table_1 - WHERE key >= (SELECT m FROM stats) - GROUP BY key - HAVING count(*) <= (SELECT m FROM stats) - LIMIT 1 - RETURNING * -) SELECT count(*) FROM inserts; -DEBUG: generating subplan XXX_1 for CTE stats: SELECT count(key) AS m FROM mx_coordinator_shouldhaveshards.table_1 -DEBUG: generating subplan XXX_2 for CTE inserts: INSERT INTO mx_coordinator_shouldhaveshards.table_2 (key, value) SELECT key, count(*) AS count FROM mx_coordinator_shouldhaveshards.table_1 WHERE (key OPERATOR(pg_catalog.>=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) GROUP BY key HAVING (count(*) OPERATOR(pg_catalog.<=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) LIMIT 1 RETURNING table_2.key, table_2.value -DEBUG: cannot push down this subquery -DETAIL: Limit clause is currently unsupported when a subquery references a column from another query -DEBUG: push down of limit count: 1 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) inserts -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be written to local file -DEBUG: Collecting INSERT ... SELECT results on coordinator - count ---------------------------------------------------------------------- - 0 -(1 row) - -WITH a AS (SELECT * FROM table_1_rep ORDER BY 1,2 DESC LIMIT 1) -SELECT count(*), -key -FROM a JOIN table_2_rep USING (key) -GROUP BY key -HAVING (max(table_2_rep.value) >= (SELECT value FROM a)); -DEBUG: generating subplan XXX_1 for CTE a: SELECT key, value FROM mx_coordinator_shouldhaveshards.table_1_rep ORDER BY key, value DESC LIMIT 1 -DEBUG: push down of limit count: 1 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count, a.key FROM ((SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a JOIN mx_coordinator_shouldhaveshards.table_2_rep USING (key)) GROUP BY a.key HAVING (max(table_2_rep.value) OPERATOR(pg_catalog.>=) (SELECT a_1.value FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a_1)) -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx - count | key ---------------------------------------------------------------------- - 1 | 1 -(1 row) - -WITH a AS (SELECT * FROM table_1_rep ORDER BY 1,2 DESC LIMIT 1) -INSERT INTO table_1_rep SELECT count(*), -key -FROM a JOIN table_2_rep USING (key) -GROUP BY key -HAVING (max(table_2_rep.value) >= (SELECT value FROM a)); -DEBUG: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns -DEBUG: generating subplan XXX_1 for CTE a: SELECT key, value FROM mx_coordinator_shouldhaveshards.table_1_rep ORDER BY key, value DESC LIMIT 1 -DEBUG: push down of limit count: 1 -DEBUG: generating subplan XXX_2 for subquery SELECT int4(count(*)) AS auto_coerced_by_citus_0, (a.key)::text AS auto_coerced_by_citus_1 FROM ((SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a JOIN mx_coordinator_shouldhaveshards.table_2_rep USING (key)) GROUP BY a.key HAVING (max(table_2_rep.value) OPERATOR(pg_catalog.>=) (SELECT a_1.value FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) a_1)) -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT auto_coerced_by_citus_0 AS key, auto_coerced_by_citus_1 AS value FROM (SELECT intermediate_result.auto_coerced_by_citus_0, intermediate_result.auto_coerced_by_citus_1 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(auto_coerced_by_citus_0 integer, auto_coerced_by_citus_1 text)) citus_insert_select_subquery -DEBUG: Collecting INSERT ... SELECT results on coordinator -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be written to local file -WITH stats AS ( - SELECT count(key) m FROM table_1_rep -), -inserts AS ( - INSERT INTO table_2_rep - SELECT key, count(*) - FROM table_1_rep - WHERE key >= (SELECT m FROM stats) - GROUP BY key - HAVING count(*) <= (SELECT m FROM stats) - LIMIT 1 - RETURNING * -) SELECT count(*) FROM inserts; -DEBUG: generating subplan XXX_1 for CTE stats: SELECT count(key) AS m FROM mx_coordinator_shouldhaveshards.table_1_rep -DEBUG: generating subplan XXX_2 for CTE inserts: INSERT INTO mx_coordinator_shouldhaveshards.table_2_rep (key, value) SELECT key, count(*) AS count FROM mx_coordinator_shouldhaveshards.table_1_rep WHERE (key OPERATOR(pg_catalog.>=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) GROUP BY key HAVING (count(*) OPERATOR(pg_catalog.<=) (SELECT stats.m FROM (SELECT intermediate_result.m FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(m bigint)) stats)) LIMIT 1 RETURNING table_2_rep.key, table_2_rep.value -DEBUG: cannot push down this subquery -DETAIL: Limit clause is currently unsupported when a subquery references a column from another query -DEBUG: push down of limit count: 1 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) inserts -DEBUG: Subplan XXX_1 will be written to local file -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_1 will be sent to localhost:xxxxx -DEBUG: Subplan XXX_2 will be written to local file -DEBUG: Collecting INSERT ... SELECT results on coordinator - count ---------------------------------------------------------------------- - 0 -(1 row) - -\c - - - :master_port -SELECT 1 FROM master_set_node_property('localhost', :master_port, 'shouldhaveshards', false); - ?column? ---------------------------------------------------------------------- - 1 -(1 row) - -SET client_min_messages TO ERROR; -DROP SCHEMA mx_coordinator_shouldhaveshards CASCADE; -SELECT master_remove_node('localhost', :master_port); - master_remove_node ---------------------------------------------------------------------- - -(1 row) - diff --git a/src/test/regress/expected/pg15.out b/src/test/regress/expected/pg15.out index f5d4327a8..66299af08 100644 --- a/src/test/regress/expected/pg15.out +++ b/src/test/regress/expected/pg15.out @@ -1,13 +1,6 @@ -- -- PG15 -- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif CREATE SCHEMA pg15; SET search_path TO pg15; SET citus.next_shard_id TO 960000; diff --git a/src/test/regress/expected/pg15_0.out b/src/test/regress/expected/pg15_0.out deleted file mode 100644 index b1ed9cc5b..000000000 --- a/src/test/regress/expected/pg15_0.out +++ /dev/null @@ -1,9 +0,0 @@ --- --- PG15 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q diff --git a/src/test/regress/expected/pg15_jsonpath.out b/src/test/regress/expected/pg15_jsonpath.out index 335a7fbba..a3bdf8a55 100644 --- a/src/test/regress/expected/pg15_jsonpath.out +++ b/src/test/regress/expected/pg15_jsonpath.out @@ -2,13 +2,6 @@ -- PG15 jsonpath tests -- Relevant pg commit: e26114c817b610424010cfbe91a743f591246ff1 -- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif CREATE SCHEMA jsonpath; SET search_path TO jsonpath; CREATE TABLE jsonpath_test (id serial, sample text); diff --git a/src/test/regress/expected/pg15_jsonpath_0.out b/src/test/regress/expected/pg15_jsonpath_0.out deleted file mode 100644 index b496f64dc..000000000 --- a/src/test/regress/expected/pg15_jsonpath_0.out +++ /dev/null @@ -1,10 +0,0 @@ --- --- PG15 jsonpath tests --- Relevant pg commit: e26114c817b610424010cfbe91a743f591246ff1 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q diff --git a/src/test/regress/expected/pgmerge.out b/src/test/regress/expected/pgmerge.out index 0c2f9b741..9057cac6b 100644 --- a/src/test/regress/expected/pgmerge.out +++ b/src/test/regress/expected/pgmerge.out @@ -1,10 +1,3 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif -- -- MERGE test from PG community (adapted to Citus by converting all tables to Citus local) -- diff --git a/src/test/regress/expected/pgmerge_0.out b/src/test/regress/expected/pgmerge_0.out deleted file mode 100644 index a7e3fbf20..000000000 --- a/src/test/regress/expected/pgmerge_0.out +++ /dev/null @@ -1,6 +0,0 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out index 2df4e59d3..d4dd2565a 100644 --- a/src/test/regress/expected/publication.out +++ b/src/test/regress/expected/publication.out @@ -258,18 +258,6 @@ DROP PUBLICATION "pub-all-insertupdateonly"; DROP PUBLICATION "pub-all"; DROP PUBLICATION pubpartitioned; DROP PUBLICATION pubnotdistributed; -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -SET client_min_messages TO ERROR; -DROP SCHEMA publication CASCADE; -DROP SCHEMA "publication-1" CASCADE; -DROP SCHEMA citus_schema_1 CASCADE; -SELECT public.wait_for_resource_cleanup(); -\q -\endif -- recreate a mixed publication CREATE PUBLICATION pubtables FOR TABLE test, "publication-1"."test-pubs", citus_schema_1.test; -- operations on an existing distributed table diff --git a/src/test/regress/expected/single_node.out b/src/test/regress/expected/single_node.out index 522ffb8e8..54143caec 100644 --- a/src/test/regress/expected/single_node.out +++ b/src/test/regress/expected/single_node.out @@ -1,17 +1,6 @@ -- -- SINGLE_NODE -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; - server_version_ge_15 ---------------------------------------------------------------------- - t -(1 row) - CREATE SCHEMA single_node; SET search_path TO single_node; SET citus.shard_count TO 4; diff --git a/src/test/regress/expected/upgrade_citus_finish_citus_upgrade_1.out b/src/test/regress/expected/upgrade_citus_finish_citus_upgrade_1.out new file mode 100644 index 000000000..99538b839 --- /dev/null +++ b/src/test/regress/expected/upgrade_citus_finish_citus_upgrade_1.out @@ -0,0 +1,41 @@ +-- Citus upgrades are finished by calling a procedure +-- Note that pg_catalog.citus_finish_citus_upgrade() behaves differently +-- when last upgrade citus version is less than 11 +-- so we have two alternative outputs for this test +\set upgrade_test_old_citus_version `echo "$CITUS_OLD_VERSION"` +SELECT substring(:'upgrade_test_old_citus_version', 'v(\d+)\.\d+\.\d+')::int < 11 +AS upgrade_test_old_citus_version_lt_11_0; + upgrade_test_old_citus_version_lt_11_0 +--------------------------------------------------------------------- + f +(1 row) + +-- this is a transactional procedure, so rollback should be fine +BEGIN; + CALL citus_finish_citus_upgrade(); +NOTICE: already at the latest distributed schema version (11.1-1) +ROLLBACK; +-- do the actual job +CALL citus_finish_citus_upgrade(); +NOTICE: already at the latest distributed schema version (11.1-1) +-- show that the upgrade is successfull +SELECT metadata->>'last_upgrade_version' = extversion +FROM pg_dist_node_metadata, pg_extension WHERE extname = 'citus'; + ?column? +--------------------------------------------------------------------- + f +(1 row) + +-- idempotent, should be called multiple times +-- still, do not NOTICE the version as it changes per release +SET client_min_messages TO WARNING; +CALL citus_finish_citus_upgrade(); +-- we should be able to sync metadata in nontransactional way as well +SET citus.metadata_sync_mode TO 'nontransactional'; +SELECT start_metadata_sync_to_all_nodes(); + start_metadata_sync_to_all_nodes +--------------------------------------------------------------------- + t +(1 row) + +RESET citus.metadata_sync_mode; diff --git a/src/test/regress/sql/citus_local_tables_queries.sql b/src/test/regress/sql/citus_local_tables_queries.sql index f80de6c57..7dbb09c6e 100644 --- a/src/test/regress/sql/citus_local_tables_queries.sql +++ b/src/test/regress/sql/citus_local_tables_queries.sql @@ -1,12 +1,6 @@ -- -- CITUS_LOCAL_TABLES_QUERIES -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; \set VERBOSITY terse diff --git a/src/test/regress/sql/columnar_pg15.sql b/src/test/regress/sql/columnar_pg15.sql index 1a0f6afdd..80dff78e8 100644 --- a/src/test/regress/sql/columnar_pg15.sql +++ b/src/test/regress/sql/columnar_pg15.sql @@ -1,11 +1,3 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif - CREATE TABLE alter_am(i int); INSERT INTO alter_am SELECT generate_series(1,1000000); diff --git a/src/test/regress/sql/coordinator_shouldhaveshards.sql b/src/test/regress/sql/coordinator_shouldhaveshards.sql index 0365f07c2..6194d3a59 100644 --- a/src/test/regress/sql/coordinator_shouldhaveshards.sql +++ b/src/test/regress/sql/coordinator_shouldhaveshards.sql @@ -3,12 +3,6 @@ -- -- Test queries on a distributed table with shards on the coordinator -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; CREATE SCHEMA coordinator_shouldhaveshards; SET search_path TO coordinator_shouldhaveshards; diff --git a/src/test/regress/sql/cte_inline.sql b/src/test/regress/sql/cte_inline.sql index 3f3e14c88..79cbad48b 100644 --- a/src/test/regress/sql/cte_inline.sql +++ b/src/test/regress/sql/cte_inline.sql @@ -1,12 +1,6 @@ -- -- CTE_INLINE -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; CREATE SCHEMA cte_inline; SET search_path TO cte_inline; diff --git a/src/test/regress/sql/detect_conn_close.sql b/src/test/regress/sql/detect_conn_close.sql index 56ec9bd1d..b5f91da3b 100644 --- a/src/test/regress/sql/detect_conn_close.sql +++ b/src/test/regress/sql/detect_conn_close.sql @@ -1,13 +1,6 @@ -- -- PG15+ test as WL_SOCKET_CLOSED exposed for PG15+ -- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif CREATE SCHEMA socket_close; SET search_path TO socket_close; diff --git a/src/test/regress/sql/grant_on_schema_propagation.sql b/src/test/regress/sql/grant_on_schema_propagation.sql index f0bd233a2..ba75834c9 100644 --- a/src/test/regress/sql/grant_on_schema_propagation.sql +++ b/src/test/regress/sql/grant_on_schema_propagation.sql @@ -1,11 +1,6 @@ -- -- GRANT_ON_SCHEMA_PROPAGATION -- --- this test has different output for PG14 compared to PG15 --- In PG15, public schema is owned by pg_database_owner role --- Relevant PG commit: b073c3ccd06e4cb845e121387a43faa8c68a7b62 -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; -- test grants are propagated when the schema is CREATE SCHEMA dist_schema; diff --git a/src/test/regress/sql/insert_select_repartition.sql b/src/test/regress/sql/insert_select_repartition.sql index 30d77f5b8..940d438e8 100644 --- a/src/test/regress/sql/insert_select_repartition.sql +++ b/src/test/regress/sql/insert_select_repartition.sql @@ -1,12 +1,6 @@ -- -- INSERT_SELECT_REPARTITION -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; -- tests behaviour of INSERT INTO ... SELECT with repartitioning CREATE SCHEMA insert_select_repartition; diff --git a/src/test/regress/sql/intermediate_result_pruning.sql b/src/test/regress/sql/intermediate_result_pruning.sql index 0ebe5825c..bcd60c00b 100644 --- a/src/test/regress/sql/intermediate_result_pruning.sql +++ b/src/test/regress/sql/intermediate_result_pruning.sql @@ -1,12 +1,6 @@ -- -- INTERMEDIATE_RESULT_PRUNING -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; CREATE SCHEMA intermediate_result_pruning; SET search_path TO intermediate_result_pruning; diff --git a/src/test/regress/sql/issue_5248.sql b/src/test/regress/sql/issue_5248.sql index 2248f1493..f58e5b1a8 100644 --- a/src/test/regress/sql/issue_5248.sql +++ b/src/test/regress/sql/issue_5248.sql @@ -1,11 +1,6 @@ -- -- ISSUE_5248 -- --- This test file has an alternative output because of the change in the --- backup modes of Postgres. Specifically, there is a renaming --- issue: pg_stop_backup PRE PG15 vs pg_backup_stop PG15+ --- The alternative output can be deleted when we drop support for PG14 --- CREATE SCHEMA issue_5248; SET search_path TO issue_5248; @@ -13,10 +8,6 @@ SET citus.shard_count TO 4; SET citus.shard_replication_factor TO 1; SET citus.next_shard_id TO 3013000; -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset - create table countries( id serial primary key , name text @@ -202,11 +193,7 @@ FROM ( ( SELECT utc_offset FROM pg_catalog.pg_timezone_names limit 1 offset 4) limit 91) AS subq_3 -\if :server_version_ge_15 WHERE pg_catalog.pg_backup_stop() > cast(NULL AS record) limit 100; -\else -WHERE pg_catalog.pg_stop_backup() > cast(NULL AS pg_lsn) limit 100; -\endif SET client_min_messages TO WARNING; DROP SCHEMA issue_5248 CASCADE; diff --git a/src/test/regress/sql/local_shard_execution.sql b/src/test/regress/sql/local_shard_execution.sql index 8acbc2978..2845693c9 100644 --- a/src/test/regress/sql/local_shard_execution.sql +++ b/src/test/regress/sql/local_shard_execution.sql @@ -1,12 +1,6 @@ -- -- LOCAL_SHARD_EXECUTION -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; CREATE SCHEMA local_shard_execution; SET search_path TO local_shard_execution; diff --git a/src/test/regress/sql/local_shard_execution_replicated.sql b/src/test/regress/sql/local_shard_execution_replicated.sql index d7e4cc064..1c3d264e0 100644 --- a/src/test/regress/sql/local_shard_execution_replicated.sql +++ b/src/test/regress/sql/local_shard_execution_replicated.sql @@ -1,12 +1,6 @@ -- -- LOCAL_SHARD_EXECUTION_REPLICATED -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; CREATE SCHEMA local_shard_execution_replicated; SET search_path TO local_shard_execution_replicated; diff --git a/src/test/regress/sql/merge.sql b/src/test/regress/sql/merge.sql index 5316b5233..14dd04e32 100644 --- a/src/test/regress/sql/merge.sql +++ b/src/test/regress/sql/merge.sql @@ -1,11 +1,3 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif - -- MERGE command performs a join from data_source to target_table_name DROP SCHEMA IF EXISTS merge_schema CASCADE; --MERGE INTO target diff --git a/src/test/regress/sql/merge_arbitrary.sql b/src/test/regress/sql/merge_arbitrary.sql index 6c0a931dc..2d1cab39b 100644 --- a/src/test/regress/sql/merge_arbitrary.sql +++ b/src/test/regress/sql/merge_arbitrary.sql @@ -1,11 +1,3 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif - SET search_path TO merge_arbitrary_schema; INSERT INTO target_cj VALUES (1, 'target', 0); INSERT INTO target_cj VALUES (2, 'target', 0); diff --git a/src/test/regress/sql/merge_arbitrary_create.sql b/src/test/regress/sql/merge_arbitrary_create.sql index efa3185da..4255ca307 100644 --- a/src/test/regress/sql/merge_arbitrary_create.sql +++ b/src/test/regress/sql/merge_arbitrary_create.sql @@ -1,11 +1,3 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif - DROP SCHEMA IF EXISTS merge_arbitrary_schema CASCADE; CREATE SCHEMA merge_arbitrary_schema; SET search_path TO merge_arbitrary_schema; diff --git a/src/test/regress/sql/merge_partition_tables.sql b/src/test/regress/sql/merge_partition_tables.sql index ab40fd23e..64fb0799e 100644 --- a/src/test/regress/sql/merge_partition_tables.sql +++ b/src/test/regress/sql/merge_partition_tables.sql @@ -1,12 +1,3 @@ - -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif - -- We create two sets of source and target tables, one set in Postgres and -- the other in Citus distributed. We run the _exact_ MERGE SQL on both sets -- and compare the final results of the target tables in Postgres and Citus. diff --git a/src/test/regress/sql/merge_repartition1.sql b/src/test/regress/sql/merge_repartition1.sql index 858f4710c..d0f4b6e56 100644 --- a/src/test/regress/sql/merge_repartition1.sql +++ b/src/test/regress/sql/merge_repartition1.sql @@ -1,11 +1,3 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif - -- We create two sets of source and target tables, one set in Postgres and -- the other in Citus distributed. We run the _exact_ MERGE SQL on both sets -- and compare the final results of the target tables in Postgres and Citus. diff --git a/src/test/regress/sql/merge_repartition2.sql b/src/test/regress/sql/merge_repartition2.sql index 7a4812274..354f0605b 100644 --- a/src/test/regress/sql/merge_repartition2.sql +++ b/src/test/regress/sql/merge_repartition2.sql @@ -1,12 +1,3 @@ - -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif - -- We create two sets of source and target tables, one set in Postgres and -- the other in Citus distributed. We run the _exact_ MERGE SQL on both sets -- and compare the final results of the target tables in Postgres and Citus. diff --git a/src/test/regress/sql/merge_schema_sharding.sql b/src/test/regress/sql/merge_schema_sharding.sql index 8ea947c1c..d7fc0007f 100644 --- a/src/test/regress/sql/merge_schema_sharding.sql +++ b/src/test/regress/sql/merge_schema_sharding.sql @@ -1,11 +1,3 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif - -- MERGE command performs a join from data_source to target_table_name DROP SCHEMA IF EXISTS schema_shard_table1 CASCADE; DROP SCHEMA IF EXISTS schema_shard_table2 CASCADE; diff --git a/src/test/regress/sql/merge_vcore.sql b/src/test/regress/sql/merge_vcore.sql index 2ab95e874..e34f998c0 100644 --- a/src/test/regress/sql/merge_vcore.sql +++ b/src/test/regress/sql/merge_vcore.sql @@ -1,11 +1,3 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif - -- MERGE command performs a join from data_source to target_table_name DROP SCHEMA IF EXISTS merge_vcore_schema CASCADE; --MERGE INTO target diff --git a/src/test/regress/sql/multi_alter_table_add_constraints_without_name.sql b/src/test/regress/sql/multi_alter_table_add_constraints_without_name.sql index f5fd653f5..206decaa7 100644 --- a/src/test/regress/sql/multi_alter_table_add_constraints_without_name.sql +++ b/src/test/regress/sql/multi_alter_table_add_constraints_without_name.sql @@ -158,14 +158,8 @@ ALTER TABLE AT_AddConstNoName.products DROP CONSTRAINT products_product_no_key; -- Check "ADD UNIQUE NULLS NOT DISTICT" -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 - ALTER TABLE AT_AddConstNoName.products ADD UNIQUE NULLS NOT DISTINCT (product_no, price); ALTER TABLE AT_AddConstNoName.products DROP CONSTRAINT products_product_no_price_key; -\endif -- Check "ADD UNIQUE ... DEFERRABLE" ALTER TABLE AT_AddConstNoName.products ADD UNIQUE(product_no) INCLUDE(price) DEFERRABLE; diff --git a/src/test/regress/sql/multi_deparse_shard_query.sql b/src/test/regress/sql/multi_deparse_shard_query.sql index faffdf862..2bd11c811 100644 --- a/src/test/regress/sql/multi_deparse_shard_query.sql +++ b/src/test/regress/sql/multi_deparse_shard_query.sql @@ -1,12 +1,6 @@ -- -- MULTI_DEPARSE_SHARD_QUERY -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; CREATE SCHEMA multi_deparse_shard_query; SET search_path TO multi_deparse_shard_query; diff --git a/src/test/regress/sql/multi_extension.sql b/src/test/regress/sql/multi_extension.sql index e0c70fe28..b5b61e329 100644 --- a/src/test/regress/sql/multi_extension.sql +++ b/src/test/regress/sql/multi_extension.sql @@ -320,14 +320,8 @@ SELECT * FROM multi_extension.print_extension_changes(); -- recreate public schema, and recreate citus_tables in the public schema by default CREATE SCHEMA public; --- In PG15, public schema is owned by pg_database_owner role --- Relevant PG commit: b073c3ccd06e4cb845e121387a43faa8c68a7b62 -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 +-- public schema is owned by pg_database_owner role ALTER SCHEMA public OWNER TO pg_database_owner; -\endif GRANT ALL ON SCHEMA public TO public; ALTER EXTENSION citus UPDATE TO '9.5-1'; ALTER EXTENSION citus UPDATE TO '10.0-4'; diff --git a/src/test/regress/sql/multi_insert_select.sql b/src/test/regress/sql/multi_insert_select.sql index b10be8424..b773ce906 100644 --- a/src/test/regress/sql/multi_insert_select.sql +++ b/src/test/regress/sql/multi_insert_select.sql @@ -1,14 +1,9 @@ -- -- MULTI_INSERT_SELECT -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- + CREATE SCHEMA multi_insert_select; SET search_path = multi_insert_select,public; -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; SET citus.next_shard_id TO 13300000; SET citus.next_placement_id TO 13300000; diff --git a/src/test/regress/sql/multi_insert_select_conflict.sql b/src/test/regress/sql/multi_insert_select_conflict.sql index cb0ac01f5..06822933c 100644 --- a/src/test/regress/sql/multi_insert_select_conflict.sql +++ b/src/test/regress/sql/multi_insert_select_conflict.sql @@ -1,12 +1,6 @@ -- -- MULTI_INSERT_SELECT_CONFLICT -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; CREATE SCHEMA on_conflict; SET search_path TO on_conflict, public; diff --git a/src/test/regress/sql/multi_metadata_sync.sql b/src/test/regress/sql/multi_metadata_sync.sql index 1b8043cdd..9c584c1ac 100644 --- a/src/test/regress/sql/multi_metadata_sync.sql +++ b/src/test/regress/sql/multi_metadata_sync.sql @@ -1,11 +1,6 @@ -- -- MULTI_METADATA_SYNC -- --- this test has different output for PG14 compared to PG15 --- In PG15, public schema is owned by pg_database_owner role --- Relevant PG commit: b073c3ccd06e4cb845e121387a43faa8c68a7b62 -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; -- Tests for metadata snapshot functions, metadata syncing functions and propagation of -- metadata changes to MX tables. diff --git a/src/test/regress/sql/multi_mx_insert_select_repartition.sql b/src/test/regress/sql/multi_mx_insert_select_repartition.sql index b206c6e4e..4d4a5772f 100644 --- a/src/test/regress/sql/multi_mx_insert_select_repartition.sql +++ b/src/test/regress/sql/multi_mx_insert_select_repartition.sql @@ -3,12 +3,6 @@ -- -- Test behaviour of repartitioned INSERT ... SELECT in MX setup -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; CREATE SCHEMA multi_mx_insert_select_repartition; SET search_path TO multi_mx_insert_select_repartition; diff --git a/src/test/regress/sql/mx_coordinator_shouldhaveshards.sql b/src/test/regress/sql/mx_coordinator_shouldhaveshards.sql index 9a892a457..d8d304351 100644 --- a/src/test/regress/sql/mx_coordinator_shouldhaveshards.sql +++ b/src/test/regress/sql/mx_coordinator_shouldhaveshards.sql @@ -1,12 +1,6 @@ -- -- MX_COORDINATOR_SHOULDHAVESHARDS -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; CREATE SCHEMA mx_coordinator_shouldhaveshards; SET search_path TO mx_coordinator_shouldhaveshards; diff --git a/src/test/regress/sql/pg15.sql b/src/test/regress/sql/pg15.sql index a2e79ba5a..96eec9bb2 100644 --- a/src/test/regress/sql/pg15.sql +++ b/src/test/regress/sql/pg15.sql @@ -1,13 +1,6 @@ -- -- PG15 -- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif CREATE SCHEMA pg15; SET search_path TO pg15; diff --git a/src/test/regress/sql/pg15_jsonpath.sql b/src/test/regress/sql/pg15_jsonpath.sql index 1f4077c11..f5c5916a0 100644 --- a/src/test/regress/sql/pg15_jsonpath.sql +++ b/src/test/regress/sql/pg15_jsonpath.sql @@ -2,14 +2,6 @@ -- PG15 jsonpath tests -- Relevant pg commit: e26114c817b610424010cfbe91a743f591246ff1 -- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif - CREATE SCHEMA jsonpath; SET search_path TO jsonpath; diff --git a/src/test/regress/sql/pgmerge.sql b/src/test/regress/sql/pgmerge.sql index 69a0210bc..eeeb881d3 100644 --- a/src/test/regress/sql/pgmerge.sql +++ b/src/test/regress/sql/pgmerge.sql @@ -1,11 +1,3 @@ -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -\q -\endif - -- -- MERGE test from PG community (adapted to Citus by converting all tables to Citus local) -- diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql index 70baf6726..3aca4f505 100644 --- a/src/test/regress/sql/publication.sql +++ b/src/test/regress/sql/publication.sql @@ -186,19 +186,6 @@ DROP PUBLICATION "pub-all"; DROP PUBLICATION pubpartitioned; DROP PUBLICATION pubnotdistributed; -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 -\gset -\if :server_version_ge_15 -\else -SET client_min_messages TO ERROR; -DROP SCHEMA publication CASCADE; -DROP SCHEMA "publication-1" CASCADE; -DROP SCHEMA citus_schema_1 CASCADE; -SELECT public.wait_for_resource_cleanup(); -\q -\endif - -- recreate a mixed publication CREATE PUBLICATION pubtables FOR TABLE test, "publication-1"."test-pubs", citus_schema_1.test; diff --git a/src/test/regress/sql/single_node.sql b/src/test/regress/sql/single_node.sql index 2bb7c58a3..962f59f79 100644 --- a/src/test/regress/sql/single_node.sql +++ b/src/test/regress/sql/single_node.sql @@ -1,12 +1,6 @@ -- -- SINGLE_NODE -- --- This test file has an alternative output because of the change in the --- display of SQL-standard function's arguments in INSERT/SELECT in PG15. --- The alternative output can be deleted when we drop support for PG14 --- -SHOW server_version \gset -SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15; CREATE SCHEMA single_node; SET search_path TO single_node;