public inbox for [email protected]help / color / mirror / Atom feed
[PATCH 04/12] wal_compression_method: default to zlib.. 104+ messages / 4 participants [nested] [flat]
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --0qVF/w3MHQqLSynd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 4/8] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --f0KYrhQ4vYSV2aJu Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --0qVF/w3MHQqLSynd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --jozmn01XJZjDjM3N Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 4/8] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --f0KYrhQ4vYSV2aJu Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --jozmn01XJZjDjM3N Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 4/8] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --f0KYrhQ4vYSV2aJu Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --jozmn01XJZjDjM3N Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --0qVF/w3MHQqLSynd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --jozmn01XJZjDjM3N Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 4/8] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --f0KYrhQ4vYSV2aJu Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --0qVF/w3MHQqLSynd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --jozmn01XJZjDjM3N Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --jozmn01XJZjDjM3N Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --jozmn01XJZjDjM3N Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 4/8] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --f0KYrhQ4vYSV2aJu Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 4/8] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --f0KYrhQ4vYSV2aJu Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --jozmn01XJZjDjM3N Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH v9 4/9] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f7909aa1d7..3254c42243 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -98,7 +98,7 @@ char *XLogArchiveCommand = NULL; bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; -int wal_compression = WAL_COMPRESSION_NONE; +int wal_compression = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index ce1149bed5..14a2203225 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -4822,7 +4822,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression, - WAL_COMPRESSION_NONE, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --neYutvxvOLaeuPCA Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v9-0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --0qVF/w3MHQqLSynd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 4/8] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --f0KYrhQ4vYSV2aJu Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --jozmn01XJZjDjM3N Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --jozmn01XJZjDjM3N Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --0qVF/w3MHQqLSynd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 4/8] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --f0KYrhQ4vYSV2aJu Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --0qVF/w3MHQqLSynd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --0qVF/w3MHQqLSynd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 4/8] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --f0KYrhQ4vYSV2aJu Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --0qVF/w3MHQqLSynd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --jozmn01XJZjDjM3N Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 4/8] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --f0KYrhQ4vYSV2aJu Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --jozmn01XJZjDjM3N Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 4/8] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --f0KYrhQ4vYSV2aJu Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 4/8] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --f0KYrhQ4vYSV2aJu Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --0qVF/w3MHQqLSynd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 4/8] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --f0KYrhQ4vYSV2aJu Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --jozmn01XJZjDjM3N Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --0qVF/w3MHQqLSynd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 4/8] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --f0KYrhQ4vYSV2aJu Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --0qVF/w3MHQqLSynd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH v7 4/9] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 18dd4ff1eb..a43e04fc0b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 99932582ba..a448267ee9 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1311,7 +1311,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4832,7 +4832,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --JYK4vJDZwFMowpUq Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v7-0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 4/8] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --f0KYrhQ4vYSV2aJu Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --0qVF/w3MHQqLSynd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --jozmn01XJZjDjM3N Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --jozmn01XJZjDjM3N Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH v8 4/9] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 18d8743715..bbac9ac882 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -98,7 +98,7 @@ char *XLogArchiveCommand = NULL; bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; -int wal_compression = WAL_COMPRESSION_NONE; +int wal_compression = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8860deda2a..f1d73c8b61 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -4822,7 +4822,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression, - WAL_COMPRESSION_NONE, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --P+33d92oIH25kiaB Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v8-0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 4/8] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --f0KYrhQ4vYSV2aJu Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --0qVF/w3MHQqLSynd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 4/8] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --f0KYrhQ4vYSV2aJu Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --jozmn01XJZjDjM3N Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --jozmn01XJZjDjM3N Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --jozmn01XJZjDjM3N Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/12] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 8db3727502..3ece007922 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 47d30d6cda..15649bd2a7 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1288,7 +1288,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4767,7 +4767,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --45Z9DzgjV8m4Oswq Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --0qVF/w3MHQqLSynd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --jozmn01XJZjDjM3N Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --0qVF/w3MHQqLSynd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 4/8] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --f0KYrhQ4vYSV2aJu Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 4/8] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --f0KYrhQ4vYSV2aJu Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --0qVF/w3MHQqLSynd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 4/8] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --f0KYrhQ4vYSV2aJu Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --0qVF/w3MHQqLSynd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --0qVF/w3MHQqLSynd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --0qVF/w3MHQqLSynd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --jozmn01XJZjDjM3N Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --0qVF/w3MHQqLSynd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --0qVF/w3MHQqLSynd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/12] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 8db3727502..3ece007922 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 47d30d6cda..15649bd2a7 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1288,7 +1288,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4767,7 +4767,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --45Z9DzgjV8m4Oswq Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 4/8] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --f0KYrhQ4vYSV2aJu Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --jozmn01XJZjDjM3N Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --jozmn01XJZjDjM3N Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 4/8] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --f0KYrhQ4vYSV2aJu Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 4/8] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --f0KYrhQ4vYSV2aJu Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --jozmn01XJZjDjM3N Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 4/8] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --f0KYrhQ4vYSV2aJu Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --jozmn01XJZjDjM3N Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6eb46ea8a7..f5d4450654 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --0qVF/w3MHQqLSynd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH 04/10] wal_compression_method: default to zlib.. @ 2021-03-11 23:36 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Justin Pryzby @ 2021-03-11 23:36 UTC (permalink / raw) this is meant to exercise the CIs, and not meant to be merged --- src/backend/access/transam/xlog.c | 2 +- src/backend/utils/misc/guc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0183589b4d..8bae73b4ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -99,7 +99,7 @@ bool EnableHotStandby = false; bool fullPageWrites = true; bool wal_log_hints = false; bool wal_compression = false; -int wal_compression_method = WAL_COMPRESSION_PGLZ; +int wal_compression_method = WAL_COMPRESSION_ZLIB; char *wal_consistency_checking_string = NULL; bool *wal_consistency_checking = NULL; bool wal_init_zero = true; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8084027465..c37a8313d3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1269,7 +1269,7 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &wal_compression, - false, + true, NULL, NULL, NULL }, @@ -4728,7 +4728,7 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_compression_method, - WAL_COMPRESSION_PGLZ, wal_compression_options, + WAL_COMPRESSION_ZLIB, wal_compression_options, NULL, NULL, NULL }, -- 2.17.0 --0qVF/w3MHQqLSynd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0005-re-add-wal_compression_method-lz4.patch" ^ permalink raw reply [nested|flat] 104+ messages in thread
* Re: Support run-time partition pruning for hash join @ 2024-01-27 03:29 vignesh C <[email protected]> 2024-01-30 02:33 ` Re: Support run-time partition pruning for hash join Richard Guo <[email protected]> 0 siblings, 1 reply; 104+ messages in thread From: vignesh C @ 2024-01-27 03:29 UTC (permalink / raw) To: Richard Guo <[email protected]>; +Cc: Alexander Lakhin <[email protected]>; David Rowley <[email protected]>; Andy Fan <[email protected]>; pgsql-hackers On Tue, 7 Nov 2023 at 13:25, Richard Guo <[email protected]> wrote: > > > On Mon, Nov 6, 2023 at 11:00 PM Alexander Lakhin <[email protected]> wrote: >> >> Please look at a warning and an assertion failure triggered by the >> following script: >> set parallel_setup_cost = 0; >> set parallel_tuple_cost = 0; >> set min_parallel_table_scan_size = '1kB'; >> >> create table t1 (i int) partition by range (i); >> create table t1_1 partition of t1 for values from (1) to (2); >> create table t1_2 partition of t1 for values from (2) to (3); >> insert into t1 values (1), (2); >> >> create table t2(i int); >> insert into t2 values (1), (2); >> analyze t1, t2; >> >> select * from t1 right join t2 on t1.i = t2.i; >> >> 2023-11-06 14:11:37.398 UTC|law|regression|6548f419.392cf5|WARNING: Join partition pruning $0 has not been performed yet. >> TRAP: failed Assert("node->as_prune_state"), File: "nodeAppend.c", Line: 846, PID: 3747061 > > > Thanks for the report! I failed to take care of the parallel-hashjoin > case, and I have to admit that it's not clear to me yet how we should do > join partition pruning in that case. > > For now I think it's better to just avoid performing join partition > pruning for parallel hashjoin, so that the patch doesn't become too > complex for review. We can always extend it in the future. > > I have done that in v5. Thanks for testing! CFBot shows that the patch does not apply anymore as in [1]: === Applying patches on top of PostgreSQL commit ID 924d046dcf55887c98a1628675a30f4b0eebe556 === === applying patch ./v5-0001-Support-run-time-partition-pruning-for-hash-join.patch ... patching file src/include/nodes/plannodes.h ... patching file src/include/optimizer/cost.h Hunk #1 FAILED at 211. 1 out of 1 hunk FAILED -- saving rejects to file src/include/optimizer/cost.h.rej Please post an updated version for the same. [1] - http://cfbot.cputube.org/patch_46_4512.log Regards, Vignesh ^ permalink raw reply [nested|flat] 104+ messages in thread
* Re: Support run-time partition pruning for hash join 2024-01-27 03:29 Re: Support run-time partition pruning for hash join vignesh C <[email protected]> @ 2024-01-30 02:33 ` Richard Guo <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Richard Guo @ 2024-01-30 02:33 UTC (permalink / raw) To: vignesh C <[email protected]>; +Cc: Alexander Lakhin <[email protected]>; David Rowley <[email protected]>; Andy Fan <[email protected]>; pgsql-hackers On Sat, Jan 27, 2024 at 11:29 AM vignesh C <[email protected]> wrote: > CFBot shows that the patch does not apply anymore as in [1]: > > Please post an updated version for the same. Attached is an updated patch. Nothing else has changed. Thanks Richard Attachments: [application/octet-stream] v6-0001-Support-run-time-partition-pruning-for-hash-join.patch (59.3K, ../../CAMbWs49Pg9TvDrWBHzBDNPe7XP1jTpHukG-nwpNEo-mmr9h4zA@mail.gmail.com/3-v6-0001-Support-run-time-partition-pruning-for-hash-join.patch) download | inline diff: From 05d18d47135ba086fe416c02abdaa44b69612c03 Mon Sep 17 00:00:00 2001 From: Richard Guo <[email protected]> Date: Mon, 14 Aug 2023 14:55:26 +0800 Subject: [PATCH v6] Support run-time partition pruning for hash join If we have a hash join with an Append node on the outer side, something like Hash Join Hash Cond: (pt.a = t.a) -> Append -> Seq Scan on pt_p1 pt_1 -> Seq Scan on pt_p2 pt_2 -> Seq Scan on pt_p3 pt_3 -> Hash -> Seq Scan on t We can actually prune those subnodes of the Append that cannot possibly contain any matching tuples from the other side of the join. To do that, when building the Hash table, for each row from the inner side we can compute the minimum set of subnodes that can possibly match the join condition. When we have built the Hash table and start to execute the Append node, we should have known which subnodes are survived and thus can skip other subnodes. This patch implements this idea. --- src/backend/commands/explain.c | 61 ++++ src/backend/executor/execPartition.c | 127 +++++++- src/backend/executor/nodeAppend.c | 32 +- src/backend/executor/nodeHash.c | 75 +++++ src/backend/executor/nodeHashjoin.c | 10 + src/backend/executor/nodeMergeAppend.c | 22 +- src/backend/optimizer/path/costsize.c | 106 +++++++ src/backend/optimizer/plan/createplan.c | 49 ++- src/backend/optimizer/plan/setrefs.c | 61 ++++ src/backend/partitioning/partprune.c | 298 ++++++++++++++++-- src/include/executor/execPartition.h | 17 +- src/include/nodes/execnodes.h | 3 + src/include/nodes/pathnodes.h | 3 + src/include/nodes/plannodes.h | 36 +++ src/include/optimizer/cost.h | 4 + src/include/partitioning/partprune.h | 12 +- src/test/regress/expected/partition_prune.out | 86 +++++ src/test/regress/sql/partition_prune.sql | 39 +++ 18 files changed, 992 insertions(+), 49 deletions(-) diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 83d00a4663..04450b9c37 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -18,6 +18,7 @@ #include "commands/createas.h" #include "commands/defrem.h" #include "commands/prepare.h" +#include "executor/execPartition.h" #include "executor/nodeHash.h" #include "foreign/fdwapi.h" #include "jit/jit.h" @@ -118,6 +119,9 @@ static void show_instrumentation_count(const char *qlabel, int which, PlanState *planstate, ExplainState *es); static void show_foreignscan_info(ForeignScanState *fsstate, ExplainState *es); static void show_eval_params(Bitmapset *bms_params, ExplainState *es); +static void show_join_pruning_result_info(Bitmapset *join_prune_paramids, + ExplainState *es); +static void show_joinpartprune_info(HashState *hashstate, ExplainState *es); static const char *explain_get_index_name(Oid indexId); static bool peek_buffer_usage(ExplainState *es, const BufferUsage *usage); static void show_buffer_usage(ExplainState *es, const BufferUsage *usage); @@ -2104,9 +2108,17 @@ ExplainNode(PlanState *planstate, List *ancestors, show_incremental_sort_info(castNode(IncrementalSortState, planstate), es); break; + case T_Append: + if (es->verbose) + show_join_pruning_result_info(((Append *) plan)->join_prune_paramids, + es); + break; case T_MergeAppend: show_merge_append_keys(castNode(MergeAppendState, planstate), ancestors, es); + if (es->verbose) + show_join_pruning_result_info(((MergeAppend *) plan)->join_prune_paramids, + es); break; case T_Result: show_upper_qual((List *) ((Result *) plan)->resconstantqual, @@ -2122,6 +2134,8 @@ ExplainNode(PlanState *planstate, List *ancestors, break; case T_Hash: show_hash_info(castNode(HashState, planstate), es); + if (es->verbose) + show_joinpartprune_info(castNode(HashState, planstate), es); break; case T_Memoize: show_memoize_info(castNode(MemoizeState, planstate), ancestors, @@ -3562,6 +3576,53 @@ show_eval_params(Bitmapset *bms_params, ExplainState *es) ExplainPropertyList("Params Evaluated", params, es); } +/* + * Show join partition pruning results at Append/MergeAppend nodes. + */ +static void +show_join_pruning_result_info(Bitmapset *join_prune_paramids, ExplainState *es) +{ + int paramid = -1; + List *params = NIL; + + if (bms_is_empty(join_prune_paramids)) + return; + + while ((paramid = bms_next_member(join_prune_paramids, paramid)) >= 0) + { + char param[32]; + + snprintf(param, sizeof(param), "$%d", paramid); + params = lappend(params, pstrdup(param)); + } + + ExplainPropertyList("Join Partition Pruning", params, es); +} + +/* + * Show join partition pruning infos at Hash nodes. + */ +static void +show_joinpartprune_info(HashState *hashstate, ExplainState *es) +{ + List *params = NIL; + ListCell *lc; + + if (!hashstate->joinpartprune_state_list) + return; + + foreach(lc, hashstate->joinpartprune_state_list) + { + JoinPartitionPruneState *jpstate = (JoinPartitionPruneState *) lfirst(lc); + char param[32]; + + snprintf(param, sizeof(param), "$%d", jpstate->paramid); + params = lappend(params, pstrdup(param)); + } + + ExplainPropertyList("Partition Prune", params, es); +} + /* * Fetch the name of an index in an EXPLAIN * diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index b22040ae8e..95c791633c 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -199,6 +199,8 @@ static void find_matching_subplans_recurse(PartitionPruningData *prunedata, PartitionedRelPruningData *pprune, bool initial_prune, Bitmapset **validsubplans); +static bool get_join_prune_matching_subplans(PlanState *planstate, + Bitmapset **partset); /* @@ -1806,7 +1808,7 @@ ExecInitPartitionPruning(PlanState *planstate, * Perform an initial partition prune pass, if required. */ if (prunestate->do_initial_prune) - *initially_valid_subplans = ExecFindMatchingSubPlans(prunestate, true); + *initially_valid_subplans = ExecFindMatchingSubPlans(prunestate, true, NULL); else { /* No pruning, so we'll need to initialize all subplans */ @@ -1836,6 +1838,37 @@ ExecInitPartitionPruning(PlanState *planstate, return prunestate; } +/* + * ExecInitJoinpartpruneList + * Initialize data structures needed for join partition pruning + */ +List * +ExecInitJoinpartpruneList(PlanState *planstate, + List *joinpartprune_info_list) +{ + ListCell *lc; + List *result = NIL; + + foreach(lc, joinpartprune_info_list) + { + JoinPartitionPruneInfo *jpinfo = (JoinPartitionPruneInfo *) lfirst(lc); + JoinPartitionPruneState *jpstate = palloc(sizeof(JoinPartitionPruneState)); + + jpstate->part_prune_state = + CreatePartitionPruneState(planstate, jpinfo->part_prune_info); + Assert(jpstate->part_prune_state->do_exec_prune); + + jpstate->paramid = jpinfo->paramid; + jpstate->nplans = jpinfo->nplans; + jpstate->finished = false; + jpstate->part_prune_result = NULL; + + result = lappend(result, jpstate); + } + + return result; +} + /* * CreatePartitionPruneState * Build the data structure required for calling ExecFindMatchingSubPlans @@ -2273,7 +2306,9 @@ PartitionPruneFixSubPlanMap(PartitionPruneState *prunestate, /* * ExecFindMatchingSubPlans * Determine which subplans match the pruning steps detailed in - * 'prunestate' for the current comparison expression values. + * 'prunestate' if any for the current comparison expression values, and + * meanwhile match the join partition pruning results if any stored in + * Append/MergeAppend node's join_prune_paramids. * * Pass initial_prune if PARAM_EXEC Params cannot yet be evaluated. This * differentiates the initial executor-time pruning step from later @@ -2281,11 +2316,30 @@ PartitionPruneFixSubPlanMap(PartitionPruneState *prunestate, */ Bitmapset * ExecFindMatchingSubPlans(PartitionPruneState *prunestate, - bool initial_prune) + bool initial_prune, + PlanState *planstate) { Bitmapset *result = NULL; MemoryContext oldcontext; int i; + Bitmapset *join_prune_partset = NULL; + bool do_join_prune; + + /* Retrieve the join partition pruning results if any */ + do_join_prune = + get_join_prune_matching_subplans(planstate, &join_prune_partset); + + /* + * Either we're here on partition prune done according to the pruning steps + * detailed in 'prunestate', or we have done join partition prune. + */ + Assert(do_join_prune || prunestate != NULL); + + /* + * If there is no 'prunestate', then rely entirely on join pruning. + */ + if (prunestate == NULL) + return join_prune_partset; /* * Either we're here on the initial prune done during pruning @@ -2326,6 +2380,10 @@ ExecFindMatchingSubPlans(PartitionPruneState *prunestate, /* Add in any subplans that partition pruning didn't account for */ result = bms_add_members(result, prunestate->other_subplans); + /* Intersect join partition pruning results */ + if (do_join_prune) + result = bms_intersect(result, join_prune_partset); + MemoryContextSwitchTo(oldcontext); /* Copy result out of the temp context before we reset it */ @@ -2396,3 +2454,66 @@ find_matching_subplans_recurse(PartitionPruningData *prunedata, } } } + +/* + * get_join_prune_matching_subplans + * Retrieve the join partition pruning results if any stored in + * Append/MergeAppend node's join_prune_paramids. Return true if we can + * do join partition pruning, otherwise return false. + * + * Adds valid (non-prunable) subplan IDs to *partset + */ +static bool +get_join_prune_matching_subplans(PlanState *planstate, Bitmapset **partset) +{ + Bitmapset *join_prune_paramids; + int nplans; + int paramid; + + if (planstate == NULL) + return false; + + if (IsA(planstate, AppendState)) + { + join_prune_paramids = + ((Append *) planstate->plan)->join_prune_paramids; + nplans = ((AppendState *) planstate)->as_nplans; + } + else if (IsA(planstate, MergeAppendState)) + { + join_prune_paramids = + ((MergeAppend *) planstate->plan)->join_prune_paramids; + nplans = ((MergeAppendState *) planstate)->ms_nplans; + } + else + { + elog(ERROR, "unrecognized node type: %d", (int) nodeTag(planstate)); + return false; + } + + if (bms_is_empty(join_prune_paramids)) + return false; + + Assert(nplans > 0); + *partset = bms_add_range(NULL, 0, nplans - 1); + + paramid = -1; + while ((paramid = bms_next_member(join_prune_paramids, paramid)) >= 0) + { + ParamExecData *param; + JoinPartitionPruneState *jpstate; + + param = &(planstate->state->es_param_exec_vals[paramid]); + Assert(param->execPlan == NULL); + Assert(!param->isnull); + jpstate = (JoinPartitionPruneState *) DatumGetPointer(param->value); + + if (jpstate != NULL) + *partset = bms_intersect(*partset, jpstate->part_prune_result); + else /* the Hash node for this pruning has not been executed */ + elog(WARNING, "Join partition pruning $%d has not been performed yet.", + paramid); + } + + return true; +} diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c index c7059e7528..b68a1e2eb2 100644 --- a/src/backend/executor/nodeAppend.c +++ b/src/backend/executor/nodeAppend.c @@ -151,11 +151,13 @@ ExecInitAppend(Append *node, EState *estate, int eflags) nplans = bms_num_members(validsubplans); /* - * When no run-time pruning is required and there's at least one - * subplan, we can fill as_valid_subplans immediately, preventing - * later calls to ExecFindMatchingSubPlans. + * When no run-time pruning or join pruning is required and there's at + * least one subplan, we can fill as_valid_subplans immediately, + * preventing later calls to ExecFindMatchingSubPlans. */ - if (!prunestate->do_exec_prune && nplans > 0) + if (!prunestate->do_exec_prune && + bms_is_empty(node->join_prune_paramids) && + nplans > 0) { appendstate->as_valid_subplans = bms_add_range(NULL, 0, nplans - 1); appendstate->as_valid_subplans_identified = true; @@ -170,10 +172,18 @@ ExecInitAppend(Append *node, EState *estate, int eflags) * subplans as valid; they must also all be initialized. */ Assert(nplans > 0); - appendstate->as_valid_subplans = validsubplans = - bms_add_range(NULL, 0, nplans - 1); - appendstate->as_valid_subplans_identified = true; + validsubplans = bms_add_range(NULL, 0, nplans - 1); appendstate->as_prune_state = NULL; + + /* + * When join pruning is not enabled we can fill as_valid_subplans + * immediately, preventing later calls to ExecFindMatchingSubPlans. + */ + if (bms_is_empty(node->join_prune_paramids)) + { + appendstate->as_valid_subplans = validsubplans; + appendstate->as_valid_subplans_identified = true; + } } /* @@ -580,7 +590,7 @@ choose_next_subplan_locally(AppendState *node) else if (!node->as_valid_subplans_identified) { node->as_valid_subplans = - ExecFindMatchingSubPlans(node->as_prune_state, false); + ExecFindMatchingSubPlans(node->as_prune_state, false, &node->ps); node->as_valid_subplans_identified = true; } @@ -647,7 +657,7 @@ choose_next_subplan_for_leader(AppendState *node) if (!node->as_valid_subplans_identified) { node->as_valid_subplans = - ExecFindMatchingSubPlans(node->as_prune_state, false); + ExecFindMatchingSubPlans(node->as_prune_state, false, &node->ps); node->as_valid_subplans_identified = true; /* @@ -723,7 +733,7 @@ choose_next_subplan_for_worker(AppendState *node) else if (!node->as_valid_subplans_identified) { node->as_valid_subplans = - ExecFindMatchingSubPlans(node->as_prune_state, false); + ExecFindMatchingSubPlans(node->as_prune_state, false, &node->ps); node->as_valid_subplans_identified = true; mark_invalid_subplans_as_finished(node); @@ -876,7 +886,7 @@ ExecAppendAsyncBegin(AppendState *node) if (!node->as_valid_subplans_identified) { node->as_valid_subplans = - ExecFindMatchingSubPlans(node->as_prune_state, false); + ExecFindMatchingSubPlans(node->as_prune_state, false, &node->ps); node->as_valid_subplans_identified = true; classify_matching_subplans(node); diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c index f90e16ede8..00138a61a2 100644 --- a/src/backend/executor/nodeHash.c +++ b/src/backend/executor/nodeHash.c @@ -31,6 +31,7 @@ #include "catalog/pg_statistic.h" #include "commands/tablespace.h" #include "executor/execdebug.h" +#include "executor/execPartition.h" #include "executor/hashjoin.h" #include "executor/nodeHash.h" #include "executor/nodeHashjoin.h" @@ -48,6 +49,8 @@ static void ExecHashIncreaseNumBatches(HashJoinTable hashtable); static void ExecHashIncreaseNumBuckets(HashJoinTable hashtable); static void ExecParallelHashIncreaseNumBatches(HashJoinTable hashtable); static void ExecParallelHashIncreaseNumBuckets(HashJoinTable hashtable); +static void ExecJoinPartitionPrune(HashState *node); +static void ExecStoreJoinPartitionPruneResult(HashState *node); static void ExecHashBuildSkewHash(HashJoinTable hashtable, Hash *node, int mcvsToUse); static void ExecHashSkewTableInsert(HashJoinTable hashtable, @@ -189,8 +192,14 @@ MultiExecPrivateHash(HashState *node) } hashtable->totalTuples += 1; } + + /* Perform join partition pruning */ + ExecJoinPartitionPrune(node); } + /* Store the surviving partitions for Append/MergeAppend nodes */ + ExecStoreJoinPartitionPruneResult(node); + /* resize the hash table if needed (NTUP_PER_BUCKET exceeded) */ if (hashtable->nbuckets != hashtable->nbuckets_optimal) ExecHashIncreaseNumBuckets(hashtable); @@ -401,6 +410,12 @@ ExecInitHash(Hash *node, EState *estate, int eflags) hashstate->hashkeys = ExecInitExprList(node->hashkeys, (PlanState *) hashstate); + /* + * initialize join partition pruning infos + */ + hashstate->joinpartprune_state_list = + ExecInitJoinpartpruneList(&hashstate->ps, node->joinpartprune_info_list); + return hashstate; } @@ -1610,6 +1625,56 @@ ExecParallelHashIncreaseNumBuckets(HashJoinTable hashtable) } } +/* + * ExecJoinPartitionPrune + * Perform join partition pruning at this join for each + * JoinPartitionPruneState. + */ +static void +ExecJoinPartitionPrune(HashState *node) +{ + ListCell *lc; + + foreach(lc, node->joinpartprune_state_list) + { + JoinPartitionPruneState *jpstate = (JoinPartitionPruneState *) lfirst(lc); + Bitmapset *matching_subPlans; + + if (jpstate->finished) + continue; + + matching_subPlans = + ExecFindMatchingSubPlans(jpstate->part_prune_state, false, NULL); + jpstate->part_prune_result = + bms_add_members(jpstate->part_prune_result, matching_subPlans); + + if (bms_num_members(jpstate->part_prune_result) == jpstate->nplans) + jpstate->finished = true; + } +} + +/* + * ExecStoreJoinPartitionPruneResult + * For each JoinPartitionPruneState, store the set of surviving partitions + * to make it available for the Append/MergeAppend node. + */ +static void +ExecStoreJoinPartitionPruneResult(HashState *node) +{ + ListCell *lc; + + foreach(lc, node->joinpartprune_state_list) + { + JoinPartitionPruneState *jpstate = (JoinPartitionPruneState *) lfirst(lc); + ParamExecData *param; + + param = &(node->ps.state->es_param_exec_vals[jpstate->paramid]); + Assert(param->execPlan == NULL); + Assert(!param->isnull); + param->value = PointerGetDatum(jpstate); + } +} + /* * ExecHashTableInsert * insert a tuple into the hash table depending on the hash value @@ -2354,6 +2419,16 @@ void ExecReScanHash(HashState *node) { PlanState *outerPlan = outerPlanState(node); + ListCell *lc; + + /* reset the state in JoinPartitionPruneStates */ + foreach(lc, node->joinpartprune_state_list) + { + JoinPartitionPruneState *jpstate = (JoinPartitionPruneState *) lfirst(lc); + + jpstate->finished = false; + jpstate->part_prune_result = NULL; + } /* * if chgParam of subnode is not null then plan will be re-scanned by diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c index 1cbec4647c..4f84799929 100644 --- a/src/backend/executor/nodeHashjoin.c +++ b/src/backend/executor/nodeHashjoin.c @@ -311,6 +311,16 @@ ExecHashJoinImpl(PlanState *pstate, bool parallel) */ node->hj_FirstOuterTupleSlot = NULL; } + else if (hashNode->joinpartprune_state_list != NIL) + { + /* + * Give the hash node a chance to run join partition + * pruning if there is any JoinPartitionPruneState that can + * be evaluated at it. So do not apply the empty-outer + * optimization in this case. + */ + node->hj_FirstOuterTupleSlot = NULL; + } else if (HJ_FILL_OUTER(node) || (outerNode->plan->startup_cost < hashNode->ps.plan->total_cost && !node->hj_OuterNotEmpty)) diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c index 0817868452..ec0ac29654 100644 --- a/src/backend/executor/nodeMergeAppend.c +++ b/src/backend/executor/nodeMergeAppend.c @@ -99,11 +99,13 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags) nplans = bms_num_members(validsubplans); /* - * When no run-time pruning is required and there's at least one - * subplan, we can fill ms_valid_subplans immediately, preventing - * later calls to ExecFindMatchingSubPlans. + * When no run-time pruning or join pruning is required and there's at + * least one subplan, we can fill ms_valid_subplans immediately, + * preventing later calls to ExecFindMatchingSubPlans. */ - if (!prunestate->do_exec_prune && nplans > 0) + if (!prunestate->do_exec_prune && + bms_is_empty(node->join_prune_paramids) && + nplans > 0) mergestate->ms_valid_subplans = bms_add_range(NULL, 0, nplans - 1); } else @@ -115,9 +117,15 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags) * subplans as valid; they must also all be initialized. */ Assert(nplans > 0); - mergestate->ms_valid_subplans = validsubplans = - bms_add_range(NULL, 0, nplans - 1); + validsubplans = bms_add_range(NULL, 0, nplans - 1); mergestate->ms_prune_state = NULL; + + /* + * When join pruning is not enabled we can fill ms_valid_subplans + * immediately, preventing later calls to ExecFindMatchingSubPlans. + */ + if (bms_is_empty(node->join_prune_paramids)) + mergestate->ms_valid_subplans = validsubplans; } mergeplanstates = (PlanState **) palloc(nplans * sizeof(PlanState *)); @@ -218,7 +226,7 @@ ExecMergeAppend(PlanState *pstate) */ if (node->ms_valid_subplans == NULL) node->ms_valid_subplans = - ExecFindMatchingSubPlans(node->ms_prune_state, false); + ExecFindMatchingSubPlans(node->ms_prune_state, false, &node->ps); /* * First time through: pull the first tuple from each valid subplan, diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 8b76e98529..ea3d5e57c1 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -173,6 +173,10 @@ static void get_restriction_qual_cost(PlannerInfo *root, RelOptInfo *baserel, static bool has_indexed_join_quals(NestPath *path); static double approx_tuple_count(PlannerInfo *root, JoinPath *path, List *quals); +static double get_joinrel_matching_outer_size(PlannerInfo *root, + RelOptInfo *outer_rel, + Relids inner_relids, + List *restrictlist); static double calc_joinrel_size_estimate(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outer_rel, @@ -5409,6 +5413,61 @@ get_parameterized_joinrel_size(PlannerInfo *root, RelOptInfo *rel, return nrows; } +/* + * get_joinrel_matching_outer_size + * Make a size estimate for the outer side that matches the inner side. + */ +static double +get_joinrel_matching_outer_size(PlannerInfo *root, + RelOptInfo *outer_rel, + Relids inner_relids, + List *restrictlist) +{ + double nrows; + Selectivity fkselec; + Selectivity jselec; + SpecialJoinInfo *sjinfo; + SpecialJoinInfo sjinfo_data; + + sjinfo = &sjinfo_data; + sjinfo->type = T_SpecialJoinInfo; + sjinfo->min_lefthand = outer_rel->relids; + sjinfo->min_righthand = inner_relids; + sjinfo->syn_lefthand = outer_rel->relids; + sjinfo->syn_righthand = inner_relids; + sjinfo->jointype = JOIN_SEMI; + sjinfo->ojrelid = 0; + sjinfo->commute_above_l = NULL; + sjinfo->commute_above_r = NULL; + sjinfo->commute_below_l = NULL; + sjinfo->commute_below_r = NULL; + /* we don't bother trying to make the remaining fields valid */ + sjinfo->lhs_strict = false; + sjinfo->semi_can_btree = false; + sjinfo->semi_can_hash = false; + sjinfo->semi_operators = NIL; + sjinfo->semi_rhs_exprs = NIL; + + fkselec = get_foreign_key_join_selectivity(root, + outer_rel->relids, + inner_relids, + sjinfo, + &restrictlist); + jselec = clauselist_selectivity(root, + restrictlist, + 0, + sjinfo->jointype, + sjinfo); + + nrows = outer_rel->rows * fkselec * jselec; + nrows = clamp_row_est(nrows); + + /* For safety, make sure result is not more than the base estimate */ + if (nrows > outer_rel->rows) + nrows = outer_rel->rows; + return nrows; +} + /* * calc_joinrel_size_estimate * Workhorse for set_joinrel_size_estimates and @@ -6530,3 +6589,50 @@ compute_bitmap_pages(PlannerInfo *root, RelOptInfo *baserel, return pages_fetched; } + +/* + * compute_partprune_cost + * Compute the overhead of join partition pruning. + */ +double +compute_partprune_cost(PlannerInfo *root, RelOptInfo *appendrel, + Cost append_total_cost, int append_nplans, + Relids inner_relids, double inner_rows, + List *prunequal) +{ + Cost prune_cost; + Cost saved_cost; + double matching_outer_rows; + double unmatched_nplans; + + switch (appendrel->part_scheme->strategy) + { + + case PARTITION_STRATEGY_LIST: + case PARTITION_STRATEGY_RANGE: + prune_cost = cpu_operator_cost * LOG2(append_nplans) * inner_rows; + break; + case PARTITION_STRATEGY_HASH: + prune_cost = cpu_operator_cost * append_nplans * inner_rows; + break; + default: + elog(ERROR, "unexpected partition strategy: %d", + (int) appendrel->part_scheme->strategy); + break; + } + + matching_outer_rows = + get_joinrel_matching_outer_size(root, + appendrel, + inner_relids, + prunequal); + + /* + * We assume that each outer joined row occupies one new partition. This + * is really the worst case. + */ + unmatched_nplans = append_nplans - Min(matching_outer_rows, append_nplans); + saved_cost = (unmatched_nplans / append_nplans) * append_total_cost; + + return prune_cost - saved_cost; +} diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 610f4a56d6..55cd3bb616 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -242,7 +242,8 @@ static Hash *make_hash(Plan *lefttree, List *hashkeys, Oid skewTable, AttrNumber skewColumn, - bool skewInherit); + bool skewInherit, + List *joinpartprune_info_list); static MergeJoin *make_mergejoin(List *tlist, List *joinclauses, List *otherclauses, List *mergeclauses, @@ -342,6 +343,7 @@ create_plan(PlannerInfo *root, Path *best_path) /* Initialize this module's workspace in PlannerInfo */ root->curOuterRels = NULL; root->curOuterParams = NIL; + root->join_partition_prune_candidates = NIL; /* Recursively process the path tree, demanding the correct tlist result */ plan = create_plan_recurse(root, best_path, CP_EXACT_TLIST); @@ -369,6 +371,8 @@ create_plan(PlannerInfo *root, Path *best_path) if (root->curOuterParams != NIL) elog(ERROR, "failed to assign all NestLoopParams to plan nodes"); + Assert(root->join_partition_prune_candidates == NIL); + /* * Reset plan_params to ensure param IDs used for nestloop params are not * re-used later @@ -1223,6 +1227,7 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags) int nasyncplans = 0; RelOptInfo *rel = best_path->path.parent; PartitionPruneInfo *partpruneinfo = NULL; + Bitmapset *join_prune_paramids = NULL; int nodenumsortkeys = 0; AttrNumber *nodeSortColIdx = NULL; Oid *nodeSortOperators = NULL; @@ -1377,6 +1382,8 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags) * If any quals exist, they may be useful to perform further partition * pruning during execution. Gather information needed by the executor to * do partition pruning. + * + * Also gather information needed by the executor to do join pruning. */ if (enable_partition_pruning) { @@ -1399,13 +1406,20 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags) partpruneinfo = make_partition_pruneinfo(root, rel, best_path->subpaths, - prunequal); + prunequal, + NULL); + + join_prune_paramids = + make_join_partition_pruneinfos(root, rel, + (Path *) best_path, + best_path->subpaths); } plan->appendplans = subplans; plan->nasyncplans = nasyncplans; plan->first_partial_plan = best_path->first_partial_path; plan->part_prune_info = partpruneinfo; + plan->join_prune_paramids = join_prune_paramids; copy_generic_path_info(&plan->plan, (Path *) best_path); @@ -1445,6 +1459,7 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path, ListCell *subpaths; RelOptInfo *rel = best_path->path.parent; PartitionPruneInfo *partpruneinfo = NULL; + Bitmapset *join_prune_paramids = NULL; /* * We don't have the actual creation of the MergeAppend node split out @@ -1541,6 +1556,8 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path, * If any quals exist, they may be useful to perform further partition * pruning during execution. Gather information needed by the executor to * do partition pruning. + * + * Also gather information needed by the executor to do join pruning. */ if (enable_partition_pruning) { @@ -1554,11 +1571,18 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path, if (prunequal != NIL) partpruneinfo = make_partition_pruneinfo(root, rel, best_path->subpaths, - prunequal); + prunequal, + NULL); + + join_prune_paramids = + make_join_partition_pruneinfos(root, rel, + (Path *) best_path, + best_path->subpaths); } node->mergeplans = subplans; node->part_prune_info = partpruneinfo; + node->join_prune_paramids = join_prune_paramids; /* * If prepare_sort_from_pathkeys added sort columns, but we were told to @@ -4743,6 +4767,13 @@ create_hashjoin_plan(PlannerInfo *root, AttrNumber skewColumn = InvalidAttrNumber; bool skewInherit = false; ListCell *lc; + List *joinpartprune_info_list; + + /* + * Collect information required to build JoinPartitionPruneInfos at this + * join. + */ + prepare_join_partition_prune_candidate(root, &best_path->jpath); /* * HashJoin can project, so we don't have to demand exact tlists from the @@ -4754,6 +4785,11 @@ create_hashjoin_plan(PlannerInfo *root, outer_plan = create_plan_recurse(root, best_path->jpath.outerjoinpath, (best_path->num_batches > 1) ? CP_SMALL_TLIST : 0); + /* + * Retrieve all the JoinPartitionPruneInfos for this join. + */ + joinpartprune_info_list = get_join_partition_prune_candidate(root); + inner_plan = create_plan_recurse(root, best_path->jpath.innerjoinpath, CP_SMALL_TLIST); @@ -4859,7 +4895,8 @@ create_hashjoin_plan(PlannerInfo *root, inner_hashkeys, skewTable, skewColumn, - skewInherit); + skewInherit, + joinpartprune_info_list); /* * Set Hash node's startup & total costs equal to total cost of input @@ -5986,7 +6023,8 @@ make_hash(Plan *lefttree, List *hashkeys, Oid skewTable, AttrNumber skewColumn, - bool skewInherit) + bool skewInherit, + List *joinpartprune_info_list) { Hash *node = makeNode(Hash); Plan *plan = &node->plan; @@ -6000,6 +6038,7 @@ make_hash(Plan *lefttree, node->skewTable = skewTable; node->skewColumn = skewColumn; node->skewInherit = skewInherit; + node->joinpartprune_info_list = joinpartprune_info_list; return node; } diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 22a1fa29f3..c83d3bc0ad 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -156,6 +156,11 @@ static Plan *set_mergeappend_references(PlannerInfo *root, MergeAppend *mplan, int rtoffset); static void set_hash_references(PlannerInfo *root, Plan *plan, int rtoffset); +static void set_joinpartitionprune_references(PlannerInfo *root, + List *joinpartprune_info_list, + indexed_tlist *outer_itlist, + int rtoffset, + double num_exec); static Relids offset_relid_set(Relids relids, int rtoffset); static Node *fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset, double num_exec); @@ -1897,6 +1902,62 @@ set_hash_references(PlannerInfo *root, Plan *plan, int rtoffset) /* Hash nodes don't have their own quals */ Assert(plan->qual == NIL); + + set_joinpartitionprune_references(root, + hplan->joinpartprune_info_list, + outer_itlist, + rtoffset, + NUM_EXEC_TLIST(plan)); +} + +/* + * set_joinpartitionprune_references + * Do set_plan_references processing on JoinPartitionPruneInfos + */ +static void +set_joinpartitionprune_references(PlannerInfo *root, + List *joinpartprune_info_list, + indexed_tlist *outer_itlist, + int rtoffset, + double num_exec) +{ + ListCell *l; + + foreach(l, joinpartprune_info_list) + { + JoinPartitionPruneInfo *jpinfo = (JoinPartitionPruneInfo *) lfirst(l); + ListCell *l1; + + foreach(l1, jpinfo->part_prune_info->prune_infos) + { + List *prune_infos = lfirst(l1); + ListCell *l2; + + foreach(l2, prune_infos) + { + PartitionedRelPruneInfo *pinfo = lfirst(l2); + + pinfo->rtindex += rtoffset; + + pinfo->initial_pruning_steps = (List *) + fix_upper_expr(root, + (Node *) pinfo->initial_pruning_steps, + outer_itlist, + OUTER_VAR, + rtoffset, + NRM_EQUAL, + num_exec); + pinfo->exec_pruning_steps = (List *) + fix_upper_expr(root, + (Node *) pinfo->exec_pruning_steps, + outer_itlist, + OUTER_VAR, + rtoffset, + NRM_EQUAL, + num_exec); + } + } + } } /* diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c index 6b635e8ad1..17725aa972 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -48,7 +48,9 @@ #include "optimizer/appendinfo.h" #include "optimizer/cost.h" #include "optimizer/optimizer.h" +#include "optimizer/paramassign.h" #include "optimizer/pathnode.h" +#include "optimizer/restrictinfo.h" #include "parser/parsetree.h" #include "partitioning/partbounds.h" #include "partitioning/partprune.h" @@ -103,15 +105,16 @@ typedef enum PartClauseTarget * * gen_partprune_steps() initializes and returns an instance of this struct. * - * Note that has_mutable_op, has_mutable_arg, and has_exec_param are set if - * we found any potentially-useful-for-pruning clause having those properties, - * whether or not we actually used the clause in the steps list. This - * definition allows us to skip the PARTTARGET_EXEC pass in some cases. + * Note that has_mutable_op, has_mutable_arg, has_exec_param and has_vars are + * set if we found any potentially-useful-for-pruning clause having those + * properties, whether or not we actually used the clause in the steps list. + * This definition allows us to skip the PARTTARGET_EXEC pass in some cases. */ typedef struct GeneratePruningStepsContext { /* Copies of input arguments for gen_partprune_steps: */ RelOptInfo *rel; /* the partitioned relation */ + Bitmapset *available_rels; /* rels whose Vars may be used for pruning */ PartClauseTarget target; /* use-case we're generating steps for */ /* Result data: */ List *steps; /* list of PartitionPruneSteps */ @@ -119,6 +122,7 @@ typedef struct GeneratePruningStepsContext bool has_mutable_arg; /* clauses include any mutable comparison * values, *other than* exec params */ bool has_exec_param; /* clauses include any PARAM_EXEC params */ + bool has_vars; /* clauses include any Vars from 'available_rels' */ bool contradictory; /* clauses were proven self-contradictory */ /* Working state: */ int next_step_id; @@ -144,8 +148,10 @@ static List *make_partitionedrel_pruneinfo(PlannerInfo *root, List *prunequal, Bitmapset *partrelids, int *relid_subplan_map, + Bitmapset *available_rels, Bitmapset **matchedsubplans); static void gen_partprune_steps(RelOptInfo *rel, List *clauses, + Bitmapset *available_rels, PartClauseTarget target, GeneratePruningStepsContext *context); static List *gen_partprune_steps_internal(GeneratePruningStepsContext *context, @@ -204,6 +210,10 @@ static PartClauseMatchStatus match_boolean_partition_clause(Oid partopfamily, static void partkey_datum_from_expr(PartitionPruneContext *context, Expr *expr, int stateidx, Datum *value, bool *isnull); +static bool contain_forbidden_var_clause(Node *node, + GeneratePruningStepsContext *context); +static bool contain_forbidden_var_clause_walker(Node *node, + GeneratePruningStepsContext *context); /* @@ -216,11 +226,14 @@ static void partkey_datum_from_expr(PartitionPruneContext *context, * of scan paths for its child rels. * 'prunequal' is a list of potential pruning quals (i.e., restriction * clauses that are applicable to the appendrel). + * 'available_rels' is the relid set of rels whose Vars may be used for + * pruning. */ PartitionPruneInfo * make_partition_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, List *subpaths, - List *prunequal) + List *prunequal, + Bitmapset *available_rels) { PartitionPruneInfo *pruneinfo; Bitmapset *allmatchedsubplans = NULL; @@ -313,6 +326,7 @@ make_partition_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, prunequal, partrelids, relid_subplan_map, + available_rels, &matchedsubplans); /* When pruning is possible, record the matched subplans */ @@ -360,6 +374,184 @@ make_partition_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, return pruneinfo; } +/* + * make_join_partition_pruneinfos + * Builds one JoinPartitionPruneInfo for each join at which join partition + * pruning is possible for this appendrel. + * + * 'parentrel' is the RelOptInfo for an appendrel, and 'subpaths' is the list + * of scan paths for its child rels. + */ +Bitmapset * +make_join_partition_pruneinfos(PlannerInfo *root, RelOptInfo *parentrel, + Path *best_path, List *subpaths) +{ + Bitmapset *result = NULL; + ListCell *lc; + + if (!IS_PARTITIONED_REL(parentrel)) + return NULL; + + foreach(lc, root->join_partition_prune_candidates) + { + JoinPartitionPruneCandidateInfo *candidate = + (JoinPartitionPruneCandidateInfo *) lfirst(lc); + PartitionPruneInfo *part_prune_info; + List *prunequal; + Relids joinrelids; + ListCell *l; + double prune_cost; + + if (candidate == NULL) + continue; + + /* + * Identify all joinclauses that are movable to this appendrel given + * this inner side relids. Only those clauses can be used for join + * partition pruning. + */ + joinrelids = bms_union(parentrel->relids, candidate->inner_relids); + prunequal = NIL; + foreach(l, candidate->joinrestrictinfo) + { + RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); + + if (join_clause_is_movable_into(rinfo, + parentrel->relids, + joinrelids)) + prunequal = lappend(prunequal, rinfo); + } + + if (prunequal == NIL) + continue; + + /* + * Check the overhead of this pruning + */ + prune_cost = compute_partprune_cost(root, + parentrel, + best_path->total_cost, + list_length(subpaths), + candidate->inner_relids, + candidate->inner_rows, + prunequal); + if (prune_cost > 0) + continue; + + part_prune_info = make_partition_pruneinfo(root, parentrel, + subpaths, + prunequal, + candidate->inner_relids); + + if (part_prune_info) + { + JoinPartitionPruneInfo *jpinfo; + + jpinfo = makeNode(JoinPartitionPruneInfo); + + jpinfo->part_prune_info = part_prune_info; + jpinfo->paramid = assign_special_exec_param(root); + jpinfo->nplans = list_length(subpaths); + + candidate->joinpartprune_info_list = + lappend(candidate->joinpartprune_info_list, jpinfo); + + result = bms_add_member(result, jpinfo->paramid); + } + } + + return result; +} + +/* + * prepare_join_partition_prune_candidate + * Check if join partition pruning is possible at this join and if so + * collect information required to build JoinPartitionPruneInfos. + * + * Note that we may build more than one JoinPartitionPruneInfo at one join, for + * different Append/MergeAppend paths. + */ +void +prepare_join_partition_prune_candidate(PlannerInfo *root, JoinPath *jpath) +{ + JoinPartitionPruneCandidateInfo *candidate; + + if (!enable_partition_pruning) + { + root->join_partition_prune_candidates = + lappend(root->join_partition_prune_candidates, NULL); + return; + } + + /* + * For now do not perform join partition pruning for parallel hashjoin. + */ + if (jpath->path.parallel_workers > 0) + { + root->join_partition_prune_candidates = + lappend(root->join_partition_prune_candidates, NULL); + return; + } + + /* + * We cannot perform join partition pruning if the outer is the + * non-nullable side. + */ + if (!(jpath->jointype == JOIN_INNER || + jpath->jointype == JOIN_SEMI || + jpath->jointype == JOIN_RIGHT || + jpath->jointype == JOIN_RIGHT_ANTI)) + { + root->join_partition_prune_candidates = + lappend(root->join_partition_prune_candidates, NULL); + return; + } + + /* + * For now we only support HashJoin. + */ + if (jpath->path.pathtype != T_HashJoin) + { + root->join_partition_prune_candidates = + lappend(root->join_partition_prune_candidates, NULL); + return; + } + + candidate = makeNode(JoinPartitionPruneCandidateInfo); + candidate->joinrestrictinfo = jpath->joinrestrictinfo; + candidate->inner_relids = jpath->innerjoinpath->parent->relids; + candidate->inner_rows = jpath->innerjoinpath->parent->rows; + candidate->joinpartprune_info_list = NIL; + + root->join_partition_prune_candidates = + lappend(root->join_partition_prune_candidates, candidate); +} + +/* + * get_join_partition_prune_candidate + * Pop out the JoinPartitionPruneCandidateInfo for this join and retrieve + * the JoinPartitionPruneInfos. + */ +List * +get_join_partition_prune_candidate(PlannerInfo *root) +{ + JoinPartitionPruneCandidateInfo *candidate; + List *result; + + candidate = llast(root->join_partition_prune_candidates); + root->join_partition_prune_candidates = + list_delete_last(root->join_partition_prune_candidates); + + if (candidate == NULL) + return NIL; + + result = candidate->joinpartprune_info_list; + + pfree(candidate); + + return result; +} + /* * add_part_relids * Add new info to a list of Bitmapsets of partitioned relids. @@ -428,6 +620,8 @@ add_part_relids(List *allpartrelids, Bitmapset *partrelids) * partrelids: Set of RT indexes identifying relevant partitioned tables * within a single partitioning hierarchy * relid_subplan_map[]: maps child relation relids to subplan indexes + * available_rels: the relid set of rels whose Vars may be used for + * pruning. * matchedsubplans: on success, receives the set of subplan indexes which * were matched to this partition hierarchy * @@ -440,6 +634,7 @@ make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, List *prunequal, Bitmapset *partrelids, int *relid_subplan_map, + Bitmapset *available_rels, Bitmapset **matchedsubplans) { RelOptInfo *targetpart = NULL; @@ -539,8 +734,8 @@ make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, * pruning steps and detects whether there's any possibly-useful quals * that would require per-scan pruning. */ - gen_partprune_steps(subpart, partprunequal, PARTTARGET_INITIAL, - &context); + gen_partprune_steps(subpart, partprunequal, available_rels, + PARTTARGET_INITIAL, &context); if (context.contradictory) { @@ -567,14 +762,15 @@ make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, initial_pruning_steps = NIL; /* - * If no exec Params appear in potentially-usable pruning clauses, - * then there's no point in even thinking about per-scan pruning. + * If no exec Params or available Vars appear in potentially-usable + * pruning clauses, then there's no point in even thinking about + * per-scan pruning. */ - if (context.has_exec_param) + if (context.has_exec_param || context.has_vars) { /* ... OK, we'd better think about it */ - gen_partprune_steps(subpart, partprunequal, PARTTARGET_EXEC, - &context); + gen_partprune_steps(subpart, partprunequal, available_rels, + PARTTARGET_EXEC, &context); if (context.contradictory) { @@ -587,11 +783,14 @@ make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, /* * Detect which exec Params actually got used; the fact that some * were in available clauses doesn't mean we actually used them. - * Skip per-scan pruning if there are none. */ execparamids = get_partkey_exec_paramids(exec_pruning_steps); - if (bms_is_empty(execparamids)) + /* + * Skip per-scan pruning if there are none used exec Params and + * there are none available Vars. + */ + if (bms_is_empty(execparamids) && !context.has_vars) exec_pruning_steps = NIL; } else @@ -703,6 +902,9 @@ make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, * Process 'clauses' (typically a rel's baserestrictinfo list of clauses) * and create a list of "partition pruning steps". * + * 'available_rels' is the relid set of rels whose Vars may be used for + * pruning. + * * 'target' tells whether to generate pruning steps for planning (use * immutable clauses only), or for executor startup (use any allowable * clause except ones containing PARAM_EXEC Params), or for executor @@ -712,12 +914,13 @@ make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, * some subsidiary flags; see the GeneratePruningStepsContext typedef. */ static void -gen_partprune_steps(RelOptInfo *rel, List *clauses, PartClauseTarget target, - GeneratePruningStepsContext *context) +gen_partprune_steps(RelOptInfo *rel, List *clauses, Bitmapset *available_rels, + PartClauseTarget target, GeneratePruningStepsContext *context) { /* Initialize all output values to zero/false/NULL */ memset(context, 0, sizeof(GeneratePruningStepsContext)); context->rel = rel; + context->available_rels = available_rels; context->target = target; /* @@ -773,7 +976,7 @@ prune_append_rel_partitions(RelOptInfo *rel) * If the clauses are found to be contradictory, we can return the empty * set. */ - gen_partprune_steps(rel, clauses, PARTTARGET_PLANNER, + gen_partprune_steps(rel, clauses, NULL, PARTTARGET_PLANNER, &gcontext); if (gcontext.contradictory) return NULL; @@ -1957,9 +2160,10 @@ match_clause_to_partition_key(GeneratePruningStepsContext *context, return PARTCLAUSE_UNSUPPORTED; /* - * We can never prune using an expression that contains Vars. + * We can never prune using an expression that contains Vars except + * for Vars belonging to context->available_rels. */ - if (contain_var_clause((Node *) expr)) + if (contain_forbidden_var_clause((Node *) expr, context)) return PARTCLAUSE_UNSUPPORTED; /* @@ -2155,9 +2359,10 @@ match_clause_to_partition_key(GeneratePruningStepsContext *context, return PARTCLAUSE_UNSUPPORTED; /* - * We can never prune using an expression that contains Vars. + * We can never prune using an expression that contains Vars except + * for Vars belonging to context->available_rels. */ - if (contain_var_clause((Node *) rightop)) + if (contain_forbidden_var_clause((Node *) rightop, context)) return PARTCLAUSE_UNSUPPORTED; /* @@ -3727,3 +3932,54 @@ partkey_datum_from_expr(PartitionPruneContext *context, *value = ExecEvalExprSwitchContext(exprstate, ectx, isnull); } } + +/* + * contain_forbidden_var_clause + * Recursively scan a clause to discover whether it contains any Var nodes + * (of the current query level) that do not belong to relations in + * context->available_rels. + * + * Returns true if any such varnode found. + * + * Does not examine subqueries, therefore must only be used after reduction + * of sublinks to subplans! + */ +static bool +contain_forbidden_var_clause(Node *node, GeneratePruningStepsContext *context) +{ + return contain_forbidden_var_clause_walker(node, context); +} + +static bool +contain_forbidden_var_clause_walker(Node *node, GeneratePruningStepsContext *context) +{ + if (node == NULL) + return false; + if (IsA(node, Var)) + { + Var *var = (Var *) node; + + if (var->varlevelsup != 0) + return false; + + if (!bms_is_member(var->varno, context->available_rels)) + return true; /* abort the tree traversal and return true */ + + context->has_vars = true; + + if (context->target != PARTTARGET_EXEC) + return true; /* abort the tree traversal and return true */ + + return false; + } + if (IsA(node, CurrentOfExpr)) + return true; + if (IsA(node, PlaceHolderVar)) + { + if (((PlaceHolderVar *) node)->phlevelsup == 0) + return true; /* abort the tree traversal and return true */ + /* else fall through to check the contained expr */ + } + return expression_tree_walker(node, contain_forbidden_var_clause_walker, + (void *) context); +} diff --git a/src/include/executor/execPartition.h b/src/include/executor/execPartition.h index c09bc83b2a..7e46f0baf6 100644 --- a/src/include/executor/execPartition.h +++ b/src/include/executor/execPartition.h @@ -121,11 +121,26 @@ typedef struct PartitionPruneState PartitionPruningData *partprunedata[FLEXIBLE_ARRAY_MEMBER]; } PartitionPruneState; +/* + * JoinPartitionPruneState - State object required for plan nodes to perform + * join partition pruning. + */ +typedef struct JoinPartitionPruneState +{ + PartitionPruneState *part_prune_state; + int paramid; + int nplans; + bool finished; + Bitmapset *part_prune_result; +} JoinPartitionPruneState; + extern PartitionPruneState *ExecInitPartitionPruning(PlanState *planstate, int n_total_subplans, PartitionPruneInfo *pruneinfo, Bitmapset **initially_valid_subplans); +extern List *ExecInitJoinpartpruneList(PlanState *planstate, List *joinpartprune_info_list); extern Bitmapset *ExecFindMatchingSubPlans(PartitionPruneState *prunestate, - bool initial_prune); + bool initial_prune, + PlanState *planstate); #endif /* EXECPARTITION_H */ diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 444a5f0fd5..8f02af1f10 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -2685,6 +2685,9 @@ typedef struct HashState /* Parallel hash state. */ struct ParallelHashJoinState *parallel_state; + + /* Infos for join partition pruning. */ + List *joinpartprune_state_list; } HashState; /* ---------------- diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h index 534692bee1..da7803448a 100644 --- a/src/include/nodes/pathnodes.h +++ b/src/include/nodes/pathnodes.h @@ -530,6 +530,9 @@ struct PlannerInfo /* not-yet-assigned NestLoopParams */ List *curOuterParams; + /* a stack of JoinPartitionPruneInfos */ + List *join_partition_prune_candidates; + /* * These fields are workspace for setrefs.c. Each is an array * corresponding to glob->subplans. (We could probably teach diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index b4ef6bc44c..964bc85123 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -275,6 +275,9 @@ typedef struct Append /* Info for run-time subplan pruning; NULL if we're not doing that */ struct PartitionPruneInfo *part_prune_info; + + /* Info for join partition pruning; NULL if we're not doing that */ + Bitmapset *join_prune_paramids; } Append; /* ---------------- @@ -310,6 +313,9 @@ typedef struct MergeAppend /* Info for run-time subplan pruning; NULL if we're not doing that */ struct PartitionPruneInfo *part_prune_info; + + /* Info for join partition pruning; NULL if we're not doing that */ + Bitmapset *join_prune_paramids; } MergeAppend; /* ---------------- @@ -1206,6 +1212,7 @@ typedef struct Hash bool skewInherit; /* is outer join rel an inheritance tree? */ /* all other info is in the parent HashJoin node */ Cardinality rows_total; /* estimate total rows if parallel_aware */ + List *joinpartprune_info_list; /* infos for join partition pruning */ } Hash; /* ---------------- @@ -1552,6 +1559,35 @@ typedef struct PartitionPruneStepCombine List *source_stepids; } PartitionPruneStepCombine; +/* + * JoinPartitionPruneCandidateInfo - Information required to build + * JoinPartitionPruneInfos. + */ +typedef struct JoinPartitionPruneCandidateInfo +{ + pg_node_attr(no_equal, no_query_jumble) + + NodeTag type; + List *joinrestrictinfo; + Bitmapset *inner_relids; + double inner_rows; + List *joinpartprune_info_list; +} JoinPartitionPruneCandidateInfo; + +/* + * JoinPartitionPruneInfo - Details required to allow the executor to prune + * partitions during join. + */ +typedef struct JoinPartitionPruneInfo +{ + pg_node_attr(no_equal, no_query_jumble) + + NodeTag type; + PartitionPruneInfo *part_prune_info; + int paramid; + int nplans; +} JoinPartitionPruneInfo; + /* * Plan invalidation info diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h index b1c51a4e70..5ccd3c62d4 100644 --- a/src/include/optimizer/cost.h +++ b/src/include/optimizer/cost.h @@ -212,5 +212,9 @@ extern PathTarget *set_pathtarget_cost_width(PlannerInfo *root, PathTarget *targ extern double compute_bitmap_pages(PlannerInfo *root, RelOptInfo *baserel, Path *bitmapqual, double loop_count, Cost *cost_p, double *tuples_p); +extern double compute_partprune_cost(PlannerInfo *root, RelOptInfo *appendrel, + Cost append_total_cost, int append_nplans, + Relids inner_relids, double inner_rows, + List *prunequal); #endif /* COST_H */ diff --git a/src/include/partitioning/partprune.h b/src/include/partitioning/partprune.h index bd490d154f..5187485c88 100644 --- a/src/include/partitioning/partprune.h +++ b/src/include/partitioning/partprune.h @@ -19,6 +19,8 @@ struct PlannerInfo; /* avoid including pathnodes.h here */ struct RelOptInfo; +struct Path; +struct JoinPath; /* @@ -73,7 +75,15 @@ typedef struct PartitionPruneContext extern PartitionPruneInfo *make_partition_pruneinfo(struct PlannerInfo *root, struct RelOptInfo *parentrel, List *subpaths, - List *prunequal); + List *prunequal, + Bitmapset *available_rels); +extern Bitmapset *make_join_partition_pruneinfos(struct PlannerInfo *root, + struct RelOptInfo *parentrel, + struct Path *best_path, + List *subpaths); +extern void prepare_join_partition_prune_candidate(struct PlannerInfo *root, + struct JoinPath *jpath); +extern List *get_join_partition_prune_candidate(struct PlannerInfo *root); extern Bitmapset *prune_append_rel_partitions(struct RelOptInfo *rel); extern Bitmapset *get_matching_partitions(PartitionPruneContext *context, List *pruning_steps); diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out index 9a4c48c055..a08e7a1f0a 100644 --- a/src/test/regress/expected/partition_prune.out +++ b/src/test/regress/expected/partition_prune.out @@ -3003,6 +3003,92 @@ order by tbl1.col1, tprt.col1; ------+------ (0 rows) +-- join partition pruning +-- The 'Memory Usage' from the Hash node can vary between machines. Let's just +-- replace the number with an 'N'. +-- We need to run EXPLAIN ANALYZE because we need to see '(never executed)' +-- notations because that's the only way to verify runtime pruning. +create function explain_join_partition_pruning(text) returns setof text +language plpgsql as +$$ +declare + ln text; +begin + for ln in + execute format('explain (analyze, verbose, costs off, summary off, timing off) %s', + $1) + loop + ln := regexp_replace(ln, 'Memory Usage: \d+', 'Memory Usage: N'); + return next ln; + end loop; +end; +$$; +delete from tbl1; +insert into tbl1 values (501), (505); +analyze tbl1, tprt; +set enable_nestloop = off; +set enable_mergejoin = off; +set enable_hashjoin = on; +select explain_join_partition_pruning(' +select * from tprt p1 + inner join tprt p2 on p1.col1 = p2.col1 + right join tbl1 t on p1.col1 = t.col1 and p2.col1 = t.col1;'); + explain_join_partition_pruning +-------------------------------------------------------------------------------- + Hash Right Join (actual rows=2 loops=1) + Output: p1.col1, p2.col1, t.col1 + Hash Cond: ((p1.col1 = t.col1) AND (p2.col1 = t.col1)) + -> Hash Join (actual rows=3 loops=1) + Output: p1.col1, p2.col1 + Hash Cond: (p1.col1 = p2.col1) + -> Append (actual rows=3 loops=1) + Join Partition Pruning: $0 + -> Seq Scan on public.tprt_1 p1_1 (never executed) + Output: p1_1.col1 + -> Seq Scan on public.tprt_2 p1_2 (actual rows=3 loops=1) + Output: p1_2.col1 + -> Seq Scan on public.tprt_3 p1_3 (never executed) + Output: p1_3.col1 + -> Seq Scan on public.tprt_4 p1_4 (never executed) + Output: p1_4.col1 + -> Seq Scan on public.tprt_5 p1_5 (never executed) + Output: p1_5.col1 + -> Seq Scan on public.tprt_6 p1_6 (never executed) + Output: p1_6.col1 + -> Hash (actual rows=3 loops=1) + Output: p2.col1 + Buckets: 1024 Batches: 1 Memory Usage: NkB + -> Append (actual rows=3 loops=1) + Join Partition Pruning: $1 + -> Seq Scan on public.tprt_1 p2_1 (never executed) + Output: p2_1.col1 + -> Seq Scan on public.tprt_2 p2_2 (actual rows=3 loops=1) + Output: p2_2.col1 + -> Seq Scan on public.tprt_3 p2_3 (never executed) + Output: p2_3.col1 + -> Seq Scan on public.tprt_4 p2_4 (never executed) + Output: p2_4.col1 + -> Seq Scan on public.tprt_5 p2_5 (never executed) + Output: p2_5.col1 + -> Seq Scan on public.tprt_6 p2_6 (never executed) + Output: p2_6.col1 + -> Hash (actual rows=2 loops=1) + Output: t.col1 + Buckets: 1024 Batches: 1 Memory Usage: NkB + Partition Prune: $0, $1 + -> Seq Scan on public.tbl1 t (actual rows=2 loops=1) + Output: t.col1 +(43 rows) + +select * from tprt p1 + inner join tprt p2 on p1.col1 = p2.col1 + right join tbl1 t on p1.col1 = t.col1 and p2.col1 = t.col1; + col1 | col1 | col1 +------+------+------ + 501 | 501 | 501 + 505 | 505 | 505 +(2 rows) + drop table tbl1, tprt; -- Test with columns defined in varying orders between each level create table part_abc (a int not null, b int not null, c int not null) partition by list (a); diff --git a/src/test/regress/sql/partition_prune.sql b/src/test/regress/sql/partition_prune.sql index 7bf3920827..fc5982edcf 100644 --- a/src/test/regress/sql/partition_prune.sql +++ b/src/test/regress/sql/partition_prune.sql @@ -727,6 +727,45 @@ select tbl1.col1, tprt.col1 from tbl1 inner join tprt on tbl1.col1 = tprt.col1 order by tbl1.col1, tprt.col1; +-- join partition pruning + +-- The 'Memory Usage' from the Hash node can vary between machines. Let's just +-- replace the number with an 'N'. +-- We need to run EXPLAIN ANALYZE because we need to see '(never executed)' +-- notations because that's the only way to verify runtime pruning. +create function explain_join_partition_pruning(text) returns setof text +language plpgsql as +$$ +declare + ln text; +begin + for ln in + execute format('explain (analyze, verbose, costs off, summary off, timing off) %s', + $1) + loop + ln := regexp_replace(ln, 'Memory Usage: \d+', 'Memory Usage: N'); + return next ln; + end loop; +end; +$$; + +delete from tbl1; +insert into tbl1 values (501), (505); +analyze tbl1, tprt; + +set enable_nestloop = off; +set enable_mergejoin = off; +set enable_hashjoin = on; + +select explain_join_partition_pruning(' +select * from tprt p1 + inner join tprt p2 on p1.col1 = p2.col1 + right join tbl1 t on p1.col1 = t.col1 and p2.col1 = t.col1;'); + +select * from tprt p1 + inner join tprt p2 on p1.col1 = p2.col1 + right join tbl1 t on p1.col1 = t.col1 and p2.col1 = t.col1; + drop table tbl1, tprt; -- Test with columns defined in varying orders between each level -- 2.31.0 ^ permalink raw reply [nested|flat] 104+ messages in thread
* [PATCH v2 1/1] move partitioning code out of tablecmds.c @ 2026-01-29 22:09 Nathan Bossart <[email protected]> 0 siblings, 0 replies; 104+ messages in thread From: Nathan Bossart @ 2026-01-29 22:09 UTC (permalink / raw) --- src/backend/commands/Makefile | 1 + src/backend/commands/meson.build | 1 + src/backend/commands/tablecmds.c | 4787 +------------------- src/backend/commands/tablecmds_partition.c | 4627 +++++++++++++++++++ src/backend/partitioning/partbounds.c | 1 + src/include/commands/tablecmds.h | 2 - src/include/commands/tablecmds_internal.h | 183 + src/include/commands/tablecmds_partition.h | 59 + 8 files changed, 4885 insertions(+), 4776 deletions(-) create mode 100644 src/backend/commands/tablecmds_partition.c create mode 100644 src/include/commands/tablecmds_internal.h create mode 100644 src/include/commands/tablecmds_partition.h diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile index 64cb6278409..764f75f6b52 100644 --- a/src/backend/commands/Makefile +++ b/src/backend/commands/Makefile @@ -57,6 +57,7 @@ OBJS = \ statscmds.o \ subscriptioncmds.o \ tablecmds.o \ + tablecmds_partition.o \ tablespace.o \ trigger.o \ tsearchcmds.o \ diff --git a/src/backend/commands/meson.build b/src/backend/commands/meson.build index ca3f53c6213..86b9d8780fd 100644 --- a/src/backend/commands/meson.build +++ b/src/backend/commands/meson.build @@ -45,6 +45,7 @@ backend_sources += files( 'statscmds.c', 'subscriptioncmds.c', 'tablecmds.c', + 'tablecmds_partition.c', 'tablespace.c', 'trigger.c', 'tsearchcmds.c', diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index f976c0e5c7e..4abba13a5b8 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -62,6 +62,8 @@ #include "commands/event_trigger.h" #include "commands/sequence.h" #include "commands/tablecmds.h" +#include "commands/tablecmds_internal.h" +#include "commands/tablecmds_partition.h" #include "commands/tablespace.h" #include "commands/trigger.h" #include "commands/typecmds.h" @@ -131,115 +133,6 @@ typedef struct OnCommitItem static List *on_commits = NIL; - -/* - * State information for ALTER TABLE - * - * The pending-work queue for an ALTER TABLE is a List of AlteredTableInfo - * structs, one for each table modified by the operation (the named table - * plus any child tables that are affected). We save lists of subcommands - * to apply to this table (possibly modified by parse transformation steps); - * these lists will be executed in Phase 2. If a Phase 3 step is needed, - * necessary information is stored in the constraints and newvals lists. - * - * Phase 2 is divided into multiple passes; subcommands are executed in - * a pass determined by subcommand type. - */ - -typedef enum AlterTablePass -{ - AT_PASS_UNSET = -1, /* UNSET will cause ERROR */ - AT_PASS_DROP, /* DROP (all flavors) */ - AT_PASS_ALTER_TYPE, /* ALTER COLUMN TYPE */ - AT_PASS_ADD_COL, /* ADD COLUMN */ - AT_PASS_SET_EXPRESSION, /* ALTER SET EXPRESSION */ - AT_PASS_OLD_INDEX, /* re-add existing indexes */ - AT_PASS_OLD_CONSTR, /* re-add existing constraints */ - /* We could support a RENAME COLUMN pass here, but not currently used */ - AT_PASS_ADD_CONSTR, /* ADD constraints (initial examination) */ - AT_PASS_COL_ATTRS, /* set column attributes, eg NOT NULL */ - AT_PASS_ADD_INDEXCONSTR, /* ADD index-based constraints */ - AT_PASS_ADD_INDEX, /* ADD indexes */ - AT_PASS_ADD_OTHERCONSTR, /* ADD other constraints, defaults */ - AT_PASS_MISC, /* other stuff */ -} AlterTablePass; - -#define AT_NUM_PASSES (AT_PASS_MISC + 1) - -typedef struct AlteredTableInfo -{ - /* Information saved before any work commences: */ - Oid relid; /* Relation to work on */ - char relkind; /* Its relkind */ - TupleDesc oldDesc; /* Pre-modification tuple descriptor */ - - /* - * Transiently set during Phase 2, normally set to NULL. - * - * ATRewriteCatalogs sets this when it starts, and closes when ATExecCmd - * returns control. This can be exploited by ATExecCmd subroutines to - * close/reopen across transaction boundaries. - */ - Relation rel; - - /* Information saved by Phase 1 for Phase 2: */ - List *subcmds[AT_NUM_PASSES]; /* Lists of AlterTableCmd */ - /* Information saved by Phases 1/2 for Phase 3: */ - List *constraints; /* List of NewConstraint */ - List *newvals; /* List of NewColumnValue */ - List *afterStmts; /* List of utility command parsetrees */ - bool verify_new_notnull; /* T if we should recheck NOT NULL */ - int rewrite; /* Reason for forced rewrite, if any */ - bool chgAccessMethod; /* T if SET ACCESS METHOD is used */ - Oid newAccessMethod; /* new access method; 0 means no change, - * if above is true */ - Oid newTableSpace; /* new tablespace; 0 means no change */ - bool chgPersistence; /* T if SET LOGGED/UNLOGGED is used */ - char newrelpersistence; /* if above is true */ - Expr *partition_constraint; /* for attach partition validation */ - /* true, if validating default due to some other attach/detach */ - bool validate_default; - /* Objects to rebuild after completing ALTER TYPE operations */ - List *changedConstraintOids; /* OIDs of constraints to rebuild */ - List *changedConstraintDefs; /* string definitions of same */ - List *changedIndexOids; /* OIDs of indexes to rebuild */ - List *changedIndexDefs; /* string definitions of same */ - char *replicaIdentityIndex; /* index to reset as REPLICA IDENTITY */ - char *clusterOnIndex; /* index to use for CLUSTER */ - List *changedStatisticsOids; /* OIDs of statistics to rebuild */ - List *changedStatisticsDefs; /* string definitions of same */ -} AlteredTableInfo; - -/* Struct describing one new constraint to check in Phase 3 scan */ -/* Note: new not-null constraints are handled elsewhere */ -typedef struct NewConstraint -{ - char *name; /* Constraint name, or NULL if none */ - ConstrType contype; /* CHECK or FOREIGN */ - Oid refrelid; /* PK rel, if FOREIGN */ - Oid refindid; /* OID of PK's index, if FOREIGN */ - bool conwithperiod; /* Whether the new FOREIGN KEY uses PERIOD */ - Oid conid; /* OID of pg_constraint entry, if FOREIGN */ - Node *qual; /* Check expr or CONSTR_FOREIGN Constraint */ - ExprState *qualstate; /* Execution state for CHECK expr */ -} NewConstraint; - -/* - * Struct describing one new column value that needs to be computed during - * Phase 3 copy (this could be either a new column with a non-null default, or - * a column that we're changing the type of). Columns without such an entry - * are just copied from the old table during ATRewriteTable. Note that the - * expr is an expression over *old* table values, except when is_generated - * is true; then it is an expression over columns of the *new* tuple. - */ -typedef struct NewColumnValue -{ - AttrNumber attnum; /* which column */ - Expr *expr; /* expression to compute */ - ExprState *exprstate; /* execution state */ - bool is_generated; /* is it a GENERATED expression? */ -} NewColumnValue; - /* * Error-reporting support for RemoveRelations */ @@ -325,17 +218,6 @@ struct DropRelationCallbackState char actual_relpersistence; }; -/* Alter table target-type flags for ATSimplePermissions */ -#define ATT_TABLE 0x0001 -#define ATT_VIEW 0x0002 -#define ATT_MATVIEW 0x0004 -#define ATT_INDEX 0x0008 -#define ATT_COMPOSITE_TYPE 0x0010 -#define ATT_FOREIGN_TABLE 0x0020 -#define ATT_PARTITIONED_INDEX 0x0040 -#define ATT_SEQUENCE 0x0080 -#define ATT_PARTITIONED_TABLE 0x0100 - /* * ForeignTruncateInfo * @@ -350,14 +232,6 @@ typedef struct ForeignTruncateInfo List *rels; } ForeignTruncateInfo; -/* Partial or complete FK creation in addFkConstraint() */ -typedef enum addFkConstraintSides -{ - addFkReferencedSide, - addFkReferencingSide, - addFkBothSides, -} addFkConstraintSides; - /* * Partition tables are expected to be dropped when the parent partitioned * table gets dropped. Hence for partitioning we use AUTO dependency. @@ -431,8 +305,6 @@ static void AlterConstrUpdateConstraintEntry(ATAlterConstraint *cmdcon, Relation static ObjectAddress ATExecValidateConstraint(List **wqueue, Relation rel, char *constrName, bool recurse, bool recursing, LOCKMODE lockmode); -static void QueueFKConstraintValidation(List **wqueue, Relation conrel, Relation fkrel, - Oid pkrelid, HeapTuple contuple, LOCKMODE lockmode); static void QueueCheckConstraintValidation(List **wqueue, Relation conrel, Relation rel, char *constrName, HeapTuple contuple, bool recurse, bool recursing, LOCKMODE lockmode); @@ -455,7 +327,6 @@ static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId, static void validateForeignKeyConstraint(char *conname, Relation rel, Relation pkrel, Oid pkindOid, Oid constraintOid, bool hasperiod); -static void CheckAlterTableIsSafe(Relation rel); static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context); @@ -476,12 +347,9 @@ static void ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context); static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap); -static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel); -static void ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets); static void ATSimpleRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context); -static void ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode); static void ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context); @@ -508,8 +376,6 @@ static ObjectAddress ATExecSetNotNull(List **wqueue, Relation rel, bool recurse, bool recursing, LOCKMODE lockmode); static bool NotNullImpliedByRelConstraints(Relation rel, Form_pg_attribute attr); -static bool ConstraintImpliedByRelConstraint(Relation scanrel, - List *testConstraint, List *provenConstraint); static ObjectAddress ATExecColumnDefault(Relation rel, const char *colName, Node *newDefault, LOCKMODE lockmode); static ObjectAddress ATExecCookedColumnDefault(Relation rel, AttrNumber attnum, @@ -518,8 +384,6 @@ static ObjectAddress ATExecAddIdentity(Relation rel, const char *colName, Node *def, LOCKMODE lockmode, bool recurse, bool recursing); static ObjectAddress ATExecSetIdentity(Relation rel, const char *colName, Node *def, LOCKMODE lockmode, bool recurse, bool recursing); -static ObjectAddress ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode, - bool recurse, bool recursing); static ObjectAddress ATExecSetExpression(AlteredTableInfo *tab, Relation rel, const char *colName, Node *newExpr, LOCKMODE lockmode); static void ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode); @@ -565,37 +429,6 @@ static ObjectAddress ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo * static int validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums, int numfksetcols, int16 *fksetcolsattnums, List *fksetcols); -static ObjectAddress addFkConstraint(addFkConstraintSides fkside, - char *constraintname, - Constraint *fkconstraint, Relation rel, - Relation pkrel, Oid indexOid, - Oid parentConstr, - int numfks, int16 *pkattnum, int16 *fkattnum, - Oid *pfeqoperators, Oid *ppeqoperators, - Oid *ffeqoperators, int numfkdelsetcols, - int16 *fkdelsetcols, bool is_internal, - bool with_period); -static void addFkRecurseReferenced(Constraint *fkconstraint, - Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, - int numfks, int16 *pkattnum, int16 *fkattnum, - Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, - int numfkdelsetcols, int16 *fkdelsetcols, - bool old_check_ok, - Oid parentDelTrigger, Oid parentUpdTrigger, - bool with_period); -static void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, - Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, - int numfks, int16 *pkattnum, int16 *fkattnum, - Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, - int numfkdelsetcols, int16 *fkdelsetcols, - bool old_check_ok, LOCKMODE lockmode, - Oid parentInsTrigger, Oid parentUpdTrigger, - bool with_period); -static void CloneForeignKeyConstraints(List **wqueue, Relation parentRel, - Relation partitionRel); -static void CloneFkReferenced(Relation parentRel, Relation partitionRel); -static void CloneFkReferencing(List **wqueue, Relation parentRel, - Relation partRel); static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, @@ -606,31 +439,6 @@ static void createForeignKeyActionTriggers(Oid myRelOid, Oid refRelOid, Oid indexOid, Oid parentDelTrigger, Oid parentUpdTrigger, Oid *deleteTrigOid, Oid *updateTrigOid); -static bool tryAttachPartitionForeignKey(List **wqueue, - ForeignKeyCacheInfo *fk, - Relation partition, - Oid parentConstrOid, int numfks, - AttrNumber *mapped_conkey, AttrNumber *confkey, - Oid *conpfeqop, - Oid parentInsTrigger, - Oid parentUpdTrigger, - Relation trigrel); -static void AttachPartitionForeignKey(List **wqueue, Relation partition, - Oid partConstrOid, Oid parentConstrOid, - Oid parentInsTrigger, Oid parentUpdTrigger, - Relation trigrel); -static void RemoveInheritedConstraint(Relation conrel, Relation trigrel, - Oid conoid, Oid conrelid); -static void DropForeignKeyConstraintTriggers(Relation trigrel, Oid conoid, - Oid confrelid, Oid conrelid); -static void GetForeignKeyActionTriggers(Relation trigrel, - Oid conoid, Oid confrelid, Oid conrelid, - Oid *deleteTriggerOid, - Oid *updateTriggerOid); -static void GetForeignKeyCheckTriggers(Relation trigrel, - Oid conoid, Oid confrelid, Oid conrelid, - Oid *insertTriggerOid, - Oid *updateTriggerOid); static void ATExecDropConstraint(Relation rel, const char *constrName, DropBehavior behavior, bool recurse, bool missing_ok, LOCKMODE lockmode); @@ -707,45 +515,9 @@ static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid, void *arg); static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg); -static PartitionSpec *transformPartitionSpec(Relation rel, PartitionSpec *partspec); -static void ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs, - List **partexprs, Oid *partopclass, Oid *partcollation, - PartitionStrategy strategy); -static void CreateInheritance(Relation child_rel, Relation parent_rel, bool ispartition); -static void RemoveInheritance(Relation child_rel, Relation parent_rel, - bool expect_detached); -static ObjectAddress ATExecAttachPartition(List **wqueue, Relation rel, - PartitionCmd *cmd, - AlterTableUtilityContext *context); -static void AttachPartitionEnsureIndexes(List **wqueue, Relation rel, Relation attachrel); -static void QueuePartitionConstraintValidation(List **wqueue, Relation scanrel, - List *partConstraint, - bool validate_default); -static void CloneRowTriggersToPartition(Relation parent, Relation partition); -static void DropClonedTriggersFromPartition(Oid partitionId); -static ObjectAddress ATExecDetachPartition(List **wqueue, AlteredTableInfo *tab, - Relation rel, RangeVar *name, - bool concurrent); -static void DetachPartitionFinalize(Relation rel, Relation partRel, - bool concurrent, Oid defaultPartOid); -static ObjectAddress ATExecDetachPartitionFinalize(Relation rel, RangeVar *name); -static ObjectAddress ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx, - RangeVar *name); -static void validatePartitionedIndex(Relation partedIdx, Relation partedTbl); -static void refuseDupeIndexAttach(Relation parentIdx, Relation partIdx, - Relation partitionTbl); -static void verifyPartitionIndexNotNull(IndexInfo *iinfo, Relation partition); -static List *GetParentedForeignKeyRefs(Relation partition); -static void ATDetachCheckNoForeignKeyRefs(Relation partition); static char GetAttributeCompression(Oid atttypid, const char *compression); static char GetAttributeStorage(Oid atttypid, const char *storagemode); -static void ATExecMergePartitions(List **wqueue, AlteredTableInfo *tab, Relation rel, - PartitionCmd *cmd, AlterTableUtilityContext *context); -static void ATExecSplitPartition(List **wqueue, AlteredTableInfo *tab, - Relation rel, PartitionCmd *cmd, - AlterTableUtilityContext *context); - /* ---------------------------------------------------------------- * DefineRelation * Creates a new relation. @@ -4443,7 +4215,7 @@ CheckTableNotInUse(Relation rel, const char *stmt) * that, notably DROP TABLE. (We must allow DROP or we couldn't clean out * an orphaned temp schema.) Compare truncate_check_activity(). */ -static void +void CheckAlterTableIsSafe(Relation rel) { /* @@ -6583,7 +6355,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap) /* * ATGetQueueEntry: find or create an entry in the ALTER TABLE work queue */ -static AlteredTableInfo * +AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel) { Oid relid = RelationGetRelid(rel); @@ -6764,7 +6536,7 @@ alter_table_type_to_string(AlterTableType cmdtype) * - Ensure this user is the owner * - Ensure that it is not a system table */ -static void +void ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets) { int actual_target; @@ -6879,36 +6651,6 @@ ATSimpleRecursion(List **wqueue, Relation rel, } } -/* - * Obtain list of partitions of the given table, locking them all at the given - * lockmode and ensuring that they all pass CheckAlterTableIsSafe. - * - * This function is a no-op if the given relation is not a partitioned table; - * in particular, nothing is done if it's a legacy inheritance parent. - */ -static void -ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode) -{ - if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) - { - List *inh; - ListCell *cell; - - inh = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL); - /* first element is the parent rel; must ignore it */ - for_each_from(cell, inh, 1) - { - Relation childrel; - - /* find_all_inheritors already got lock */ - childrel = table_open(lfirst_oid(cell), NoLock); - CheckAlterTableIsSafe(childrel); - table_close(childrel, NoLock); - } - list_free(inh); - } -} - /* * ATTypedTableRecursion * @@ -8513,7 +8255,7 @@ ATExecSetIdentity(Relation rel, const char *colName, Node *def, * * Return the address of the affected column. */ -static ObjectAddress +ObjectAddress ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode, bool recurse, bool recursing) { @@ -10748,7 +10490,7 @@ validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums, * NULL/DEFAULT clause * with_period: true if this is a temporal FK */ -static ObjectAddress +ObjectAddress addFkConstraint(addFkConstraintSides fkside, char *constraintname, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, @@ -10926,7 +10668,7 @@ addFkConstraint(addFkConstraintSides fkside, * UPDATE respectively. * with_period: true if this is a temporal FK */ -static void +void addFkRecurseReferenced(Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, @@ -11064,7 +10806,7 @@ addFkRecurseReferenced(Constraint *fkconstraint, Relation rel, * UPDATE respectively. * with_period: true if this is a temporal FK */ -static void +void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, @@ -11230,795 +10972,6 @@ addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel, } } -/* - * CloneForeignKeyConstraints - * Clone foreign keys from a partitioned table to a newly acquired - * partition. - * - * partitionRel is a partition of parentRel, so we can be certain that it has - * the same columns with the same datatypes. The columns may be in different - * order, though. - * - * wqueue must be passed to set up phase 3 constraint checking, unless the - * referencing-side partition is known to be empty (such as in CREATE TABLE / - * PARTITION OF). - */ -static void -CloneForeignKeyConstraints(List **wqueue, Relation parentRel, - Relation partitionRel) -{ - /* This only works for declarative partitioning */ - Assert(parentRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE); - - /* - * First, clone constraints where the parent is on the referencing side. - */ - CloneFkReferencing(wqueue, parentRel, partitionRel); - - /* - * Clone constraints for which the parent is on the referenced side. - */ - CloneFkReferenced(parentRel, partitionRel); -} - -/* - * CloneFkReferenced - * Subroutine for CloneForeignKeyConstraints - * - * Find all the FKs that have the parent relation on the referenced side; - * clone those constraints to the given partition. This is to be called - * when the partition is being created or attached. - * - * This recurses to partitions, if the relation being attached is partitioned. - * Recursion is done by calling addFkRecurseReferenced. - */ -static void -CloneFkReferenced(Relation parentRel, Relation partitionRel) -{ - Relation pg_constraint; - AttrMap *attmap; - ListCell *cell; - SysScanDesc scan; - ScanKeyData key[2]; - HeapTuple tuple; - List *clone = NIL; - Relation trigrel; - - /* - * Search for any constraints where this partition's parent is in the - * referenced side. However, we must not clone any constraint whose - * parent constraint is also going to be cloned, to avoid duplicates. So - * do it in two steps: first construct the list of constraints to clone, - * then go over that list cloning those whose parents are not in the list. - * (We must not rely on the parent being seen first, since the catalog - * scan could return children first.) - */ - pg_constraint = table_open(ConstraintRelationId, RowShareLock); - ScanKeyInit(&key[0], - Anum_pg_constraint_confrelid, BTEqualStrategyNumber, - F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parentRel))); - ScanKeyInit(&key[1], - Anum_pg_constraint_contype, BTEqualStrategyNumber, - F_CHAREQ, CharGetDatum(CONSTRAINT_FOREIGN)); - /* This is a seqscan, as we don't have a usable index ... */ - scan = systable_beginscan(pg_constraint, InvalidOid, true, - NULL, 2, key); - while ((tuple = systable_getnext(scan)) != NULL) - { - Form_pg_constraint constrForm = (Form_pg_constraint) GETSTRUCT(tuple); - - clone = lappend_oid(clone, constrForm->oid); - } - systable_endscan(scan); - table_close(pg_constraint, RowShareLock); - - /* - * Triggers of the foreign keys will be manipulated a bunch of times in - * the loop below. To avoid repeatedly opening/closing the trigger - * catalog relation, we open it here and pass it to the subroutines called - * below. - */ - trigrel = table_open(TriggerRelationId, RowExclusiveLock); - - attmap = build_attrmap_by_name(RelationGetDescr(partitionRel), - RelationGetDescr(parentRel), - false); - foreach(cell, clone) - { - Oid constrOid = lfirst_oid(cell); - Form_pg_constraint constrForm; - Relation fkRel; - Oid indexOid; - Oid partIndexId; - int numfks; - AttrNumber conkey[INDEX_MAX_KEYS]; - AttrNumber mapped_confkey[INDEX_MAX_KEYS]; - AttrNumber confkey[INDEX_MAX_KEYS]; - Oid conpfeqop[INDEX_MAX_KEYS]; - Oid conppeqop[INDEX_MAX_KEYS]; - Oid conffeqop[INDEX_MAX_KEYS]; - int numfkdelsetcols; - AttrNumber confdelsetcols[INDEX_MAX_KEYS]; - Constraint *fkconstraint; - ObjectAddress address; - Oid deleteTriggerOid = InvalidOid, - updateTriggerOid = InvalidOid; - - tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid)); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for constraint %u", constrOid); - constrForm = (Form_pg_constraint) GETSTRUCT(tuple); - - /* - * As explained above: don't try to clone a constraint for which we're - * going to clone the parent. - */ - if (list_member_oid(clone, constrForm->conparentid)) - { - ReleaseSysCache(tuple); - continue; - } - - /* We need the same lock level that CreateTrigger will acquire */ - fkRel = table_open(constrForm->conrelid, ShareRowExclusiveLock); - - indexOid = constrForm->conindid; - DeconstructFkConstraintRow(tuple, - &numfks, - conkey, - confkey, - conpfeqop, - conppeqop, - conffeqop, - &numfkdelsetcols, - confdelsetcols); - - for (int i = 0; i < numfks; i++) - mapped_confkey[i] = attmap->attnums[confkey[i] - 1]; - - fkconstraint = makeNode(Constraint); - fkconstraint->contype = CONSTRAINT_FOREIGN; - fkconstraint->conname = NameStr(constrForm->conname); - fkconstraint->deferrable = constrForm->condeferrable; - fkconstraint->initdeferred = constrForm->condeferred; - fkconstraint->location = -1; - fkconstraint->pktable = NULL; - /* ->fk_attrs determined below */ - fkconstraint->pk_attrs = NIL; - fkconstraint->fk_matchtype = constrForm->confmatchtype; - fkconstraint->fk_upd_action = constrForm->confupdtype; - fkconstraint->fk_del_action = constrForm->confdeltype; - fkconstraint->fk_del_set_cols = NIL; - fkconstraint->old_conpfeqop = NIL; - fkconstraint->old_pktable_oid = InvalidOid; - fkconstraint->is_enforced = constrForm->conenforced; - fkconstraint->skip_validation = false; - fkconstraint->initially_valid = constrForm->convalidated; - - /* set up colnames that are used to generate the constraint name */ - for (int i = 0; i < numfks; i++) - { - Form_pg_attribute att; - - att = TupleDescAttr(RelationGetDescr(fkRel), - conkey[i] - 1); - fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs, - makeString(NameStr(att->attname))); - } - - /* - * Add the new foreign key constraint pointing to the new partition. - * Because this new partition appears in the referenced side of the - * constraint, we don't need to set up for Phase 3 check. - */ - partIndexId = index_get_partition(partitionRel, indexOid); - if (!OidIsValid(partIndexId)) - elog(ERROR, "index for %u not found in partition %s", - indexOid, RelationGetRelationName(partitionRel)); - - /* - * Get the "action" triggers belonging to the constraint to pass as - * parent OIDs for similar triggers that will be created on the - * partition in addFkRecurseReferenced(). - */ - if (constrForm->conenforced) - GetForeignKeyActionTriggers(trigrel, constrOid, - constrForm->confrelid, constrForm->conrelid, - &deleteTriggerOid, &updateTriggerOid); - - /* Add this constraint ... */ - address = addFkConstraint(addFkReferencedSide, - fkconstraint->conname, fkconstraint, fkRel, - partitionRel, partIndexId, constrOid, - numfks, mapped_confkey, - conkey, conpfeqop, conppeqop, conffeqop, - numfkdelsetcols, confdelsetcols, false, - constrForm->conperiod); - /* ... and recurse */ - addFkRecurseReferenced(fkconstraint, - fkRel, - partitionRel, - partIndexId, - address.objectId, - numfks, - mapped_confkey, - conkey, - conpfeqop, - conppeqop, - conffeqop, - numfkdelsetcols, - confdelsetcols, - true, - deleteTriggerOid, - updateTriggerOid, - constrForm->conperiod); - - table_close(fkRel, NoLock); - ReleaseSysCache(tuple); - } - - table_close(trigrel, RowExclusiveLock); -} - -/* - * CloneFkReferencing - * Subroutine for CloneForeignKeyConstraints - * - * For each FK constraint of the parent relation in the given list, find an - * equivalent constraint in its partition relation that can be reparented; - * if one cannot be found, create a new constraint in the partition as its - * child. - * - * If wqueue is given, it is used to set up phase-3 verification for each - * cloned constraint; omit it if such verification is not needed - * (example: the partition is being created anew). - */ -static void -CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel) -{ - AttrMap *attmap; - List *partFKs; - List *clone = NIL; - ListCell *cell; - Relation trigrel; - - /* obtain a list of constraints that we need to clone */ - foreach(cell, RelationGetFKeyList(parentRel)) - { - ForeignKeyCacheInfo *fk = lfirst(cell); - - /* - * Refuse to attach a table as partition that this partitioned table - * already has a foreign key to. This isn't useful schema, which is - * proven by the fact that there have been no user complaints that - * it's already impossible to achieve this in the opposite direction, - * i.e., creating a foreign key that references a partition. This - * restriction allows us to dodge some complexities around - * pg_constraint and pg_trigger row creations that would be needed - * during ATTACH/DETACH for this kind of relationship. - */ - if (fk->confrelid == RelationGetRelid(partRel)) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot attach table \"%s\" as a partition because it is referenced by foreign key \"%s\"", - RelationGetRelationName(partRel), - get_constraint_name(fk->conoid)))); - - clone = lappend_oid(clone, fk->conoid); - } - - /* - * Silently do nothing if there's nothing to do. In particular, this - * avoids throwing a spurious error for foreign tables. - */ - if (clone == NIL) - return; - - if (partRel->rd_rel->relkind == RELKIND_FOREIGN_TABLE) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("foreign key constraints are not supported on foreign tables"))); - - /* - * Triggers of the foreign keys will be manipulated a bunch of times in - * the loop below. To avoid repeatedly opening/closing the trigger - * catalog relation, we open it here and pass it to the subroutines called - * below. - */ - trigrel = table_open(TriggerRelationId, RowExclusiveLock); - - /* - * The constraint key may differ, if the columns in the partition are - * different. This map is used to convert them. - */ - attmap = build_attrmap_by_name(RelationGetDescr(partRel), - RelationGetDescr(parentRel), - false); - - partFKs = copyObject(RelationGetFKeyList(partRel)); - - foreach(cell, clone) - { - Oid parentConstrOid = lfirst_oid(cell); - Form_pg_constraint constrForm; - Relation pkrel; - HeapTuple tuple; - int numfks; - AttrNumber conkey[INDEX_MAX_KEYS]; - AttrNumber mapped_conkey[INDEX_MAX_KEYS]; - AttrNumber confkey[INDEX_MAX_KEYS]; - Oid conpfeqop[INDEX_MAX_KEYS]; - Oid conppeqop[INDEX_MAX_KEYS]; - Oid conffeqop[INDEX_MAX_KEYS]; - int numfkdelsetcols; - AttrNumber confdelsetcols[INDEX_MAX_KEYS]; - Constraint *fkconstraint; - bool attached; - Oid indexOid; - ObjectAddress address; - ListCell *lc; - Oid insertTriggerOid = InvalidOid, - updateTriggerOid = InvalidOid; - bool with_period; - - tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(parentConstrOid)); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for constraint %u", - parentConstrOid); - constrForm = (Form_pg_constraint) GETSTRUCT(tuple); - - /* Don't clone constraints whose parents are being cloned */ - if (list_member_oid(clone, constrForm->conparentid)) - { - ReleaseSysCache(tuple); - continue; - } - - /* - * Need to prevent concurrent deletions. If pkrel is a partitioned - * relation, that means to lock all partitions. - */ - pkrel = table_open(constrForm->confrelid, ShareRowExclusiveLock); - if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) - (void) find_all_inheritors(RelationGetRelid(pkrel), - ShareRowExclusiveLock, NULL); - - DeconstructFkConstraintRow(tuple, &numfks, conkey, confkey, - conpfeqop, conppeqop, conffeqop, - &numfkdelsetcols, confdelsetcols); - for (int i = 0; i < numfks; i++) - mapped_conkey[i] = attmap->attnums[conkey[i] - 1]; - - /* - * Get the "check" triggers belonging to the constraint, if it is - * ENFORCED, to pass as parent OIDs for similar triggers that will be - * created on the partition in addFkRecurseReferencing(). They are - * also passed to tryAttachPartitionForeignKey() below to simply - * assign as parents to the partition's existing "check" triggers, - * that is, if the corresponding constraints is deemed attachable to - * the parent constraint. - */ - if (constrForm->conenforced) - GetForeignKeyCheckTriggers(trigrel, constrForm->oid, - constrForm->confrelid, constrForm->conrelid, - &insertTriggerOid, &updateTriggerOid); - - /* - * Before creating a new constraint, see whether any existing FKs are - * fit for the purpose. If one is, attach the parent constraint to - * it, and don't clone anything. This way we avoid the expensive - * verification step and don't end up with a duplicate FK, and we - * don't need to recurse to partitions for this constraint. - */ - attached = false; - foreach(lc, partFKs) - { - ForeignKeyCacheInfo *fk = lfirst_node(ForeignKeyCacheInfo, lc); - - if (tryAttachPartitionForeignKey(wqueue, - fk, - partRel, - parentConstrOid, - numfks, - mapped_conkey, - confkey, - conpfeqop, - insertTriggerOid, - updateTriggerOid, - trigrel)) - { - attached = true; - table_close(pkrel, NoLock); - break; - } - } - if (attached) - { - ReleaseSysCache(tuple); - continue; - } - - /* No dice. Set up to create our own constraint */ - fkconstraint = makeNode(Constraint); - fkconstraint->contype = CONSTRAINT_FOREIGN; - /* ->conname determined below */ - fkconstraint->deferrable = constrForm->condeferrable; - fkconstraint->initdeferred = constrForm->condeferred; - fkconstraint->location = -1; - fkconstraint->pktable = NULL; - /* ->fk_attrs determined below */ - fkconstraint->pk_attrs = NIL; - fkconstraint->fk_matchtype = constrForm->confmatchtype; - fkconstraint->fk_upd_action = constrForm->confupdtype; - fkconstraint->fk_del_action = constrForm->confdeltype; - fkconstraint->fk_del_set_cols = NIL; - fkconstraint->old_conpfeqop = NIL; - fkconstraint->old_pktable_oid = InvalidOid; - fkconstraint->is_enforced = constrForm->conenforced; - fkconstraint->skip_validation = false; - fkconstraint->initially_valid = constrForm->convalidated; - for (int i = 0; i < numfks; i++) - { - Form_pg_attribute att; - - att = TupleDescAttr(RelationGetDescr(partRel), - mapped_conkey[i] - 1); - fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs, - makeString(NameStr(att->attname))); - } - - indexOid = constrForm->conindid; - with_period = constrForm->conperiod; - - /* Create the pg_constraint entry at this level */ - address = addFkConstraint(addFkReferencingSide, - NameStr(constrForm->conname), fkconstraint, - partRel, pkrel, indexOid, parentConstrOid, - numfks, confkey, - mapped_conkey, conpfeqop, - conppeqop, conffeqop, - numfkdelsetcols, confdelsetcols, - false, with_period); - - /* Done with the cloned constraint's tuple */ - ReleaseSysCache(tuple); - - /* Create the check triggers, and recurse to partitions, if any */ - addFkRecurseReferencing(wqueue, - fkconstraint, - partRel, - pkrel, - indexOid, - address.objectId, - numfks, - confkey, - mapped_conkey, - conpfeqop, - conppeqop, - conffeqop, - numfkdelsetcols, - confdelsetcols, - false, /* no old check exists */ - AccessExclusiveLock, - insertTriggerOid, - updateTriggerOid, - with_period); - table_close(pkrel, NoLock); - } - - table_close(trigrel, RowExclusiveLock); -} - -/* - * When the parent of a partition receives [the referencing side of] a foreign - * key, we must propagate that foreign key to the partition. However, the - * partition might already have an equivalent foreign key; this routine - * compares the given ForeignKeyCacheInfo (in the partition) to the FK defined - * by the other parameters. If they are equivalent, create the link between - * the two constraints and return true. - * - * If the given FK does not match the one defined by rest of the params, - * return false. - */ -static bool -tryAttachPartitionForeignKey(List **wqueue, - ForeignKeyCacheInfo *fk, - Relation partition, - Oid parentConstrOid, - int numfks, - AttrNumber *mapped_conkey, - AttrNumber *confkey, - Oid *conpfeqop, - Oid parentInsTrigger, - Oid parentUpdTrigger, - Relation trigrel) -{ - HeapTuple parentConstrTup; - Form_pg_constraint parentConstr; - HeapTuple partcontup; - Form_pg_constraint partConstr; - - parentConstrTup = SearchSysCache1(CONSTROID, - ObjectIdGetDatum(parentConstrOid)); - if (!HeapTupleIsValid(parentConstrTup)) - elog(ERROR, "cache lookup failed for constraint %u", parentConstrOid); - parentConstr = (Form_pg_constraint) GETSTRUCT(parentConstrTup); - - /* - * Do some quick & easy initial checks. If any of these fail, we cannot - * use this constraint. - */ - if (fk->confrelid != parentConstr->confrelid || fk->nkeys != numfks) - { - ReleaseSysCache(parentConstrTup); - return false; - } - for (int i = 0; i < numfks; i++) - { - if (fk->conkey[i] != mapped_conkey[i] || - fk->confkey[i] != confkey[i] || - fk->conpfeqop[i] != conpfeqop[i]) - { - ReleaseSysCache(parentConstrTup); - return false; - } - } - - /* Looks good so far; perform more extensive checks. */ - partcontup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(fk->conoid)); - if (!HeapTupleIsValid(partcontup)) - elog(ERROR, "cache lookup failed for constraint %u", fk->conoid); - partConstr = (Form_pg_constraint) GETSTRUCT(partcontup); - - /* - * An error should be raised if the constraint enforceability is - * different. Returning false without raising an error, as we do for other - * attributes, could lead to a duplicate constraint with the same - * enforceability as the parent. While this may be acceptable, it may not - * be ideal. Therefore, it's better to raise an error and allow the user - * to correct the enforceability before proceeding. - */ - if (partConstr->conenforced != parentConstr->conenforced) - ereport(ERROR, - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("constraint \"%s\" enforceability conflicts with constraint \"%s\" on relation \"%s\"", - NameStr(parentConstr->conname), - NameStr(partConstr->conname), - RelationGetRelationName(partition)))); - - if (OidIsValid(partConstr->conparentid) || - partConstr->condeferrable != parentConstr->condeferrable || - partConstr->condeferred != parentConstr->condeferred || - partConstr->confupdtype != parentConstr->confupdtype || - partConstr->confdeltype != parentConstr->confdeltype || - partConstr->confmatchtype != parentConstr->confmatchtype) - { - ReleaseSysCache(parentConstrTup); - ReleaseSysCache(partcontup); - return false; - } - - ReleaseSysCache(parentConstrTup); - ReleaseSysCache(partcontup); - - /* Looks good! Attach this constraint. */ - AttachPartitionForeignKey(wqueue, partition, fk->conoid, - parentConstrOid, parentInsTrigger, - parentUpdTrigger, trigrel); - - return true; -} - -/* - * AttachPartitionForeignKey - * - * The subroutine for tryAttachPartitionForeignKey performs the final tasks of - * attaching the constraint, removing redundant triggers and entries from - * pg_constraint, and setting the constraint's parent. - */ -static void -AttachPartitionForeignKey(List **wqueue, - Relation partition, - Oid partConstrOid, - Oid parentConstrOid, - Oid parentInsTrigger, - Oid parentUpdTrigger, - Relation trigrel) -{ - HeapTuple parentConstrTup; - Form_pg_constraint parentConstr; - HeapTuple partcontup; - Form_pg_constraint partConstr; - bool queueValidation; - Oid partConstrFrelid; - Oid partConstrRelid; - bool parentConstrIsEnforced; - - /* Fetch the parent constraint tuple */ - parentConstrTup = SearchSysCache1(CONSTROID, - ObjectIdGetDatum(parentConstrOid)); - if (!HeapTupleIsValid(parentConstrTup)) - elog(ERROR, "cache lookup failed for constraint %u", parentConstrOid); - parentConstr = (Form_pg_constraint) GETSTRUCT(parentConstrTup); - parentConstrIsEnforced = parentConstr->conenforced; - - /* Fetch the child constraint tuple */ - partcontup = SearchSysCache1(CONSTROID, - ObjectIdGetDatum(partConstrOid)); - if (!HeapTupleIsValid(partcontup)) - elog(ERROR, "cache lookup failed for constraint %u", partConstrOid); - partConstr = (Form_pg_constraint) GETSTRUCT(partcontup); - partConstrFrelid = partConstr->confrelid; - partConstrRelid = partConstr->conrelid; - - /* - * If the referenced table is partitioned, then the partition we're - * attaching now has extra pg_constraint rows and action triggers that are - * no longer needed. Remove those. - */ - if (get_rel_relkind(partConstrFrelid) == RELKIND_PARTITIONED_TABLE) - { - Relation pg_constraint = table_open(ConstraintRelationId, RowShareLock); - - RemoveInheritedConstraint(pg_constraint, trigrel, partConstrOid, - partConstrRelid); - - table_close(pg_constraint, RowShareLock); - } - - /* - * Will we need to validate this constraint? A valid parent constraint - * implies that all child constraints have been validated, so if this one - * isn't, we must trigger phase 3 validation. - */ - queueValidation = parentConstr->convalidated && !partConstr->convalidated; - - ReleaseSysCache(partcontup); - ReleaseSysCache(parentConstrTup); - - /* - * The action triggers in the new partition become redundant -- the parent - * table already has equivalent ones, and those will be able to reach the - * partition. Remove the ones in the partition. We identify them because - * they have our constraint OID, as well as being on the referenced rel. - */ - DropForeignKeyConstraintTriggers(trigrel, partConstrOid, partConstrFrelid, - partConstrRelid); - - ConstraintSetParentConstraint(partConstrOid, parentConstrOid, - RelationGetRelid(partition)); - - /* - * Like the constraint, attach partition's "check" triggers to the - * corresponding parent triggers if the constraint is ENFORCED. NOT - * ENFORCED constraints do not have these triggers. - */ - if (parentConstrIsEnforced) - { - Oid insertTriggerOid, - updateTriggerOid; - - GetForeignKeyCheckTriggers(trigrel, - partConstrOid, partConstrFrelid, partConstrRelid, - &insertTriggerOid, &updateTriggerOid); - Assert(OidIsValid(insertTriggerOid) && OidIsValid(parentInsTrigger)); - TriggerSetParentTrigger(trigrel, insertTriggerOid, parentInsTrigger, - RelationGetRelid(partition)); - Assert(OidIsValid(updateTriggerOid) && OidIsValid(parentUpdTrigger)); - TriggerSetParentTrigger(trigrel, updateTriggerOid, parentUpdTrigger, - RelationGetRelid(partition)); - } - - /* - * We updated this pg_constraint row above to set its parent; validating - * it will cause its convalidated flag to change, so we need CCI here. In - * addition, we need it unconditionally for the rare case where the parent - * table has *two* identical constraints; when reaching this function for - * the second one, we must have made our changes visible, otherwise we - * would try to attach both to this one. - */ - CommandCounterIncrement(); - - /* If validation is needed, put it in the queue now. */ - if (queueValidation) - { - Relation conrel; - Oid confrelid; - - conrel = table_open(ConstraintRelationId, RowExclusiveLock); - - partcontup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(partConstrOid)); - if (!HeapTupleIsValid(partcontup)) - elog(ERROR, "cache lookup failed for constraint %u", partConstrOid); - - confrelid = ((Form_pg_constraint) GETSTRUCT(partcontup))->confrelid; - - /* Use the same lock as for AT_ValidateConstraint */ - QueueFKConstraintValidation(wqueue, conrel, partition, confrelid, - partcontup, ShareUpdateExclusiveLock); - ReleaseSysCache(partcontup); - table_close(conrel, RowExclusiveLock); - } -} - -/* - * RemoveInheritedConstraint - * - * Removes the constraint and its associated trigger from the specified - * relation, which inherited the given constraint. - */ -static void -RemoveInheritedConstraint(Relation conrel, Relation trigrel, Oid conoid, - Oid conrelid) -{ - ObjectAddresses *objs; - HeapTuple consttup; - ScanKeyData key; - SysScanDesc scan; - HeapTuple trigtup; - - ScanKeyInit(&key, - Anum_pg_constraint_conrelid, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(conrelid)); - - scan = systable_beginscan(conrel, - ConstraintRelidTypidNameIndexId, - true, NULL, 1, &key); - objs = new_object_addresses(); - while ((consttup = systable_getnext(scan)) != NULL) - { - Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(consttup); - - if (conform->conparentid != conoid) - continue; - else - { - ObjectAddress addr; - SysScanDesc scan2; - ScanKeyData key2; - int n PG_USED_FOR_ASSERTS_ONLY; - - ObjectAddressSet(addr, ConstraintRelationId, conform->oid); - add_exact_object_address(&addr, objs); - - /* - * First we must delete the dependency record that binds the - * constraint records together. - */ - n = deleteDependencyRecordsForSpecific(ConstraintRelationId, - conform->oid, - DEPENDENCY_INTERNAL, - ConstraintRelationId, - conoid); - Assert(n == 1); /* actually only one is expected */ - - /* - * Now search for the triggers for this constraint and set them up - * for deletion too - */ - ScanKeyInit(&key2, - Anum_pg_trigger_tgconstraint, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(conform->oid)); - scan2 = systable_beginscan(trigrel, TriggerConstraintIndexId, - true, NULL, 1, &key2); - while ((trigtup = systable_getnext(scan2)) != NULL) - { - ObjectAddressSet(addr, TriggerRelationId, - ((Form_pg_trigger) GETSTRUCT(trigtup))->oid); - add_exact_object_address(&addr, objs); - } - systable_endscan(scan2); - } - } - /* make the dependency deletions visible */ - CommandCounterIncrement(); - performMultipleDeletions(objs, DROP_RESTRICT, - PERFORM_DELETION_INTERNAL); - systable_endscan(scan); -} - /* * DropForeignKeyConstraintTriggers * @@ -12029,7 +10982,7 @@ RemoveInheritedConstraint(Relation conrel, Relation trigrel, Oid conoid, * trigger check will be skipped, and the trigger will be considered for * removal. */ -static void +void DropForeignKeyConstraintTriggers(Relation trigrel, Oid conoid, Oid confrelid, Oid conrelid) { @@ -12092,128 +11045,6 @@ DropForeignKeyConstraintTriggers(Relation trigrel, Oid conoid, Oid confrelid, systable_endscan(scan); } -/* - * GetForeignKeyActionTriggers - * Returns delete and update "action" triggers of the given relation - * belonging to the given constraint - */ -static void -GetForeignKeyActionTriggers(Relation trigrel, - Oid conoid, Oid confrelid, Oid conrelid, - Oid *deleteTriggerOid, - Oid *updateTriggerOid) -{ - ScanKeyData key; - SysScanDesc scan; - HeapTuple trigtup; - - *deleteTriggerOid = *updateTriggerOid = InvalidOid; - ScanKeyInit(&key, - Anum_pg_trigger_tgconstraint, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(conoid)); - - scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true, - NULL, 1, &key); - while ((trigtup = systable_getnext(scan)) != NULL) - { - Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup); - - if (trgform->tgconstrrelid != conrelid) - continue; - if (trgform->tgrelid != confrelid) - continue; - /* Only ever look at "action" triggers on the PK side. */ - if (RI_FKey_trigger_type(trgform->tgfoid) != RI_TRIGGER_PK) - continue; - if (TRIGGER_FOR_DELETE(trgform->tgtype)) - { - Assert(*deleteTriggerOid == InvalidOid); - *deleteTriggerOid = trgform->oid; - } - else if (TRIGGER_FOR_UPDATE(trgform->tgtype)) - { - Assert(*updateTriggerOid == InvalidOid); - *updateTriggerOid = trgform->oid; - } -#ifndef USE_ASSERT_CHECKING - /* In an assert-enabled build, continue looking to find duplicates */ - if (OidIsValid(*deleteTriggerOid) && OidIsValid(*updateTriggerOid)) - break; -#endif - } - - if (!OidIsValid(*deleteTriggerOid)) - elog(ERROR, "could not find ON DELETE action trigger of foreign key constraint %u", - conoid); - if (!OidIsValid(*updateTriggerOid)) - elog(ERROR, "could not find ON UPDATE action trigger of foreign key constraint %u", - conoid); - - systable_endscan(scan); -} - -/* - * GetForeignKeyCheckTriggers - * Returns insert and update "check" triggers of the given relation - * belonging to the given constraint - */ -static void -GetForeignKeyCheckTriggers(Relation trigrel, - Oid conoid, Oid confrelid, Oid conrelid, - Oid *insertTriggerOid, - Oid *updateTriggerOid) -{ - ScanKeyData key; - SysScanDesc scan; - HeapTuple trigtup; - - *insertTriggerOid = *updateTriggerOid = InvalidOid; - ScanKeyInit(&key, - Anum_pg_trigger_tgconstraint, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(conoid)); - - scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true, - NULL, 1, &key); - while ((trigtup = systable_getnext(scan)) != NULL) - { - Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup); - - if (trgform->tgconstrrelid != confrelid) - continue; - if (trgform->tgrelid != conrelid) - continue; - /* Only ever look at "check" triggers on the FK side. */ - if (RI_FKey_trigger_type(trgform->tgfoid) != RI_TRIGGER_FK) - continue; - if (TRIGGER_FOR_INSERT(trgform->tgtype)) - { - Assert(*insertTriggerOid == InvalidOid); - *insertTriggerOid = trgform->oid; - } - else if (TRIGGER_FOR_UPDATE(trgform->tgtype)) - { - Assert(*updateTriggerOid == InvalidOid); - *updateTriggerOid = trgform->oid; - } -#ifndef USE_ASSERT_CHECKING - /* In an assert-enabled build, continue looking to find duplicates. */ - if (OidIsValid(*insertTriggerOid) && OidIsValid(*updateTriggerOid)) - break; -#endif - } - - if (!OidIsValid(*insertTriggerOid)) - elog(ERROR, "could not find ON INSERT check triggers of foreign key constraint %u", - conoid); - if (!OidIsValid(*updateTriggerOid)) - elog(ERROR, "could not find ON UPDATE check triggers of foreign key constraint %u", - conoid); - - systable_endscan(scan); -} - /* * ALTER TABLE ALTER CONSTRAINT * @@ -13024,7 +11855,7 @@ ATExecValidateConstraint(List **wqueue, Relation rel, char *constrName, * Phase 3 and update the convalidated field in the pg_constraint catalog * for the specified relation and all its children. */ -static void +void QueueFKConstraintValidation(List **wqueue, Relation conrel, Relation fkrel, Oid pkrelid, HeapTuple contuple, LOCKMODE lockmode) { @@ -17398,7 +16229,7 @@ ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode) * * Common to ATExecAddInherit() and ATExecAttachPartition(). */ -static void +void CreateInheritance(Relation child_rel, Relation parent_rel, bool ispartition) { Relation catalogRelation; @@ -17884,78 +16715,6 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode) return address; } -/* - * MarkInheritDetached - * - * Set inhdetachpending for a partition, for ATExecDetachPartition - * in concurrent mode. While at it, verify that no other partition is - * already pending detach. - */ -static void -MarkInheritDetached(Relation child_rel, Relation parent_rel) -{ - Relation catalogRelation; - SysScanDesc scan; - ScanKeyData key; - HeapTuple inheritsTuple; - bool found = false; - - Assert(parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE); - - /* - * Find pg_inherits entries by inhparent. (We need to scan them all in - * order to verify that no other partition is pending detach.) - */ - catalogRelation = table_open(InheritsRelationId, RowExclusiveLock); - ScanKeyInit(&key, - Anum_pg_inherits_inhparent, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(RelationGetRelid(parent_rel))); - scan = systable_beginscan(catalogRelation, InheritsParentIndexId, - true, NULL, 1, &key); - - while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan))) - { - Form_pg_inherits inhForm; - - inhForm = (Form_pg_inherits) GETSTRUCT(inheritsTuple); - if (inhForm->inhdetachpending) - ereport(ERROR, - errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("partition \"%s\" already pending detach in partitioned table \"%s.%s\"", - get_rel_name(inhForm->inhrelid), - get_namespace_name(parent_rel->rd_rel->relnamespace), - RelationGetRelationName(parent_rel)), - errhint("Use ALTER TABLE ... DETACH PARTITION ... FINALIZE to complete the pending detach operation.")); - - if (inhForm->inhrelid == RelationGetRelid(child_rel)) - { - HeapTuple newtup; - - newtup = heap_copytuple(inheritsTuple); - ((Form_pg_inherits) GETSTRUCT(newtup))->inhdetachpending = true; - - CatalogTupleUpdate(catalogRelation, - &inheritsTuple->t_self, - newtup); - found = true; - heap_freetuple(newtup); - /* keep looking, to ensure we catch others pending detach */ - } - } - - /* Done */ - systable_endscan(scan); - table_close(catalogRelation, RowExclusiveLock); - - if (!found) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_TABLE), - errmsg("relation \"%s\" is not a partition of relation \"%s\"", - RelationGetRelationName(child_rel), - RelationGetRelationName(parent_rel)))); -} - /* * RemoveInheritance * @@ -17974,7 +16733,7 @@ MarkInheritDetached(Relation child_rel, Relation parent_rel) * * Common to ATExecDropInherit() and ATExecDetachPartition(). */ -static void +void RemoveInheritance(Relation child_rel, Relation parent_rel, bool expect_detached) { Relation catalogRelation; @@ -19746,2290 +18505,6 @@ RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, ReleaseSysCache(tuple); } -/* - * Transform any expressions present in the partition key - * - * Returns a transformed PartitionSpec. - */ -static PartitionSpec * -transformPartitionSpec(Relation rel, PartitionSpec *partspec) -{ - PartitionSpec *newspec; - ParseState *pstate; - ParseNamespaceItem *nsitem; - ListCell *l; - - newspec = makeNode(PartitionSpec); - - newspec->strategy = partspec->strategy; - newspec->partParams = NIL; - newspec->location = partspec->location; - - /* Check valid number of columns for strategy */ - if (partspec->strategy == PARTITION_STRATEGY_LIST && - list_length(partspec->partParams) != 1) - ereport(ERROR, - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("cannot use \"list\" partition strategy with more than one column"))); - - /* - * Create a dummy ParseState and insert the target relation as its sole - * rangetable entry. We need a ParseState for transformExpr. - */ - pstate = make_parsestate(NULL); - nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock, - NULL, false, true); - addNSItemToQuery(pstate, nsitem, true, true, true); - - /* take care of any partition expressions */ - foreach(l, partspec->partParams) - { - PartitionElem *pelem = lfirst_node(PartitionElem, l); - - if (pelem->expr) - { - /* Copy, to avoid scribbling on the input */ - pelem = copyObject(pelem); - - /* Now do parse transformation of the expression */ - pelem->expr = transformExpr(pstate, pelem->expr, - EXPR_KIND_PARTITION_EXPRESSION); - - /* we have to fix its collations too */ - assign_expr_collations(pstate, pelem->expr); - } - - newspec->partParams = lappend(newspec->partParams, pelem); - } - - return newspec; -} - -/* - * Compute per-partition-column information from a list of PartitionElems. - * Expressions in the PartitionElems must be parse-analyzed already. - */ -static void -ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs, - List **partexprs, Oid *partopclass, Oid *partcollation, - PartitionStrategy strategy) -{ - int attn; - ListCell *lc; - Oid am_oid; - - attn = 0; - foreach(lc, partParams) - { - PartitionElem *pelem = lfirst_node(PartitionElem, lc); - Oid atttype; - Oid attcollation; - - if (pelem->name != NULL) - { - /* Simple attribute reference */ - HeapTuple atttuple; - Form_pg_attribute attform; - - atttuple = SearchSysCacheAttName(RelationGetRelid(rel), - pelem->name); - if (!HeapTupleIsValid(atttuple)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_COLUMN), - errmsg("column \"%s\" named in partition key does not exist", - pelem->name), - parser_errposition(pstate, pelem->location))); - attform = (Form_pg_attribute) GETSTRUCT(atttuple); - - if (attform->attnum <= 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("cannot use system column \"%s\" in partition key", - pelem->name), - parser_errposition(pstate, pelem->location))); - - /* - * Stored generated columns cannot work: They are computed after - * BEFORE triggers, but partition routing is done before all - * triggers. Maybe virtual generated columns could be made to - * work, but then they would need to be handled as an expression - * below. - */ - if (attform->attgenerated) - ereport(ERROR, - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("cannot use generated column in partition key"), - errdetail("Column \"%s\" is a generated column.", - pelem->name), - parser_errposition(pstate, pelem->location))); - - partattrs[attn] = attform->attnum; - atttype = attform->atttypid; - attcollation = attform->attcollation; - ReleaseSysCache(atttuple); - } - else - { - /* Expression */ - Node *expr = pelem->expr; - char partattname[16]; - Bitmapset *expr_attrs = NULL; - int i; - - Assert(expr != NULL); - atttype = exprType(expr); - attcollation = exprCollation(expr); - - /* - * The expression must be of a storable type (e.g., not RECORD). - * The test is the same as for whether a table column is of a safe - * type (which is why we needn't check for the non-expression - * case). - */ - snprintf(partattname, sizeof(partattname), "%d", attn + 1); - CheckAttributeType(partattname, - atttype, attcollation, - NIL, CHKATYPE_IS_PARTKEY); - - /* - * Strip any top-level COLLATE clause. This ensures that we treat - * "x COLLATE y" and "(x COLLATE y)" alike. - */ - while (IsA(expr, CollateExpr)) - expr = (Node *) ((CollateExpr *) expr)->arg; - - /* - * Examine all the columns in the partition key expression. When - * the whole-row reference is present, examine all the columns of - * the partitioned table. - */ - pull_varattnos(expr, 1, &expr_attrs); - if (bms_is_member(0 - FirstLowInvalidHeapAttributeNumber, expr_attrs)) - { - expr_attrs = bms_add_range(expr_attrs, - 1 - FirstLowInvalidHeapAttributeNumber, - RelationGetNumberOfAttributes(rel) - FirstLowInvalidHeapAttributeNumber); - expr_attrs = bms_del_member(expr_attrs, 0 - FirstLowInvalidHeapAttributeNumber); - } - - i = -1; - while ((i = bms_next_member(expr_attrs, i)) >= 0) - { - AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber; - - Assert(attno != 0); - - /* - * Cannot allow system column references, since that would - * make partition routing impossible: their values won't be - * known yet when we need to do that. - */ - if (attno < 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("partition key expressions cannot contain system column references"))); - - /* - * Stored generated columns cannot work: They are computed - * after BEFORE triggers, but partition routing is done before - * all triggers. Virtual generated columns could probably - * work, but it would require more work elsewhere (for example - * SET EXPRESSION would need to check whether the column is - * used in partition keys). Seems safer to prohibit for now. - */ - if (TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated) - ereport(ERROR, - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("cannot use generated column in partition key"), - errdetail("Column \"%s\" is a generated column.", - get_attname(RelationGetRelid(rel), attno, false)), - parser_errposition(pstate, pelem->location))); - } - - if (IsA(expr, Var) && - ((Var *) expr)->varattno > 0) - { - - /* - * User wrote "(column)" or "(column COLLATE something)". - * Treat it like simple attribute anyway. - */ - partattrs[attn] = ((Var *) expr)->varattno; - } - else - { - partattrs[attn] = 0; /* marks the column as expression */ - *partexprs = lappend(*partexprs, expr); - - /* - * transformPartitionSpec() should have already rejected - * subqueries, aggregates, window functions, and SRFs, based - * on the EXPR_KIND_ for partition expressions. - */ - - /* - * Preprocess the expression before checking for mutability. - * This is essential for the reasons described in - * contain_mutable_functions_after_planning. However, we call - * expression_planner for ourselves rather than using that - * function, because if constant-folding reduces the - * expression to a constant, we'd like to know that so we can - * complain below. - * - * Like contain_mutable_functions_after_planning, assume that - * expression_planner won't scribble on its input, so this - * won't affect the partexprs entry we saved above. - */ - expr = (Node *) expression_planner((Expr *) expr); - - /* - * Partition expressions cannot contain mutable functions, - * because a given row must always map to the same partition - * as long as there is no change in the partition boundary - * structure. - */ - if (contain_mutable_functions(expr)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("functions in partition key expression must be marked IMMUTABLE"))); - - /* - * While it is not exactly *wrong* for a partition expression - * to be a constant, it seems better to reject such keys. - */ - if (IsA(expr, Const)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("cannot use constant expression as partition key"))); - } - } - - /* - * Apply collation override if any - */ - if (pelem->collation) - attcollation = get_collation_oid(pelem->collation, false); - - /* - * Check we have a collation iff it's a collatable type. The only - * expected failures here are (1) COLLATE applied to a noncollatable - * type, or (2) partition expression had an unresolved collation. But - * we might as well code this to be a complete consistency check. - */ - if (type_is_collatable(atttype)) - { - if (!OidIsValid(attcollation)) - ereport(ERROR, - (errcode(ERRCODE_INDETERMINATE_COLLATION), - errmsg("could not determine which collation to use for partition expression"), - errhint("Use the COLLATE clause to set the collation explicitly."))); - } - else - { - if (OidIsValid(attcollation)) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("collations are not supported by type %s", - format_type_be(atttype)))); - } - - partcollation[attn] = attcollation; - - /* - * Identify the appropriate operator class. For list and range - * partitioning, we use a btree operator class; hash partitioning uses - * a hash operator class. - */ - if (strategy == PARTITION_STRATEGY_HASH) - am_oid = HASH_AM_OID; - else - am_oid = BTREE_AM_OID; - - if (!pelem->opclass) - { - partopclass[attn] = GetDefaultOpClass(atttype, am_oid); - - if (!OidIsValid(partopclass[attn])) - { - if (strategy == PARTITION_STRATEGY_HASH) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("data type %s has no default operator class for access method \"%s\"", - format_type_be(atttype), "hash"), - errhint("You must specify a hash operator class or define a default hash operator class for the data type."))); - else - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("data type %s has no default operator class for access method \"%s\"", - format_type_be(atttype), "btree"), - errhint("You must specify a btree operator class or define a default btree operator class for the data type."))); - } - } - else - partopclass[attn] = ResolveOpClass(pelem->opclass, - atttype, - am_oid == HASH_AM_OID ? "hash" : "btree", - am_oid); - - attn++; - } -} - -/* - * PartConstraintImpliedByRelConstraint - * Do scanrel's existing constraints imply the partition constraint? - * - * "Existing constraints" include its check constraints and column-level - * not-null constraints. partConstraint describes the partition constraint, - * in implicit-AND form. - */ -bool -PartConstraintImpliedByRelConstraint(Relation scanrel, - List *partConstraint) -{ - List *existConstraint = NIL; - TupleConstr *constr = RelationGetDescr(scanrel)->constr; - int i; - - if (constr && constr->has_not_null) - { - int natts = scanrel->rd_att->natts; - - for (i = 1; i <= natts; i++) - { - CompactAttribute *att = TupleDescCompactAttr(scanrel->rd_att, i - 1); - - /* invalid not-null constraint must be ignored here */ - if (att->attnullability == ATTNULLABLE_VALID && !att->attisdropped) - { - Form_pg_attribute wholeatt = TupleDescAttr(scanrel->rd_att, i - 1); - NullTest *ntest = makeNode(NullTest); - - ntest->arg = (Expr *) makeVar(1, - i, - wholeatt->atttypid, - wholeatt->atttypmod, - wholeatt->attcollation, - 0); - ntest->nulltesttype = IS_NOT_NULL; - - /* - * argisrow=false is correct even for a composite column, - * because attnotnull does not represent a SQL-spec IS NOT - * NULL test in such a case, just IS DISTINCT FROM NULL. - */ - ntest->argisrow = false; - ntest->location = -1; - existConstraint = lappend(existConstraint, ntest); - } - } - } - - return ConstraintImpliedByRelConstraint(scanrel, partConstraint, existConstraint); -} - -/* - * ConstraintImpliedByRelConstraint - * Do scanrel's existing constraints imply the given constraint? - * - * testConstraint is the constraint to validate. provenConstraint is a - * caller-provided list of conditions which this function may assume - * to be true. Both provenConstraint and testConstraint must be in - * implicit-AND form, must only contain immutable clauses, and must - * contain only Vars with varno = 1. - */ -bool -ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint) -{ - List *existConstraint = list_copy(provenConstraint); - TupleConstr *constr = RelationGetDescr(scanrel)->constr; - int num_check, - i; - - num_check = (constr != NULL) ? constr->num_check : 0; - for (i = 0; i < num_check; i++) - { - Node *cexpr; - - /* - * If this constraint hasn't been fully validated yet, we must ignore - * it here. - */ - if (!constr->check[i].ccvalid) - continue; - - /* - * NOT ENFORCED constraints are always marked as invalid, which should - * have been ignored. - */ - Assert(constr->check[i].ccenforced); - - cexpr = stringToNode(constr->check[i].ccbin); - - /* - * Run each expression through const-simplification and - * canonicalization. It is necessary, because we will be comparing it - * to similarly-processed partition constraint expressions, and may - * fail to detect valid matches without this. - */ - cexpr = eval_const_expressions(NULL, cexpr); - cexpr = (Node *) canonicalize_qual((Expr *) cexpr, true); - - existConstraint = list_concat(existConstraint, - make_ands_implicit((Expr *) cexpr)); - } - - /* - * Try to make the proof. Since we are comparing CHECK constraints, we - * need to use weak implication, i.e., we assume existConstraint is - * not-false and try to prove the same for testConstraint. - * - * Note that predicate_implied_by assumes its first argument is known - * immutable. That should always be true for both NOT NULL and partition - * constraints, so we don't test it here. - */ - return predicate_implied_by(testConstraint, existConstraint, true); -} - -/* - * QueuePartitionConstraintValidation - * - * Add an entry to wqueue to have the given partition constraint validated by - * Phase 3, for the given relation, and all its children. - * - * We first verify whether the given constraint is implied by pre-existing - * relation constraints; if it is, there's no need to scan the table to - * validate, so don't queue in that case. - */ -static void -QueuePartitionConstraintValidation(List **wqueue, Relation scanrel, - List *partConstraint, - bool validate_default) -{ - /* - * Based on the table's existing constraints, determine whether or not we - * may skip scanning the table. - */ - if (PartConstraintImpliedByRelConstraint(scanrel, partConstraint)) - { - if (!validate_default) - ereport(DEBUG1, - (errmsg_internal("partition constraint for table \"%s\" is implied by existing constraints", - RelationGetRelationName(scanrel)))); - else - ereport(DEBUG1, - (errmsg_internal("updated partition constraint for default partition \"%s\" is implied by existing constraints", - RelationGetRelationName(scanrel)))); - return; - } - - /* - * Constraints proved insufficient. For plain relations, queue a - * validation item now; for partitioned tables, recurse to process each - * partition. - */ - if (scanrel->rd_rel->relkind == RELKIND_RELATION) - { - AlteredTableInfo *tab; - - /* Grab a work queue entry. */ - tab = ATGetQueueEntry(wqueue, scanrel); - Assert(tab->partition_constraint == NULL); - tab->partition_constraint = (Expr *) linitial(partConstraint); - tab->validate_default = validate_default; - } - else if (scanrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) - { - PartitionDesc partdesc = RelationGetPartitionDesc(scanrel, true); - int i; - - for (i = 0; i < partdesc->nparts; i++) - { - Relation part_rel; - List *thisPartConstraint; - - /* - * This is the minimum lock we need to prevent deadlocks. - */ - part_rel = table_open(partdesc->oids[i], AccessExclusiveLock); - - /* - * Adjust the constraint for scanrel so that it matches this - * partition's attribute numbers. - */ - thisPartConstraint = - map_partition_varattnos(partConstraint, 1, - part_rel, scanrel); - - QueuePartitionConstraintValidation(wqueue, part_rel, - thisPartConstraint, - validate_default); - table_close(part_rel, NoLock); /* keep lock till commit */ - } - } -} - -/* - * attachPartitionTable: attach a new partition to the partitioned table - * - * wqueue: the ALTER TABLE work queue; can be NULL when not running as part - * of an ALTER TABLE sequence. - * rel: partitioned relation; - * attachrel: relation of attached partition; - * bound: bounds of attached relation. - */ -static void -attachPartitionTable(List **wqueue, Relation rel, Relation attachrel, PartitionBoundSpec *bound) -{ - /* - * Create an inheritance; the relevant checks are performed inside the - * function. - */ - CreateInheritance(attachrel, rel, true); - - /* Update the pg_class entry. */ - StorePartitionBound(attachrel, rel, bound); - - /* Ensure there exists a correct set of indexes in the partition. */ - AttachPartitionEnsureIndexes(wqueue, rel, attachrel); - - /* and triggers */ - CloneRowTriggersToPartition(rel, attachrel); - - /* - * Clone foreign key constraints. Callee is responsible for setting up - * for phase 3 constraint verification. - */ - CloneForeignKeyConstraints(wqueue, rel, attachrel); -} - -/* - * ALTER TABLE <name> ATTACH PARTITION <partition-name> FOR VALUES - * - * Return the address of the newly attached partition. - */ -static ObjectAddress -ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd, - AlterTableUtilityContext *context) -{ - Relation attachrel, - catalog; - List *attachrel_children; - List *partConstraint; - SysScanDesc scan; - ScanKeyData skey; - AttrNumber attno; - int natts; - TupleDesc tupleDesc; - ObjectAddress address; - const char *trigger_name; - Oid defaultPartOid; - List *partBoundConstraint; - ParseState *pstate = make_parsestate(NULL); - - pstate->p_sourcetext = context->queryString; - - /* - * We must lock the default partition if one exists, because attaching a - * new partition will change its partition constraint. - */ - defaultPartOid = - get_default_oid_from_partdesc(RelationGetPartitionDesc(rel, true)); - if (OidIsValid(defaultPartOid)) - LockRelationOid(defaultPartOid, AccessExclusiveLock); - - attachrel = table_openrv(cmd->name, AccessExclusiveLock); - - /* - * XXX I think it'd be a good idea to grab locks on all tables referenced - * by FKs at this point also. - */ - - /* - * Must be owner of both parent and source table -- parent was checked by - * ATSimplePermissions call in ATPrepCmd - */ - ATSimplePermissions(AT_AttachPartition, attachrel, - ATT_TABLE | ATT_PARTITIONED_TABLE | ATT_FOREIGN_TABLE); - - /* A partition can only have one parent */ - if (attachrel->rd_rel->relispartition) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("\"%s\" is already a partition", - RelationGetRelationName(attachrel)))); - - if (OidIsValid(attachrel->rd_rel->reloftype)) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("cannot attach a typed table as partition"))); - - /* - * Table being attached should not already be part of inheritance; either - * as a child table... - */ - catalog = table_open(InheritsRelationId, AccessShareLock); - ScanKeyInit(&skey, - Anum_pg_inherits_inhrelid, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(RelationGetRelid(attachrel))); - scan = systable_beginscan(catalog, InheritsRelidSeqnoIndexId, true, - NULL, 1, &skey); - if (HeapTupleIsValid(systable_getnext(scan))) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("cannot attach inheritance child as partition"))); - systable_endscan(scan); - - /* ...or as a parent table (except the case when it is partitioned) */ - ScanKeyInit(&skey, - Anum_pg_inherits_inhparent, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(RelationGetRelid(attachrel))); - scan = systable_beginscan(catalog, InheritsParentIndexId, true, NULL, - 1, &skey); - if (HeapTupleIsValid(systable_getnext(scan)) && - attachrel->rd_rel->relkind == RELKIND_RELATION) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("cannot attach inheritance parent as partition"))); - systable_endscan(scan); - table_close(catalog, AccessShareLock); - - /* - * Prevent circularity by seeing if rel is a partition of attachrel. (In - * particular, this disallows making a rel a partition of itself.) - * - * We do that by checking if rel is a member of the list of attachrel's - * partitions provided the latter is partitioned at all. We want to avoid - * having to construct this list again, so we request the strongest lock - * on all partitions. We need the strongest lock, because we may decide - * to scan them if we find out that the table being attached (or its leaf - * partitions) may contain rows that violate the partition constraint. If - * the table has a constraint that would prevent such rows, which by - * definition is present in all the partitions, we need not scan the - * table, nor its partitions. But we cannot risk a deadlock by taking a - * weaker lock now and the stronger one only when needed. - */ - attachrel_children = find_all_inheritors(RelationGetRelid(attachrel), - AccessExclusiveLock, NULL); - if (list_member_oid(attachrel_children, RelationGetRelid(rel))) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_TABLE), - errmsg("circular inheritance not allowed"), - errdetail("\"%s\" is already a child of \"%s\".", - RelationGetRelationName(rel), - RelationGetRelationName(attachrel)))); - - /* If the parent is permanent, so must be all of its partitions. */ - if (rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP && - attachrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("cannot attach a temporary relation as partition of permanent relation \"%s\"", - RelationGetRelationName(rel)))); - - /* Temp parent cannot have a partition that is itself not a temp */ - if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP && - attachrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("cannot attach a permanent relation as partition of temporary relation \"%s\"", - RelationGetRelationName(rel)))); - - /* If the parent is temp, it must belong to this session */ - if (RELATION_IS_OTHER_TEMP(rel)) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("cannot attach as partition of temporary relation of another session"))); - - /* Ditto for the partition */ - if (RELATION_IS_OTHER_TEMP(attachrel)) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("cannot attach temporary relation of another session as partition"))); - - /* - * Check if attachrel has any identity columns or any columns that aren't - * in the parent. - */ - tupleDesc = RelationGetDescr(attachrel); - natts = tupleDesc->natts; - for (attno = 1; attno <= natts; attno++) - { - Form_pg_attribute attribute = TupleDescAttr(tupleDesc, attno - 1); - char *attributeName = NameStr(attribute->attname); - - /* Ignore dropped */ - if (attribute->attisdropped) - continue; - - if (attribute->attidentity) - ereport(ERROR, - errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("table \"%s\" being attached contains an identity column \"%s\"", - RelationGetRelationName(attachrel), attributeName), - errdetail("The new partition may not contain an identity column.")); - - /* Try to find the column in parent (matching on column name) */ - if (!SearchSysCacheExists2(ATTNAME, - ObjectIdGetDatum(RelationGetRelid(rel)), - CStringGetDatum(attributeName))) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("table \"%s\" contains column \"%s\" not found in parent \"%s\"", - RelationGetRelationName(attachrel), attributeName, - RelationGetRelationName(rel)), - errdetail("The new partition may contain only the columns present in parent."))); - } - - /* - * If child_rel has row-level triggers with transition tables, we - * currently don't allow it to become a partition. See also prohibitions - * in ATExecAddInherit() and CreateTrigger(). - */ - trigger_name = FindTriggerIncompatibleWithInheritance(attachrel->trigdesc); - if (trigger_name != NULL) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("trigger \"%s\" prevents table \"%s\" from becoming a partition", - trigger_name, RelationGetRelationName(attachrel)), - errdetail("ROW triggers with transition tables are not supported on partitions."))); - - /* - * Check that the new partition's bound is valid and does not overlap any - * of existing partitions of the parent - note that it does not return on - * error. - */ - check_new_partition_bound(RelationGetRelationName(attachrel), rel, - cmd->bound, pstate); - - attachPartitionTable(wqueue, rel, attachrel, cmd->bound); - - /* - * Generate a partition constraint from the partition bound specification. - * If the parent itself is a partition, make sure to include its - * constraint as well. - */ - partBoundConstraint = get_qual_from_partbound(rel, cmd->bound); - - /* - * Use list_concat_copy() to avoid modifying partBoundConstraint in place, - * since it's needed later to construct the constraint expression for - * validating against the default partition, if any. - */ - partConstraint = list_concat_copy(partBoundConstraint, - RelationGetPartitionQual(rel)); - - /* Skip validation if there are no constraints to validate. */ - if (partConstraint) - { - /* - * Run the partition quals through const-simplification similar to - * check constraints. We skip canonicalize_qual, though, because - * partition quals should be in canonical form already. - */ - partConstraint = - (List *) eval_const_expressions(NULL, - (Node *) partConstraint); - - /* XXX this sure looks wrong */ - partConstraint = list_make1(make_ands_explicit(partConstraint)); - - /* - * Adjust the generated constraint to match this partition's attribute - * numbers. - */ - partConstraint = map_partition_varattnos(partConstraint, 1, attachrel, - rel); - - /* Validate partition constraints against the table being attached. */ - QueuePartitionConstraintValidation(wqueue, attachrel, partConstraint, - false); - } - - /* - * If we're attaching a partition other than the default partition and a - * default one exists, then that partition's partition constraint changes, - * so add an entry to the work queue to validate it, too. (We must not do - * this when the partition being attached is the default one; we already - * did it above!) - */ - if (OidIsValid(defaultPartOid)) - { - Relation defaultrel; - List *defPartConstraint; - - Assert(!cmd->bound->is_default); - - /* we already hold a lock on the default partition */ - defaultrel = table_open(defaultPartOid, NoLock); - defPartConstraint = - get_proposed_default_constraint(partBoundConstraint); - - /* - * Map the Vars in the constraint expression from rel's attnos to - * defaultrel's. - */ - defPartConstraint = - map_partition_varattnos(defPartConstraint, - 1, defaultrel, rel); - QueuePartitionConstraintValidation(wqueue, defaultrel, - defPartConstraint, true); - - /* keep our lock until commit. */ - table_close(defaultrel, NoLock); - } - - ObjectAddressSet(address, RelationRelationId, RelationGetRelid(attachrel)); - - /* - * If the partition we just attached is partitioned itself, invalidate - * relcache for all descendent partitions too to ensure that their - * rd_partcheck expression trees are rebuilt; partitions already locked at - * the beginning of this function. - */ - if (attachrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) - { - ListCell *l; - - foreach(l, attachrel_children) - { - CacheInvalidateRelcacheByRelid(lfirst_oid(l)); - } - } - - /* keep our lock until commit */ - table_close(attachrel, NoLock); - - return address; -} - -/* - * AttachPartitionEnsureIndexes - * subroutine for ATExecAttachPartition to create/match indexes - * - * Enforce the indexing rule for partitioned tables during ALTER TABLE / ATTACH - * PARTITION: every partition must have an index attached to each index on the - * partitioned table. - */ -static void -AttachPartitionEnsureIndexes(List **wqueue, Relation rel, Relation attachrel) -{ - List *idxes; - List *attachRelIdxs; - Relation *attachrelIdxRels; - IndexInfo **attachInfos; - ListCell *cell; - MemoryContext cxt; - MemoryContext oldcxt; - - cxt = AllocSetContextCreate(CurrentMemoryContext, - "AttachPartitionEnsureIndexes", - ALLOCSET_DEFAULT_SIZES); - oldcxt = MemoryContextSwitchTo(cxt); - - idxes = RelationGetIndexList(rel); - attachRelIdxs = RelationGetIndexList(attachrel); - attachrelIdxRels = palloc_array(Relation, list_length(attachRelIdxs)); - attachInfos = palloc_array(IndexInfo *, list_length(attachRelIdxs)); - - /* Build arrays of all existing indexes and their IndexInfos */ - foreach_oid(cldIdxId, attachRelIdxs) - { - int i = foreach_current_index(cldIdxId); - - attachrelIdxRels[i] = index_open(cldIdxId, AccessShareLock); - attachInfos[i] = BuildIndexInfo(attachrelIdxRels[i]); - } - - /* - * If we're attaching a foreign table, we must fail if any of the indexes - * is a constraint index; otherwise, there's nothing to do here. Do this - * before starting work, to avoid wasting the effort of building a few - * non-unique indexes before coming across a unique one. - */ - if (attachrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE) - { - foreach(cell, idxes) - { - Oid idx = lfirst_oid(cell); - Relation idxRel = index_open(idx, AccessShareLock); - - if (idxRel->rd_index->indisunique || - idxRel->rd_index->indisprimary) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("cannot attach foreign table \"%s\" as partition of partitioned table \"%s\"", - RelationGetRelationName(attachrel), - RelationGetRelationName(rel)), - errdetail("Partitioned table \"%s\" contains unique indexes.", - RelationGetRelationName(rel)))); - index_close(idxRel, AccessShareLock); - } - - goto out; - } - - /* - * For each index on the partitioned table, find a matching one in the - * partition-to-be; if one is not found, create one. - */ - foreach(cell, idxes) - { - Oid idx = lfirst_oid(cell); - Relation idxRel = index_open(idx, AccessShareLock); - IndexInfo *info; - AttrMap *attmap; - bool found = false; - Oid constraintOid; - - /* - * Ignore indexes in the partitioned table other than partitioned - * indexes. - */ - if (idxRel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX) - { - index_close(idxRel, AccessShareLock); - continue; - } - - /* construct an indexinfo to compare existing indexes against */ - info = BuildIndexInfo(idxRel); - attmap = build_attrmap_by_name(RelationGetDescr(attachrel), - RelationGetDescr(rel), - false); - constraintOid = get_relation_idx_constraint_oid(RelationGetRelid(rel), idx); - - /* - * Scan the list of existing indexes in the partition-to-be, and mark - * the first matching, valid, unattached one we find, if any, as - * partition of the parent index. If we find one, we're done. - */ - for (int i = 0; i < list_length(attachRelIdxs); i++) - { - Oid cldIdxId = RelationGetRelid(attachrelIdxRels[i]); - Oid cldConstrOid = InvalidOid; - - /* does this index have a parent? if so, can't use it */ - if (attachrelIdxRels[i]->rd_rel->relispartition) - continue; - - /* If this index is invalid, can't use it */ - if (!attachrelIdxRels[i]->rd_index->indisvalid) - continue; - - if (CompareIndexInfo(attachInfos[i], info, - attachrelIdxRels[i]->rd_indcollation, - idxRel->rd_indcollation, - attachrelIdxRels[i]->rd_opfamily, - idxRel->rd_opfamily, - attmap)) - { - /* - * If this index is being created in the parent because of a - * constraint, then the child needs to have a constraint also, - * so look for one. If there is no such constraint, this - * index is no good, so keep looking. - */ - if (OidIsValid(constraintOid)) - { - cldConstrOid = - get_relation_idx_constraint_oid(RelationGetRelid(attachrel), - cldIdxId); - /* no dice */ - if (!OidIsValid(cldConstrOid)) - continue; - - /* Ensure they're both the same type of constraint */ - if (get_constraint_type(constraintOid) != - get_constraint_type(cldConstrOid)) - continue; - } - - /* bingo. */ - IndexSetParentIndex(attachrelIdxRels[i], idx); - if (OidIsValid(constraintOid)) - ConstraintSetParentConstraint(cldConstrOid, constraintOid, - RelationGetRelid(attachrel)); - found = true; - - CommandCounterIncrement(); - break; - } - } - - /* - * If no suitable index was found in the partition-to-be, create one - * now. Note that if this is a PK, not-null constraints must already - * exist. - */ - if (!found) - { - IndexStmt *stmt; - Oid conOid; - - stmt = generateClonedIndexStmt(NULL, - idxRel, attmap, - &conOid); - DefineIndex(NULL, - RelationGetRelid(attachrel), stmt, InvalidOid, - RelationGetRelid(idxRel), - conOid, - -1, - true, false, false, false, false); - } - - index_close(idxRel, AccessShareLock); - } - -out: - /* Clean up. */ - for (int i = 0; i < list_length(attachRelIdxs); i++) - index_close(attachrelIdxRels[i], AccessShareLock); - MemoryContextSwitchTo(oldcxt); - MemoryContextDelete(cxt); -} - -/* - * CloneRowTriggersToPartition - * subroutine for ATExecAttachPartition/DefineRelation to create row - * triggers on partitions - */ -static void -CloneRowTriggersToPartition(Relation parent, Relation partition) -{ - Relation pg_trigger; - ScanKeyData key; - SysScanDesc scan; - HeapTuple tuple; - MemoryContext perTupCxt; - - ScanKeyInit(&key, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber, - F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parent))); - pg_trigger = table_open(TriggerRelationId, RowExclusiveLock); - scan = systable_beginscan(pg_trigger, TriggerRelidNameIndexId, - true, NULL, 1, &key); - - perTupCxt = AllocSetContextCreate(CurrentMemoryContext, - "clone trig", ALLOCSET_SMALL_SIZES); - - while (HeapTupleIsValid(tuple = systable_getnext(scan))) - { - Form_pg_trigger trigForm = (Form_pg_trigger) GETSTRUCT(tuple); - CreateTrigStmt *trigStmt; - Node *qual = NULL; - Datum value; - bool isnull; - List *cols = NIL; - List *trigargs = NIL; - MemoryContext oldcxt; - - /* - * Ignore statement-level triggers; those are not cloned. - */ - if (!TRIGGER_FOR_ROW(trigForm->tgtype)) - continue; - - /* - * Don't clone internal triggers, because the constraint cloning code - * will. - */ - if (trigForm->tgisinternal) - continue; - - /* - * Complain if we find an unexpected trigger type. - */ - if (!TRIGGER_FOR_BEFORE(trigForm->tgtype) && - !TRIGGER_FOR_AFTER(trigForm->tgtype)) - elog(ERROR, "unexpected trigger \"%s\" found", - NameStr(trigForm->tgname)); - - /* Use short-lived context for CREATE TRIGGER */ - oldcxt = MemoryContextSwitchTo(perTupCxt); - - /* - * If there is a WHEN clause, generate a 'cooked' version of it that's - * appropriate for the partition. - */ - value = heap_getattr(tuple, Anum_pg_trigger_tgqual, - RelationGetDescr(pg_trigger), &isnull); - if (!isnull) - { - qual = stringToNode(TextDatumGetCString(value)); - qual = (Node *) map_partition_varattnos((List *) qual, PRS2_OLD_VARNO, - partition, parent); - qual = (Node *) map_partition_varattnos((List *) qual, PRS2_NEW_VARNO, - partition, parent); - } - - /* - * If there is a column list, transform it to a list of column names. - * Note we don't need to map this list in any way ... - */ - if (trigForm->tgattr.dim1 > 0) - { - int i; - - for (i = 0; i < trigForm->tgattr.dim1; i++) - { - Form_pg_attribute col; - - col = TupleDescAttr(parent->rd_att, - trigForm->tgattr.values[i] - 1); - cols = lappend(cols, - makeString(pstrdup(NameStr(col->attname)))); - } - } - - /* Reconstruct trigger arguments list. */ - if (trigForm->tgnargs > 0) - { - char *p; - - value = heap_getattr(tuple, Anum_pg_trigger_tgargs, - RelationGetDescr(pg_trigger), &isnull); - if (isnull) - elog(ERROR, "tgargs is null for trigger \"%s\" in partition \"%s\"", - NameStr(trigForm->tgname), RelationGetRelationName(partition)); - - p = (char *) VARDATA_ANY(DatumGetByteaPP(value)); - - for (int i = 0; i < trigForm->tgnargs; i++) - { - trigargs = lappend(trigargs, makeString(pstrdup(p))); - p += strlen(p) + 1; - } - } - - trigStmt = makeNode(CreateTrigStmt); - trigStmt->replace = false; - trigStmt->isconstraint = OidIsValid(trigForm->tgconstraint); - trigStmt->trigname = NameStr(trigForm->tgname); - trigStmt->relation = NULL; - trigStmt->funcname = NULL; /* passed separately */ - trigStmt->args = trigargs; - trigStmt->row = true; - trigStmt->timing = trigForm->tgtype & TRIGGER_TYPE_TIMING_MASK; - trigStmt->events = trigForm->tgtype & TRIGGER_TYPE_EVENT_MASK; - trigStmt->columns = cols; - trigStmt->whenClause = NULL; /* passed separately */ - trigStmt->transitionRels = NIL; /* not supported at present */ - trigStmt->deferrable = trigForm->tgdeferrable; - trigStmt->initdeferred = trigForm->tginitdeferred; - trigStmt->constrrel = NULL; /* passed separately */ - - CreateTriggerFiringOn(trigStmt, NULL, RelationGetRelid(partition), - trigForm->tgconstrrelid, InvalidOid, InvalidOid, - trigForm->tgfoid, trigForm->oid, qual, - false, true, trigForm->tgenabled); - - MemoryContextSwitchTo(oldcxt); - MemoryContextReset(perTupCxt); - } - - MemoryContextDelete(perTupCxt); - - systable_endscan(scan); - table_close(pg_trigger, RowExclusiveLock); -} - -/* - * ALTER TABLE DETACH PARTITION - * - * Return the address of the relation that is no longer a partition of rel. - * - * If concurrent mode is requested, we run in two transactions. A side- - * effect is that this command cannot run in a multi-part ALTER TABLE. - * Currently, that's enforced by the grammar. - * - * The strategy for concurrency is to first modify the partition's - * pg_inherit catalog row to make it visible to everyone that the - * partition is detached, lock the partition against writes, and commit - * the transaction; anyone who requests the partition descriptor from - * that point onwards has to ignore such a partition. In a second - * transaction, we wait until all transactions that could have seen the - * partition as attached are gone, then we remove the rest of partition - * metadata (pg_inherits and pg_class.relpartbounds). - */ -static ObjectAddress -ATExecDetachPartition(List **wqueue, AlteredTableInfo *tab, Relation rel, - RangeVar *name, bool concurrent) -{ - Relation partRel; - ObjectAddress address; - Oid defaultPartOid; - - /* - * We must lock the default partition, because detaching this partition - * will change its partition constraint. - */ - defaultPartOid = - get_default_oid_from_partdesc(RelationGetPartitionDesc(rel, true)); - if (OidIsValid(defaultPartOid)) - { - /* - * Concurrent detaching when a default partition exists is not - * supported. The main problem is that the default partition - * constraint would change. And there's a definitional problem: what - * should happen to the tuples that are being inserted that belong to - * the partition being detached? Putting them on the partition being - * detached would be wrong, since they'd become "lost" after the - * detaching completes but we cannot put them in the default partition - * either until we alter its partition constraint. - * - * I think we could solve this problem if we effected the constraint - * change before committing the first transaction. But the lock would - * have to remain AEL and it would cause concurrent query planning to - * be blocked, so changing it that way would be even worse. - */ - if (concurrent) - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("cannot detach partitions concurrently when a default partition exists"))); - LockRelationOid(defaultPartOid, AccessExclusiveLock); - } - - /* - * In concurrent mode, the partition is locked with share-update-exclusive - * in the first transaction. This allows concurrent transactions to be - * doing DML to the partition. - */ - partRel = table_openrv(name, concurrent ? ShareUpdateExclusiveLock : - AccessExclusiveLock); - - /* - * Check inheritance conditions and either delete the pg_inherits row (in - * non-concurrent mode) or just set the inhdetachpending flag. - */ - if (!concurrent) - RemoveInheritance(partRel, rel, false); - else - MarkInheritDetached(partRel, rel); - - /* - * Ensure that foreign keys still hold after this detach. This keeps - * locks on the referencing tables, which prevents concurrent transactions - * from adding rows that we wouldn't see. For this to work in concurrent - * mode, it is critical that the partition appears as no longer attached - * for the RI queries as soon as the first transaction commits. - */ - ATDetachCheckNoForeignKeyRefs(partRel); - - /* - * Concurrent mode has to work harder; first we add a new constraint to - * the partition that matches the partition constraint. Then we close our - * existing transaction, and in a new one wait for all processes to catch - * up on the catalog updates we've done so far; at that point we can - * complete the operation. - */ - if (concurrent) - { - Oid partrelid, - parentrelid; - LOCKTAG tag; - char *parentrelname; - char *partrelname; - - /* - * We're almost done now; the only traces that remain are the - * pg_inherits tuple and the partition's relpartbounds. Before we can - * remove those, we need to wait until all transactions that know that - * this is a partition are gone. - */ - - /* - * Remember relation OIDs to re-acquire them later; and relation names - * too, for error messages if something is dropped in between. - */ - partrelid = RelationGetRelid(partRel); - parentrelid = RelationGetRelid(rel); - parentrelname = MemoryContextStrdup(PortalContext, - RelationGetRelationName(rel)); - partrelname = MemoryContextStrdup(PortalContext, - RelationGetRelationName(partRel)); - - /* Invalidate relcache entries for the parent -- must be before close */ - CacheInvalidateRelcache(rel); - - table_close(partRel, NoLock); - table_close(rel, NoLock); - tab->rel = NULL; - - /* Make updated catalog entry visible */ - PopActiveSnapshot(); - CommitTransactionCommand(); - - StartTransactionCommand(); - - /* - * Now wait. This ensures that all queries that were planned - * including the partition are finished before we remove the rest of - * catalog entries. We don't need or indeed want to acquire this - * lock, though -- that would block later queries. - * - * We don't need to concern ourselves with waiting for a lock on the - * partition itself, since we will acquire AccessExclusiveLock below. - */ - SET_LOCKTAG_RELATION(tag, MyDatabaseId, parentrelid); - WaitForLockersMultiple(list_make1(&tag), AccessExclusiveLock, false); - - /* - * Now acquire locks in both relations again. Note they may have been - * removed in the meantime, so care is required. - */ - rel = try_relation_open(parentrelid, ShareUpdateExclusiveLock); - partRel = try_relation_open(partrelid, AccessExclusiveLock); - - /* If the relations aren't there, something bad happened; bail out */ - if (rel == NULL) - { - if (partRel != NULL) /* shouldn't happen */ - elog(WARNING, "dangling partition \"%s\" remains, can't fix", - partrelname); - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("partitioned table \"%s\" was removed concurrently", - parentrelname))); - } - if (partRel == NULL) - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("partition \"%s\" was removed concurrently", partrelname))); - - tab->rel = rel; - } - - /* - * Detaching the partition might involve TOAST table access, so ensure we - * have a valid snapshot. - */ - PushActiveSnapshot(GetTransactionSnapshot()); - - /* Do the final part of detaching */ - DetachPartitionFinalize(rel, partRel, concurrent, defaultPartOid); - - PopActiveSnapshot(); - - ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel)); - - /* keep our lock until commit */ - table_close(partRel, NoLock); - - return address; -} - -/* - * Second part of ALTER TABLE .. DETACH. - * - * This is separate so that it can be run independently when the second - * transaction of the concurrent algorithm fails (crash or abort). - */ -static void -DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent, - Oid defaultPartOid) -{ - Relation classRel; - List *fks; - ListCell *cell; - List *indexes; - Datum new_val[Natts_pg_class]; - bool new_null[Natts_pg_class], - new_repl[Natts_pg_class]; - HeapTuple tuple, - newtuple; - Relation trigrel = NULL; - List *fkoids = NIL; - - if (concurrent) - { - /* - * We can remove the pg_inherits row now. (In the non-concurrent case, - * this was already done). - */ - RemoveInheritance(partRel, rel, true); - } - - /* Drop any triggers that were cloned on creation/attach. */ - DropClonedTriggersFromPartition(RelationGetRelid(partRel)); - - /* - * Detach any foreign keys that are inherited. This includes creating - * additional action triggers. - */ - fks = copyObject(RelationGetFKeyList(partRel)); - if (fks != NIL) - trigrel = table_open(TriggerRelationId, RowExclusiveLock); - - /* - * It's possible that the partition being detached has a foreign key that - * references a partitioned table. When that happens, there are multiple - * pg_constraint rows for the partition: one points to the partitioned - * table itself, while the others point to each of its partitions. Only - * the topmost one is to be considered here; the child constraints must be - * left alone, because conceptually those aren't coming from our parent - * partitioned table, but from this partition itself. - * - * We implement this by collecting all the constraint OIDs in a first scan - * of the FK array, and skipping in the loop below those constraints whose - * parents are listed here. - */ - foreach_node(ForeignKeyCacheInfo, fk, fks) - fkoids = lappend_oid(fkoids, fk->conoid); - - foreach(cell, fks) - { - ForeignKeyCacheInfo *fk = lfirst(cell); - HeapTuple contup; - Form_pg_constraint conform; - - contup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(fk->conoid)); - if (!HeapTupleIsValid(contup)) - elog(ERROR, "cache lookup failed for constraint %u", fk->conoid); - conform = (Form_pg_constraint) GETSTRUCT(contup); - - /* - * Consider only inherited foreign keys, and only if their parents - * aren't in the list. - */ - if (conform->contype != CONSTRAINT_FOREIGN || - !OidIsValid(conform->conparentid) || - list_member_oid(fkoids, conform->conparentid)) - { - ReleaseSysCache(contup); - continue; - } - - /* - * The constraint on this table must be marked no longer a child of - * the parent's constraint, as do its check triggers. - */ - ConstraintSetParentConstraint(fk->conoid, InvalidOid, InvalidOid); - - /* - * Also, look up the partition's "check" triggers corresponding to the - * ENFORCED constraint being detached and detach them from the parent - * triggers. NOT ENFORCED constraints do not have these triggers; - * therefore, this step is not needed. - */ - if (fk->conenforced) - { - Oid insertTriggerOid, - updateTriggerOid; - - GetForeignKeyCheckTriggers(trigrel, - fk->conoid, fk->confrelid, fk->conrelid, - &insertTriggerOid, &updateTriggerOid); - Assert(OidIsValid(insertTriggerOid)); - TriggerSetParentTrigger(trigrel, insertTriggerOid, InvalidOid, - RelationGetRelid(partRel)); - Assert(OidIsValid(updateTriggerOid)); - TriggerSetParentTrigger(trigrel, updateTriggerOid, InvalidOid, - RelationGetRelid(partRel)); - } - - /* - * Lastly, create the action triggers on the referenced table, using - * addFkRecurseReferenced, which requires some elaborate setup (so put - * it in a separate block). While at it, if the table is partitioned, - * that function will recurse to create the pg_constraint rows and - * action triggers for each partition. - * - * Note there's no need to do addFkConstraint() here, because the - * pg_constraint row already exists. - */ - { - Constraint *fkconstraint; - int numfks; - AttrNumber conkey[INDEX_MAX_KEYS]; - AttrNumber confkey[INDEX_MAX_KEYS]; - Oid conpfeqop[INDEX_MAX_KEYS]; - Oid conppeqop[INDEX_MAX_KEYS]; - Oid conffeqop[INDEX_MAX_KEYS]; - int numfkdelsetcols; - AttrNumber confdelsetcols[INDEX_MAX_KEYS]; - Relation refdRel; - - DeconstructFkConstraintRow(contup, - &numfks, - conkey, - confkey, - conpfeqop, - conppeqop, - conffeqop, - &numfkdelsetcols, - confdelsetcols); - - /* Create a synthetic node we'll use throughout */ - fkconstraint = makeNode(Constraint); - fkconstraint->contype = CONSTRAINT_FOREIGN; - fkconstraint->conname = pstrdup(NameStr(conform->conname)); - fkconstraint->deferrable = conform->condeferrable; - fkconstraint->initdeferred = conform->condeferred; - fkconstraint->is_enforced = conform->conenforced; - fkconstraint->skip_validation = true; - fkconstraint->initially_valid = conform->convalidated; - /* a few irrelevant fields omitted here */ - fkconstraint->pktable = NULL; - fkconstraint->fk_attrs = NIL; - fkconstraint->pk_attrs = NIL; - fkconstraint->fk_matchtype = conform->confmatchtype; - fkconstraint->fk_upd_action = conform->confupdtype; - fkconstraint->fk_del_action = conform->confdeltype; - fkconstraint->fk_del_set_cols = NIL; - fkconstraint->old_conpfeqop = NIL; - fkconstraint->old_pktable_oid = InvalidOid; - fkconstraint->location = -1; - - /* set up colnames, used to generate the constraint name */ - for (int i = 0; i < numfks; i++) - { - Form_pg_attribute att; - - att = TupleDescAttr(RelationGetDescr(partRel), - conkey[i] - 1); - - fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs, - makeString(NameStr(att->attname))); - } - - refdRel = table_open(fk->confrelid, ShareRowExclusiveLock); - - addFkRecurseReferenced(fkconstraint, partRel, - refdRel, - conform->conindid, - fk->conoid, - numfks, - confkey, - conkey, - conpfeqop, - conppeqop, - conffeqop, - numfkdelsetcols, - confdelsetcols, - true, - InvalidOid, InvalidOid, - conform->conperiod); - table_close(refdRel, NoLock); /* keep lock till end of xact */ - } - - ReleaseSysCache(contup); - } - list_free_deep(fks); - if (trigrel) - table_close(trigrel, RowExclusiveLock); - - /* - * Any sub-constraints that are in the referenced-side of a larger - * constraint have to be removed. This partition is no longer part of the - * key space of the constraint. - */ - foreach(cell, GetParentedForeignKeyRefs(partRel)) - { - Oid constrOid = lfirst_oid(cell); - ObjectAddress constraint; - - ConstraintSetParentConstraint(constrOid, InvalidOid, InvalidOid); - deleteDependencyRecordsForClass(ConstraintRelationId, - constrOid, - ConstraintRelationId, - DEPENDENCY_INTERNAL); - CommandCounterIncrement(); - - ObjectAddressSet(constraint, ConstraintRelationId, constrOid); - performDeletion(&constraint, DROP_RESTRICT, 0); - } - - /* Now we can detach indexes */ - indexes = RelationGetIndexList(partRel); - foreach(cell, indexes) - { - Oid idxid = lfirst_oid(cell); - Oid parentidx; - Relation idx; - Oid constrOid; - Oid parentConstrOid; - - if (!has_superclass(idxid)) - continue; - - parentidx = get_partition_parent(idxid, false); - Assert((IndexGetRelation(parentidx, false) == RelationGetRelid(rel))); - - idx = index_open(idxid, AccessExclusiveLock); - IndexSetParentIndex(idx, InvalidOid); - - /* - * If there's a constraint associated with the index, detach it too. - * Careful: it is possible for a constraint index in a partition to be - * the child of a non-constraint index, so verify whether the parent - * index does actually have a constraint. - */ - constrOid = get_relation_idx_constraint_oid(RelationGetRelid(partRel), - idxid); - parentConstrOid = get_relation_idx_constraint_oid(RelationGetRelid(rel), - parentidx); - if (OidIsValid(parentConstrOid) && OidIsValid(constrOid)) - ConstraintSetParentConstraint(constrOid, InvalidOid, InvalidOid); - - index_close(idx, NoLock); - } - - /* Update pg_class tuple */ - classRel = table_open(RelationRelationId, RowExclusiveLock); - tuple = SearchSysCacheCopy1(RELOID, - ObjectIdGetDatum(RelationGetRelid(partRel))); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for relation %u", - RelationGetRelid(partRel)); - Assert(((Form_pg_class) GETSTRUCT(tuple))->relispartition); - - /* Clear relpartbound and reset relispartition */ - memset(new_val, 0, sizeof(new_val)); - memset(new_null, false, sizeof(new_null)); - memset(new_repl, false, sizeof(new_repl)); - new_val[Anum_pg_class_relpartbound - 1] = (Datum) 0; - new_null[Anum_pg_class_relpartbound - 1] = true; - new_repl[Anum_pg_class_relpartbound - 1] = true; - newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel), - new_val, new_null, new_repl); - - ((Form_pg_class) GETSTRUCT(newtuple))->relispartition = false; - CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple); - heap_freetuple(newtuple); - table_close(classRel, RowExclusiveLock); - - /* - * Drop identity property from all identity columns of partition. - */ - for (int attno = 0; attno < RelationGetNumberOfAttributes(partRel); attno++) - { - Form_pg_attribute attr = TupleDescAttr(partRel->rd_att, attno); - - if (!attr->attisdropped && attr->attidentity) - ATExecDropIdentity(partRel, NameStr(attr->attname), false, - AccessExclusiveLock, true, true); - } - - if (OidIsValid(defaultPartOid)) - { - /* - * If the relation being detached is the default partition itself, - * remove it from the parent's pg_partitioned_table entry. - * - * If not, we must invalidate default partition's relcache entry, as - * in StorePartitionBound: its partition constraint depends on every - * other partition's partition constraint. - */ - if (RelationGetRelid(partRel) == defaultPartOid) - update_default_partition_oid(RelationGetRelid(rel), InvalidOid); - else - CacheInvalidateRelcacheByRelid(defaultPartOid); - } - - /* - * Invalidate the parent's relcache so that the partition is no longer - * included in its partition descriptor. - */ - CacheInvalidateRelcache(rel); - - /* - * If the partition we just detached is partitioned itself, invalidate - * relcache for all descendent partitions too to ensure that their - * rd_partcheck expression trees are rebuilt; must lock partitions before - * doing so, using the same lockmode as what partRel has been locked with - * by the caller. - */ - if (partRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) - { - List *children; - - children = find_all_inheritors(RelationGetRelid(partRel), - AccessExclusiveLock, NULL); - foreach(cell, children) - { - CacheInvalidateRelcacheByRelid(lfirst_oid(cell)); - } - } -} - -/* - * ALTER TABLE ... DETACH PARTITION ... FINALIZE - * - * To use when a DETACH PARTITION command previously did not run to - * completion; this completes the detaching process. - */ -static ObjectAddress -ATExecDetachPartitionFinalize(Relation rel, RangeVar *name) -{ - Relation partRel; - ObjectAddress address; - Snapshot snap = GetActiveSnapshot(); - - partRel = table_openrv(name, AccessExclusiveLock); - - /* - * Wait until existing snapshots are gone. This is important if the - * second transaction of DETACH PARTITION CONCURRENTLY is canceled: the - * user could immediately run DETACH FINALIZE without actually waiting for - * existing transactions. We must not complete the detach action until - * all such queries are complete (otherwise we would present them with an - * inconsistent view of catalogs). - */ - WaitForOlderSnapshots(snap->xmin, false); - - DetachPartitionFinalize(rel, partRel, true, InvalidOid); - - ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel)); - - table_close(partRel, NoLock); - - return address; -} - -/* - * DropClonedTriggersFromPartition - * subroutine for ATExecDetachPartition to remove any triggers that were - * cloned to the partition when it was created-as-partition or attached. - * This undoes what CloneRowTriggersToPartition did. - */ -static void -DropClonedTriggersFromPartition(Oid partitionId) -{ - ScanKeyData skey; - SysScanDesc scan; - HeapTuple trigtup; - Relation tgrel; - ObjectAddresses *objects; - - objects = new_object_addresses(); - - /* - * Scan pg_trigger to search for all triggers on this rel. - */ - ScanKeyInit(&skey, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber, - F_OIDEQ, ObjectIdGetDatum(partitionId)); - tgrel = table_open(TriggerRelationId, RowExclusiveLock); - scan = systable_beginscan(tgrel, TriggerRelidNameIndexId, - true, NULL, 1, &skey); - while (HeapTupleIsValid(trigtup = systable_getnext(scan))) - { - Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(trigtup); - ObjectAddress trig; - - /* Ignore triggers that weren't cloned */ - if (!OidIsValid(pg_trigger->tgparentid)) - continue; - - /* - * Ignore internal triggers that are implementation objects of foreign - * keys, because these will be detached when the foreign keys - * themselves are. - */ - if (OidIsValid(pg_trigger->tgconstrrelid)) - continue; - - /* - * This is ugly, but necessary: remove the dependency markings on the - * trigger so that it can be removed. - */ - deleteDependencyRecordsForClass(TriggerRelationId, pg_trigger->oid, - TriggerRelationId, - DEPENDENCY_PARTITION_PRI); - deleteDependencyRecordsForClass(TriggerRelationId, pg_trigger->oid, - RelationRelationId, - DEPENDENCY_PARTITION_SEC); - - /* remember this trigger to remove it below */ - ObjectAddressSet(trig, TriggerRelationId, pg_trigger->oid); - add_exact_object_address(&trig, objects); - } - - /* make the dependency removal visible to the deletion below */ - CommandCounterIncrement(); - performMultipleDeletions(objects, DROP_RESTRICT, PERFORM_DELETION_INTERNAL); - - /* done */ - free_object_addresses(objects); - systable_endscan(scan); - table_close(tgrel, RowExclusiveLock); -} - -/* - * Before acquiring lock on an index, acquire the same lock on the owning - * table. - */ -struct AttachIndexCallbackState -{ - Oid partitionOid; - Oid parentTblOid; - bool lockedParentTbl; -}; - -static void -RangeVarCallbackForAttachIndex(const RangeVar *rv, Oid relOid, Oid oldRelOid, - void *arg) -{ - struct AttachIndexCallbackState *state; - Form_pg_class classform; - HeapTuple tuple; - - state = (struct AttachIndexCallbackState *) arg; - - if (!state->lockedParentTbl) - { - LockRelationOid(state->parentTblOid, AccessShareLock); - state->lockedParentTbl = true; - } - - /* - * If we previously locked some other heap, and the name we're looking up - * no longer refers to an index on that relation, release the now-useless - * lock. XXX maybe we should do *after* we verify whether the index does - * not actually belong to the same relation ... - */ - if (relOid != oldRelOid && OidIsValid(state->partitionOid)) - { - UnlockRelationOid(state->partitionOid, AccessShareLock); - state->partitionOid = InvalidOid; - } - - /* Didn't find a relation, so no need for locking or permission checks. */ - if (!OidIsValid(relOid)) - return; - - tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid)); - if (!HeapTupleIsValid(tuple)) - return; /* concurrently dropped, so nothing to do */ - classform = (Form_pg_class) GETSTRUCT(tuple); - if (classform->relkind != RELKIND_PARTITIONED_INDEX && - classform->relkind != RELKIND_INDEX) - ereport(ERROR, - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("\"%s\" is not an index", rv->relname))); - ReleaseSysCache(tuple); - - /* - * Since we need only examine the heap's tupledesc, an access share lock - * on it (preventing any DDL) is sufficient. - */ - state->partitionOid = IndexGetRelation(relOid, false); - LockRelationOid(state->partitionOid, AccessShareLock); -} - -/* - * ALTER INDEX i1 ATTACH PARTITION i2 - */ -static ObjectAddress -ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx, RangeVar *name) -{ - Relation partIdx; - Relation partTbl; - Relation parentTbl; - ObjectAddress address; - Oid partIdxId; - Oid currParent; - struct AttachIndexCallbackState state; - - /* - * We need to obtain lock on the index 'name' to modify it, but we also - * need to read its owning table's tuple descriptor -- so we need to lock - * both. To avoid deadlocks, obtain lock on the table before doing so on - * the index. Furthermore, we need to examine the parent table of the - * partition, so lock that one too. - */ - state.partitionOid = InvalidOid; - state.parentTblOid = parentIdx->rd_index->indrelid; - state.lockedParentTbl = false; - partIdxId = - RangeVarGetRelidExtended(name, AccessExclusiveLock, 0, - RangeVarCallbackForAttachIndex, - &state); - /* Not there? */ - if (!OidIsValid(partIdxId)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("index \"%s\" does not exist", name->relname))); - - /* no deadlock risk: RangeVarGetRelidExtended already acquired the lock */ - partIdx = relation_open(partIdxId, AccessExclusiveLock); - - /* we already hold locks on both tables, so this is safe: */ - parentTbl = relation_open(parentIdx->rd_index->indrelid, AccessShareLock); - partTbl = relation_open(partIdx->rd_index->indrelid, NoLock); - - ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partIdx)); - - /* Silently do nothing if already in the right state */ - currParent = partIdx->rd_rel->relispartition ? - get_partition_parent(partIdxId, false) : InvalidOid; - if (currParent != RelationGetRelid(parentIdx)) - { - IndexInfo *childInfo; - IndexInfo *parentInfo; - AttrMap *attmap; - bool found; - int i; - PartitionDesc partDesc; - Oid constraintOid, - cldConstrId = InvalidOid; - - /* - * If this partition already has an index attached, refuse the - * operation. - */ - refuseDupeIndexAttach(parentIdx, partIdx, partTbl); - - if (OidIsValid(currParent)) - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("cannot attach index \"%s\" as a partition of index \"%s\"", - RelationGetRelationName(partIdx), - RelationGetRelationName(parentIdx)), - errdetail("Index \"%s\" is already attached to another index.", - RelationGetRelationName(partIdx)))); - - /* Make sure it indexes a partition of the other index's table */ - partDesc = RelationGetPartitionDesc(parentTbl, true); - found = false; - for (i = 0; i < partDesc->nparts; i++) - { - if (partDesc->oids[i] == state.partitionOid) - { - found = true; - break; - } - } - if (!found) - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("cannot attach index \"%s\" as a partition of index \"%s\"", - RelationGetRelationName(partIdx), - RelationGetRelationName(parentIdx)), - errdetail("Index \"%s\" is not an index on any partition of table \"%s\".", - RelationGetRelationName(partIdx), - RelationGetRelationName(parentTbl)))); - - /* Ensure the indexes are compatible */ - childInfo = BuildIndexInfo(partIdx); - parentInfo = BuildIndexInfo(parentIdx); - attmap = build_attrmap_by_name(RelationGetDescr(partTbl), - RelationGetDescr(parentTbl), - false); - if (!CompareIndexInfo(childInfo, parentInfo, - partIdx->rd_indcollation, - parentIdx->rd_indcollation, - partIdx->rd_opfamily, - parentIdx->rd_opfamily, - attmap)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("cannot attach index \"%s\" as a partition of index \"%s\"", - RelationGetRelationName(partIdx), - RelationGetRelationName(parentIdx)), - errdetail("The index definitions do not match."))); - - /* - * If there is a constraint in the parent, make sure there is one in - * the child too. - */ - constraintOid = get_relation_idx_constraint_oid(RelationGetRelid(parentTbl), - RelationGetRelid(parentIdx)); - - if (OidIsValid(constraintOid)) - { - cldConstrId = get_relation_idx_constraint_oid(RelationGetRelid(partTbl), - partIdxId); - if (!OidIsValid(cldConstrId)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("cannot attach index \"%s\" as a partition of index \"%s\"", - RelationGetRelationName(partIdx), - RelationGetRelationName(parentIdx)), - errdetail("The index \"%s\" belongs to a constraint in table \"%s\" but no constraint exists for index \"%s\".", - RelationGetRelationName(parentIdx), - RelationGetRelationName(parentTbl), - RelationGetRelationName(partIdx)))); - } - - /* - * If it's a primary key, make sure the columns in the partition are - * NOT NULL. - */ - if (parentIdx->rd_index->indisprimary) - verifyPartitionIndexNotNull(childInfo, partTbl); - - /* All good -- do it */ - IndexSetParentIndex(partIdx, RelationGetRelid(parentIdx)); - if (OidIsValid(constraintOid)) - ConstraintSetParentConstraint(cldConstrId, constraintOid, - RelationGetRelid(partTbl)); - - free_attrmap(attmap); - - validatePartitionedIndex(parentIdx, parentTbl); - } - - relation_close(parentTbl, AccessShareLock); - /* keep these locks till commit */ - relation_close(partTbl, NoLock); - relation_close(partIdx, NoLock); - - return address; -} - -/* - * Verify whether the given partition already contains an index attached - * to the given partitioned index. If so, raise an error. - */ -static void -refuseDupeIndexAttach(Relation parentIdx, Relation partIdx, Relation partitionTbl) -{ - Oid existingIdx; - - existingIdx = index_get_partition(partitionTbl, - RelationGetRelid(parentIdx)); - if (OidIsValid(existingIdx)) - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("cannot attach index \"%s\" as a partition of index \"%s\"", - RelationGetRelationName(partIdx), - RelationGetRelationName(parentIdx)), - errdetail("Another index \"%s\" is already attached for partition \"%s\".", - get_rel_name(existingIdx), - RelationGetRelationName(partitionTbl)))); -} - -/* - * Verify whether the set of attached partition indexes to a parent index on - * a partitioned table is complete. If it is, mark the parent index valid. - * - * This should be called each time a partition index is attached. - */ -static void -validatePartitionedIndex(Relation partedIdx, Relation partedTbl) -{ - Relation inheritsRel; - SysScanDesc scan; - ScanKeyData key; - int tuples = 0; - HeapTuple inhTup; - bool updated = false; - - Assert(partedIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX); - - /* - * Scan pg_inherits for this parent index. Count each valid index we find - * (verifying the pg_index entry for each), and if we reach the total - * amount we expect, we can mark this parent index as valid. - */ - inheritsRel = table_open(InheritsRelationId, AccessShareLock); - ScanKeyInit(&key, Anum_pg_inherits_inhparent, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(RelationGetRelid(partedIdx))); - scan = systable_beginscan(inheritsRel, InheritsParentIndexId, true, - NULL, 1, &key); - while ((inhTup = systable_getnext(scan)) != NULL) - { - Form_pg_inherits inhForm = (Form_pg_inherits) GETSTRUCT(inhTup); - HeapTuple indTup; - Form_pg_index indexForm; - - indTup = SearchSysCache1(INDEXRELID, - ObjectIdGetDatum(inhForm->inhrelid)); - if (!HeapTupleIsValid(indTup)) - elog(ERROR, "cache lookup failed for index %u", inhForm->inhrelid); - indexForm = (Form_pg_index) GETSTRUCT(indTup); - if (indexForm->indisvalid) - tuples += 1; - ReleaseSysCache(indTup); - } - - /* Done with pg_inherits */ - systable_endscan(scan); - table_close(inheritsRel, AccessShareLock); - - /* - * If we found as many inherited indexes as the partitioned table has - * partitions, we're good; update pg_index to set indisvalid. - */ - if (tuples == RelationGetPartitionDesc(partedTbl, true)->nparts) - { - Relation idxRel; - HeapTuple indTup; - Form_pg_index indexForm; - - idxRel = table_open(IndexRelationId, RowExclusiveLock); - indTup = SearchSysCacheCopy1(INDEXRELID, - ObjectIdGetDatum(RelationGetRelid(partedIdx))); - if (!HeapTupleIsValid(indTup)) - elog(ERROR, "cache lookup failed for index %u", - RelationGetRelid(partedIdx)); - indexForm = (Form_pg_index) GETSTRUCT(indTup); - - indexForm->indisvalid = true; - updated = true; - - CatalogTupleUpdate(idxRel, &indTup->t_self, indTup); - - table_close(idxRel, RowExclusiveLock); - heap_freetuple(indTup); - } - - /* - * If this index is in turn a partition of a larger index, validating it - * might cause the parent to become valid also. Try that. - */ - if (updated && partedIdx->rd_rel->relispartition) - { - Oid parentIdxId, - parentTblId; - Relation parentIdx, - parentTbl; - - /* make sure we see the validation we just did */ - CommandCounterIncrement(); - - parentIdxId = get_partition_parent(RelationGetRelid(partedIdx), false); - parentTblId = get_partition_parent(RelationGetRelid(partedTbl), false); - parentIdx = relation_open(parentIdxId, AccessExclusiveLock); - parentTbl = relation_open(parentTblId, AccessExclusiveLock); - Assert(!parentIdx->rd_index->indisvalid); - - validatePartitionedIndex(parentIdx, parentTbl); - - relation_close(parentIdx, AccessExclusiveLock); - relation_close(parentTbl, AccessExclusiveLock); - } -} - -/* - * When attaching an index as a partition of a partitioned index which is a - * primary key, verify that all the columns in the partition are marked NOT - * NULL. - */ -static void -verifyPartitionIndexNotNull(IndexInfo *iinfo, Relation partition) -{ - for (int i = 0; i < iinfo->ii_NumIndexKeyAttrs; i++) - { - Form_pg_attribute att = TupleDescAttr(RelationGetDescr(partition), - iinfo->ii_IndexAttrNumbers[i] - 1); - - if (!att->attnotnull) - ereport(ERROR, - errcode(ERRCODE_INVALID_TABLE_DEFINITION), - errmsg("invalid primary key definition"), - errdetail("Column \"%s\" of relation \"%s\" is not marked NOT NULL.", - NameStr(att->attname), - RelationGetRelationName(partition))); - } -} - -/* - * Return an OID list of constraints that reference the given relation - * that are marked as having a parent constraints. - */ -static List * -GetParentedForeignKeyRefs(Relation partition) -{ - Relation pg_constraint; - HeapTuple tuple; - SysScanDesc scan; - ScanKeyData key[2]; - List *constraints = NIL; - - /* - * If no indexes, or no columns are referenceable by FKs, we can avoid the - * scan. - */ - if (RelationGetIndexList(partition) == NIL || - bms_is_empty(RelationGetIndexAttrBitmap(partition, - INDEX_ATTR_BITMAP_KEY))) - return NIL; - - /* Search for constraints referencing this table */ - pg_constraint = table_open(ConstraintRelationId, AccessShareLock); - ScanKeyInit(&key[0], - Anum_pg_constraint_confrelid, BTEqualStrategyNumber, - F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(partition))); - ScanKeyInit(&key[1], - Anum_pg_constraint_contype, BTEqualStrategyNumber, - F_CHAREQ, CharGetDatum(CONSTRAINT_FOREIGN)); - - /* XXX This is a seqscan, as we don't have a usable index */ - scan = systable_beginscan(pg_constraint, InvalidOid, true, NULL, 2, key); - while ((tuple = systable_getnext(scan)) != NULL) - { - Form_pg_constraint constrForm = (Form_pg_constraint) GETSTRUCT(tuple); - - /* - * We only need to process constraints that are part of larger ones. - */ - if (!OidIsValid(constrForm->conparentid)) - continue; - - constraints = lappend_oid(constraints, constrForm->oid); - } - - systable_endscan(scan); - table_close(pg_constraint, AccessShareLock); - - return constraints; -} - -/* - * During DETACH PARTITION, verify that any foreign keys pointing to the - * partitioned table would not become invalid. An error is raised if any - * referenced values exist. - */ -static void -ATDetachCheckNoForeignKeyRefs(Relation partition) -{ - List *constraints; - ListCell *cell; - - constraints = GetParentedForeignKeyRefs(partition); - - foreach(cell, constraints) - { - Oid constrOid = lfirst_oid(cell); - HeapTuple tuple; - Form_pg_constraint constrForm; - Relation rel; - Trigger trig = {0}; - - tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid)); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for constraint %u", constrOid); - constrForm = (Form_pg_constraint) GETSTRUCT(tuple); - - Assert(OidIsValid(constrForm->conparentid)); - Assert(constrForm->confrelid == RelationGetRelid(partition)); - - /* prevent data changes into the referencing table until commit */ - rel = table_open(constrForm->conrelid, ShareLock); - - trig.tgoid = InvalidOid; - trig.tgname = NameStr(constrForm->conname); - trig.tgenabled = TRIGGER_FIRES_ON_ORIGIN; - trig.tgisinternal = true; - trig.tgconstrrelid = RelationGetRelid(partition); - trig.tgconstrindid = constrForm->conindid; - trig.tgconstraint = constrForm->oid; - trig.tgdeferrable = false; - trig.tginitdeferred = false; - /* we needn't fill in remaining fields */ - - RI_PartitionRemove_Check(&trig, rel, partition); - - ReleaseSysCache(tuple); - - table_close(rel, NoLock); - } -} - /* * resolve column compression specification to compression method. */ @@ -22104,1239 +18579,3 @@ GetAttributeStorage(Oid atttypid, const char *storagemode) return cstorage; } - -/* - * buildExpressionExecutionStates: build the needed expression execution states - * for new partition (newPartRel) checks and initialize expressions for - * generated columns. All expressions should be created in "tab" - * (AlteredTableInfo structure). - */ -static void -buildExpressionExecutionStates(AlteredTableInfo *tab, Relation newPartRel, EState *estate) -{ - /* - * Build the needed expression execution states. Here, we expect only NOT - * NULL and CHECK constraint. - */ - foreach_ptr(NewConstraint, con, tab->constraints) - { - switch (con->contype) - { - case CONSTR_CHECK: - - /* - * We already expanded virtual expression in - * createTableConstraints. - */ - con->qualstate = ExecPrepareExpr((Expr *) con->qual, estate); - break; - case CONSTR_NOTNULL: - /* Nothing to do here. */ - break; - default: - elog(ERROR, "unrecognized constraint type: %d", - (int) con->contype); - } - } - - /* Expression already planned in createTableConstraints */ - foreach_ptr(NewColumnValue, ex, tab->newvals) - ex->exprstate = ExecInitExpr((Expr *) ex->expr, NULL); -} - -/* - * evaluateGeneratedExpressionsAndCheckConstraints: evaluate any generated - * expressions for "tab" (AlteredTableInfo structure) whose inputs come from - * the new tuple (insertslot) of the new partition (newPartRel). - */ -static void -evaluateGeneratedExpressionsAndCheckConstraints(AlteredTableInfo *tab, - Relation newPartRel, - TupleTableSlot *insertslot, - ExprContext *econtext) -{ - econtext->ecxt_scantuple = insertslot; - - foreach_ptr(NewColumnValue, ex, tab->newvals) - { - if (!ex->is_generated) - continue; - - insertslot->tts_values[ex->attnum - 1] - = ExecEvalExpr(ex->exprstate, - econtext, - &insertslot->tts_isnull[ex->attnum - 1]); - } - - foreach_ptr(NewConstraint, con, tab->constraints) - { - switch (con->contype) - { - case CONSTR_CHECK: - if (!ExecCheck(con->qualstate, econtext)) - ereport(ERROR, - errcode(ERRCODE_CHECK_VIOLATION), - errmsg("check constraint \"%s\" of relation \"%s\" is violated by some row", - con->name, RelationGetRelationName(newPartRel)), - errtableconstraint(newPartRel, con->name)); - break; - case CONSTR_NOTNULL: - case CONSTR_FOREIGN: - /* Nothing to do here */ - break; - default: - elog(ERROR, "unrecognized constraint type: %d", - (int) con->contype); - } - } -} - -/* - * getAttributesList: build a list of columns (ColumnDef) based on parent_rel - */ -static List * -getAttributesList(Relation parent_rel) -{ - AttrNumber parent_attno; - TupleDesc modelDesc; - List *colList = NIL; - - modelDesc = RelationGetDescr(parent_rel); - - for (parent_attno = 1; parent_attno <= modelDesc->natts; - parent_attno++) - { - Form_pg_attribute attribute = TupleDescAttr(modelDesc, - parent_attno - 1); - ColumnDef *def; - - /* Ignore dropped columns in the parent. */ - if (attribute->attisdropped) - continue; - - def = makeColumnDef(NameStr(attribute->attname), attribute->atttypid, - attribute->atttypmod, attribute->attcollation); - - def->is_not_null = attribute->attnotnull; - - /* Copy identity. */ - def->identity = attribute->attidentity; - - /* Copy attgenerated. */ - def->generated = attribute->attgenerated; - - def->storage = attribute->attstorage; - - /* Likewise, copy compression. */ - if (CompressionMethodIsValid(attribute->attcompression)) - def->compression = - pstrdup(GetCompressionMethodName(attribute->attcompression)); - else - def->compression = NULL; - - /* Add to column list. */ - colList = lappend(colList, def); - } - - return colList; -} - -/* - * createTableConstraints: - * create check constraints, default values, and generated values for newRel - * based on parent_rel. tab is pending-work queue for newRel, we may need it in - * MergePartitionsMoveRows. - */ -static void -createTableConstraints(List **wqueue, AlteredTableInfo *tab, - Relation parent_rel, Relation newRel) -{ - TupleDesc tupleDesc; - TupleConstr *constr; - AttrMap *attmap; - AttrNumber parent_attno; - int ccnum; - List *constraints = NIL; - List *cookedConstraints = NIL; - - tupleDesc = RelationGetDescr(parent_rel); - constr = tupleDesc->constr; - - if (!constr) - return; - - /* - * Construct a map from the parent relation's attnos to the child rel's. - * This re-checks type match, etc, although it shouldn't be possible to - * have a failure since both tables are locked. - */ - attmap = build_attrmap_by_name(RelationGetDescr(newRel), - tupleDesc, - false); - - /* Cycle for default values. */ - for (parent_attno = 1; parent_attno <= tupleDesc->natts; parent_attno++) - { - Form_pg_attribute attribute = TupleDescAttr(tupleDesc, - parent_attno - 1); - - /* Ignore dropped columns in the parent. */ - if (attribute->attisdropped) - continue; - - /* Copy the default, if present, and it should be copied. */ - if (attribute->atthasdef) - { - Node *this_default = NULL; - bool found_whole_row; - AttrNumber num; - Node *def; - NewColumnValue *newval; - - if (attribute->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL) - this_default = build_generation_expression(parent_rel, attribute->attnum); - else - { - this_default = TupleDescGetDefault(tupleDesc, attribute->attnum); - if (this_default == NULL) - elog(ERROR, "default expression not found for attribute %d of relation \"%s\"", - attribute->attnum, RelationGetRelationName(parent_rel)); - } - - num = attmap->attnums[parent_attno - 1]; - def = map_variable_attnos(this_default, 1, 0, attmap, InvalidOid, &found_whole_row); - - if (found_whole_row && attribute->attgenerated != '\0') - elog(ERROR, "cannot convert whole-row table reference"); - - /* Add a pre-cooked default expression. */ - StoreAttrDefault(newRel, num, def, true); - - /* - * Stored generated column expressions in parent_rel might - * reference the tableoid. newRel, parent_rel tableoid clear is - * not the same. If so, these stored generated columns require - * recomputation for newRel within MergePartitionsMoveRows. - */ - if (attribute->attgenerated == ATTRIBUTE_GENERATED_STORED) - { - newval = palloc0_object(NewColumnValue); - newval->attnum = num; - newval->expr = expression_planner((Expr *) def); - newval->is_generated = (attribute->attgenerated != '\0'); - tab->newvals = lappend(tab->newvals, newval); - } - } - } - - /* Cycle for CHECK constraints. */ - for (ccnum = 0; ccnum < constr->num_check; ccnum++) - { - char *ccname = constr->check[ccnum].ccname; - char *ccbin = constr->check[ccnum].ccbin; - bool ccenforced = constr->check[ccnum].ccenforced; - bool ccnoinherit = constr->check[ccnum].ccnoinherit; - bool ccvalid = constr->check[ccnum].ccvalid; - Node *ccbin_node; - bool found_whole_row; - Constraint *constr; - - /* - * The partitioned table can not have a NO INHERIT check constraint - * (see StoreRelCheck function for details). - */ - Assert(!ccnoinherit); - - ccbin_node = map_variable_attnos(stringToNode(ccbin), - 1, 0, - attmap, - InvalidOid, &found_whole_row); - - /* - * For the moment we have to reject whole-row variables (as for CREATE - * TABLE LIKE and inheritances). - */ - if (found_whole_row) - elog(ERROR, "Constraint \"%s\" contains a whole-row reference to table \"%s\".", - ccname, - RelationGetRelationName(parent_rel)); - - constr = makeNode(Constraint); - constr->contype = CONSTR_CHECK; - constr->conname = pstrdup(ccname); - constr->deferrable = false; - constr->initdeferred = false; - constr->is_enforced = ccenforced; - constr->skip_validation = !ccvalid; - constr->initially_valid = ccvalid; - constr->is_no_inherit = ccnoinherit; - constr->raw_expr = NULL; - constr->cooked_expr = nodeToString(ccbin_node); - constr->location = -1; - constraints = lappend(constraints, constr); - } - - /* Install all CHECK constraints. */ - cookedConstraints = AddRelationNewConstraints(newRel, NIL, constraints, - false, true, true, NULL); - - /* Make the additional catalog changes visible. */ - CommandCounterIncrement(); - - /* - * parent_rel check constraint expression may reference tableoid, so later - * in MergePartitionsMoveRows, we need to evaluate the check constraint - * again for the newRel. We can check whether the check constraint - * contains a tableoid reference via pull_varattnos. - */ - foreach_ptr(CookedConstraint, ccon, cookedConstraints) - { - if (!ccon->skip_validation) - { - Node *qual; - Bitmapset *attnums = NULL; - - Assert(ccon->contype == CONSTR_CHECK); - qual = expand_generated_columns_in_expr(ccon->expr, newRel, 1); - pull_varattnos(qual, 1, &attnums); - - /* - * Add a check only if it contains a tableoid - * (TableOidAttributeNumber). - */ - if (bms_is_member(TableOidAttributeNumber - FirstLowInvalidHeapAttributeNumber, - attnums)) - { - NewConstraint *newcon; - - newcon = palloc0_object(NewConstraint); - newcon->name = ccon->name; - newcon->contype = CONSTR_CHECK; - newcon->qual = qual; - - tab->constraints = lappend(tab->constraints, newcon); - } - } - } - - /* Don't need the cookedConstraints anymore. */ - list_free_deep(cookedConstraints); - - /* Reproduce not-null constraints. */ - if (constr->has_not_null) - { - List *nnconstraints; - - /* - * The "include_noinh" argument is false because a partitioned table - * can't have NO INHERIT constraint. - */ - nnconstraints = RelationGetNotNullConstraints(RelationGetRelid(parent_rel), - false, false); - - Assert(list_length(nnconstraints) > 0); - - /* - * We already set pg_attribute.attnotnull in createPartitionTable. No - * need call set_attnotnull again. - */ - AddRelationNewConstraints(newRel, NIL, nnconstraints, false, true, true, NULL); - } -} - -/* - * createPartitionTable: - * - * Create a new partition (newPartName) for the partitioned table (parent_rel). - * ownerId is determined by the partition on which the operation is performed, - * so it is passed separately. The new partition will inherit the access method - * and persistence type from the parent table. - * - * Returns the created relation (locked in AccessExclusiveLock mode). - */ -static Relation -createPartitionTable(List **wqueue, RangeVar *newPartName, - Relation parent_rel, Oid ownerId) -{ - Relation newRel; - Oid newRelId; - Oid existingRelid; - TupleDesc descriptor; - List *colList = NIL; - Oid relamId; - Oid namespaceId; - AlteredTableInfo *new_partrel_tab; - Form_pg_class parent_relform = parent_rel->rd_rel; - - /* If the existing rel is temp, it must belong to this session. */ - if (RELATION_IS_OTHER_TEMP(parent_rel)) - ereport(ERROR, - errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("cannot create as partition of temporary relation of another session")); - - /* Look up inheritance ancestors and generate the relation schema. */ - colList = getAttributesList(parent_rel); - - /* Create a tuple descriptor from the relation schema. */ - descriptor = BuildDescForRelation(colList); - - /* Look up the access method for the new relation. */ - relamId = (parent_relform->relam != InvalidOid) ? parent_relform->relam : HEAP_TABLE_AM_OID; - - /* Look up the namespace in which we are supposed to create the relation. */ - namespaceId = - RangeVarGetAndCheckCreationNamespace(newPartName, NoLock, &existingRelid); - if (OidIsValid(existingRelid)) - ereport(ERROR, - errcode(ERRCODE_DUPLICATE_TABLE), - errmsg("relation \"%s\" already exists", newPartName->relname)); - - /* - * We intended to create the partition with the same persistence as the - * parent table, but we still need to recheck because that might be - * affected by the search_path. If the parent is permanent, so must be - * all of its partitions. - */ - if (parent_relform->relpersistence != RELPERSISTENCE_TEMP && - newPartName->relpersistence == RELPERSISTENCE_TEMP) - ereport(ERROR, - errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("cannot create a temporary relation as partition of permanent relation \"%s\"", - RelationGetRelationName(parent_rel))); - - /* Permanent rels cannot be partitions belonging to a temporary parent. */ - if (newPartName->relpersistence != RELPERSISTENCE_TEMP && - parent_relform->relpersistence == RELPERSISTENCE_TEMP) - ereport(ERROR, - errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("cannot create a permanent relation as partition of temporary relation \"%s\"", - RelationGetRelationName(parent_rel))); - - /* Create the relation. */ - newRelId = heap_create_with_catalog(newPartName->relname, - namespaceId, - parent_relform->reltablespace, - InvalidOid, - InvalidOid, - InvalidOid, - ownerId, - relamId, - descriptor, - NIL, - RELKIND_RELATION, - newPartName->relpersistence, - false, - false, - ONCOMMIT_NOOP, - (Datum) 0, - true, - allowSystemTableMods, - true, - InvalidOid, - NULL); - - /* - * We must bump the command counter to make the newly-created relation - * tuple visible for opening. - */ - CommandCounterIncrement(); - - /* - * Open the new partition with no lock, because we already have an - * AccessExclusiveLock placed there after creation. - */ - newRel = table_open(newRelId, NoLock); - - /* Find or create a work queue entry for the newly created table. */ - new_partrel_tab = ATGetQueueEntry(wqueue, newRel); - - /* Create constraints, default values, and generated values. */ - createTableConstraints(wqueue, new_partrel_tab, parent_rel, newRel); - - /* - * Need to call CommandCounterIncrement, so a fresh relcache entry has - * newly installed constraint info. - */ - CommandCounterIncrement(); - - return newRel; -} - -/* - * MergePartitionsMoveRows: scan partitions to be merged (mergingPartitions) - * of the partitioned table and move rows into the new partition - * (newPartRel). We also verify check constraints against these rows. - */ -static void -MergePartitionsMoveRows(List **wqueue, List *mergingPartitions, Relation newPartRel) -{ - CommandId mycid; - EState *estate; - AlteredTableInfo *tab; - ListCell *ltab; - - /* The FSM is empty, so don't bother using it. */ - int ti_options = TABLE_INSERT_SKIP_FSM; - BulkInsertState bistate; /* state of bulk inserts for partition */ - TupleTableSlot *dstslot; - - /* Find the work queue entry for the new partition table: newPartRel. */ - tab = ATGetQueueEntry(wqueue, newPartRel); - - /* Generate the constraint and default execution states. */ - estate = CreateExecutorState(); - - buildExpressionExecutionStates(tab, newPartRel, estate); - - mycid = GetCurrentCommandId(true); - - /* Prepare a BulkInsertState for table_tuple_insert. */ - bistate = GetBulkInsertState(); - - /* Create the necessary tuple slot. */ - dstslot = table_slot_create(newPartRel, NULL); - - foreach_oid(merging_oid, mergingPartitions) - { - ExprContext *econtext; - TupleTableSlot *srcslot; - TupleConversionMap *tuple_map; - TableScanDesc scan; - MemoryContext oldCxt; - Snapshot snapshot; - Relation mergingPartition; - - econtext = GetPerTupleExprContext(estate); - - /* - * Partition is already locked in the transformPartitionCmdForMerge - * function. - */ - mergingPartition = table_open(merging_oid, NoLock); - - /* Create a source tuple slot for the partition being merged. */ - srcslot = table_slot_create(mergingPartition, NULL); - - /* - * Map computing for moving attributes of the merged partition to the - * new partition. - */ - tuple_map = convert_tuples_by_name(RelationGetDescr(mergingPartition), - RelationGetDescr(newPartRel)); - - /* Scan through the rows. */ - snapshot = RegisterSnapshot(GetLatestSnapshot()); - scan = table_beginscan(mergingPartition, snapshot, 0, NULL); - - /* - * Switch to per-tuple memory context and reset it for each tuple - * produced, so we don't leak memory. - */ - oldCxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); - - while (table_scan_getnextslot(scan, ForwardScanDirection, srcslot)) - { - TupleTableSlot *insertslot; - - CHECK_FOR_INTERRUPTS(); - - if (tuple_map) - { - /* Need to use a map to copy attributes. */ - insertslot = execute_attr_map_slot(tuple_map->attrMap, srcslot, dstslot); - } - else - { - slot_getallattrs(srcslot); - - /* Copy attributes directly. */ - insertslot = dstslot; - - ExecClearTuple(insertslot); - - memcpy(insertslot->tts_values, srcslot->tts_values, - sizeof(Datum) * srcslot->tts_nvalid); - memcpy(insertslot->tts_isnull, srcslot->tts_isnull, - sizeof(bool) * srcslot->tts_nvalid); - - ExecStoreVirtualTuple(insertslot); - } - - /* - * Constraints and GENERATED expressions might reference the - * tableoid column, so fill tts_tableOid with the desired value. - * (We must do this each time, because it gets overwritten with - * newrel's OID during storing.) - */ - insertslot->tts_tableOid = RelationGetRelid(newPartRel); - - /* - * Now, evaluate any generated expressions whose inputs come from - * the new tuple. We assume these columns won't reference each - * other, so that there's no ordering dependency. - */ - evaluateGeneratedExpressionsAndCheckConstraints(tab, newPartRel, - insertslot, econtext); - - /* Write the tuple out to the new relation. */ - table_tuple_insert(newPartRel, insertslot, mycid, - ti_options, bistate); - - ResetExprContext(econtext); - } - - MemoryContextSwitchTo(oldCxt); - table_endscan(scan); - UnregisterSnapshot(snapshot); - - if (tuple_map) - free_conversion_map(tuple_map); - - ExecDropSingleTupleTableSlot(srcslot); - table_close(mergingPartition, NoLock); - } - - FreeExecutorState(estate); - ExecDropSingleTupleTableSlot(dstslot); - FreeBulkInsertState(bistate); - - table_finish_bulk_insert(newPartRel, ti_options); - - /* - * We don't need to process this newPartRel since we already processed it - * here, so delete the ALTER TABLE queue for it. - */ - foreach(ltab, *wqueue) - { - tab = (AlteredTableInfo *) lfirst(ltab); - if (tab->relid == RelationGetRelid(newPartRel)) - { - *wqueue = list_delete_cell(*wqueue, ltab); - break; - } - } -} - -/* - * detachPartitionTable: detach partition "child_rel" from partitioned table - * "parent_rel" with default partition identifier "defaultPartOid" - */ -static void -detachPartitionTable(Relation parent_rel, Relation child_rel, Oid defaultPartOid) -{ - /* Remove the pg_inherits row first. */ - RemoveInheritance(child_rel, parent_rel, false); - - /* - * Detaching the partition might involve TOAST table access, so ensure we - * have a valid snapshot. - */ - PushActiveSnapshot(GetTransactionSnapshot()); - - /* Do the final part of detaching. */ - DetachPartitionFinalize(parent_rel, child_rel, false, defaultPartOid); - - PopActiveSnapshot(); -} - -/* - * ALTER TABLE <name> MERGE PARTITIONS <partition-list> INTO <partition-name> - */ -static void -ATExecMergePartitions(List **wqueue, AlteredTableInfo *tab, Relation rel, - PartitionCmd *cmd, AlterTableUtilityContext *context) -{ - Relation newPartRel; - List *mergingPartitions = NIL; - Oid defaultPartOid; - Oid existingRelid; - Oid ownerId = InvalidOid; - Oid save_userid; - int save_sec_context; - int save_nestlevel; - - /* - * Check ownership of merged partitions - partitions with different owners - * cannot be merged. Also, collect the OIDs of these partitions during the - * check. - */ - foreach_node(RangeVar, name, cmd->partlist) - { - Relation mergingPartition; - - /* - * We are going to detach and remove this partition. We already took - * AccessExclusiveLock lock on transformPartitionCmdForMerge, so here, - * NoLock is fine. - */ - mergingPartition = table_openrv_extended(name, NoLock, false); - Assert(CheckRelationLockedByMe(mergingPartition, AccessExclusiveLock, false)); - - if (OidIsValid(ownerId)) - { - /* Do the partitions being merged have different owners? */ - if (ownerId != mergingPartition->rd_rel->relowner) - ereport(ERROR, - errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("partitions being merged have different owners")); - } - else - ownerId = mergingPartition->rd_rel->relowner; - - /* Store the next merging partition into the list. */ - mergingPartitions = lappend_oid(mergingPartitions, - RelationGetRelid(mergingPartition)); - - table_close(mergingPartition, NoLock); - } - - /* Look up the existing relation by the new partition name. */ - RangeVarGetAndCheckCreationNamespace(cmd->name, NoLock, &existingRelid); - - /* - * Check if this name is already taken. This helps us to detect the - * situation when one of the merging partitions has the same name as the - * new partition. Otherwise, this would fail later on anyway, but - * catching this here allows us to emit a nicer error message. - */ - if (OidIsValid(existingRelid)) - { - if (list_member_oid(mergingPartitions, existingRelid)) - { - /* - * The new partition has the same name as one of the merging - * partitions. - */ - char tmpRelName[NAMEDATALEN]; - - /* Generate a temporary name. */ - sprintf(tmpRelName, "merge-%u-%X-tmp", RelationGetRelid(rel), MyProcPid); - - /* - * Rename the existing partition with a temporary name, leaving it - * free for the new partition. We don't need to care about this - * in the future because we're going to eventually drop the - * existing partition anyway. - */ - RenameRelationInternal(existingRelid, tmpRelName, true, false); - - /* - * We must bump the command counter to make the new partition - * tuple visible for rename. - */ - CommandCounterIncrement(); - } - else - { - ereport(ERROR, - errcode(ERRCODE_DUPLICATE_TABLE), - errmsg("relation \"%s\" already exists", cmd->name->relname)); - } - } - - defaultPartOid = - get_default_oid_from_partdesc(RelationGetPartitionDesc(rel, true)); - - /* Detach all merging partitions. */ - foreach_oid(mergingPartitionOid, mergingPartitions) - { - Relation child_rel; - - child_rel = table_open(mergingPartitionOid, NoLock); - - detachPartitionTable(rel, child_rel, defaultPartOid); - - table_close(child_rel, NoLock); - } - - /* - * Perform a preliminary check to determine whether it's safe to drop all - * merging partitions before we actually do so later. After merging rows - * into the new partitions via MergePartitionsMoveRows, all old partitions - * need to be dropped. However, since the drop behavior is DROP_RESTRICT - * and the merge process (MergePartitionsMoveRows) can be time-consuming, - * performing an early check on the drop eligibility of old partitions is - * preferable. - */ - foreach_oid(mergingPartitionOid, mergingPartitions) - { - ObjectAddress object; - - /* Get oid of the later to be dropped relation. */ - object.objectId = mergingPartitionOid; - object.classId = RelationRelationId; - object.objectSubId = 0; - - performDeletionCheck(&object, DROP_RESTRICT, PERFORM_DELETION_INTERNAL); - } - - /* - * Create a table for the new partition, using the partitioned table as a - * model. - */ - Assert(OidIsValid(ownerId)); - newPartRel = createPartitionTable(wqueue, cmd->name, rel, ownerId); - - /* - * Switch to the table owner's userid, so that any index functions are run - * as that user. Also, lockdown security-restricted operations and - * arrange to make GUC variable changes local to this command. - * - * Need to do it after determining the namespace in the - * createPartitionTable() call. - */ - GetUserIdAndSecContext(&save_userid, &save_sec_context); - SetUserIdAndSecContext(ownerId, - save_sec_context | SECURITY_RESTRICTED_OPERATION); - save_nestlevel = NewGUCNestLevel(); - RestrictSearchPath(); - - /* Copy data from merged partitions to the new partition. */ - MergePartitionsMoveRows(wqueue, mergingPartitions, newPartRel); - - /* Drop the current partitions before attaching the new one. */ - foreach_oid(mergingPartitionOid, mergingPartitions) - { - ObjectAddress object; - - object.objectId = mergingPartitionOid; - object.classId = RelationRelationId; - object.objectSubId = 0; - - performDeletion(&object, DROP_RESTRICT, 0); - } - - list_free(mergingPartitions); - - /* - * Attach a new partition to the partitioned table. wqueue = NULL: - * verification for each cloned constraint is not needed. - */ - attachPartitionTable(NULL, rel, newPartRel, cmd->bound); - - /* Keep the lock until commit. */ - table_close(newPartRel, NoLock); - - /* Roll back any GUC changes executed by index functions. */ - AtEOXact_GUC(false, save_nestlevel); - - /* Restore the userid and security context. */ - SetUserIdAndSecContext(save_userid, save_sec_context); -} - -/* - * Struct with the context of the new partition for inserting rows from the - * split partition. - */ -typedef struct SplitPartitionContext -{ - ExprState *partqualstate; /* expression for checking a slot for a - * partition (NULL for DEFAULT partition) */ - BulkInsertState bistate; /* state of bulk inserts for partition */ - TupleTableSlot *dstslot; /* slot for inserting row into partition */ - AlteredTableInfo *tab; /* structure with generated column expressions - * and check constraint expressions. */ - Relation partRel; /* relation for partition */ -} SplitPartitionContext; - -/* - * createSplitPartitionContext: create context for partition and fill it - */ -static SplitPartitionContext * -createSplitPartitionContext(Relation partRel) -{ - SplitPartitionContext *pc; - - pc = palloc0_object(SplitPartitionContext); - pc->partRel = partRel; - - /* - * Prepare a BulkInsertState for table_tuple_insert. The FSM is empty, so - * don't bother using it. - */ - pc->bistate = GetBulkInsertState(); - - /* Create a destination tuple slot for the new partition. */ - pc->dstslot = table_slot_create(pc->partRel, NULL); - - return pc; -} - -/* - * deleteSplitPartitionContext: delete context for partition - */ -static void -deleteSplitPartitionContext(SplitPartitionContext *pc, List **wqueue, int ti_options) -{ - ListCell *ltab; - - ExecDropSingleTupleTableSlot(pc->dstslot); - FreeBulkInsertState(pc->bistate); - - table_finish_bulk_insert(pc->partRel, ti_options); - - /* - * We don't need to process this pc->partRel so delete the ALTER TABLE - * queue of it. - */ - foreach(ltab, *wqueue) - { - AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab); - - if (tab->relid == RelationGetRelid(pc->partRel)) - { - *wqueue = list_delete_cell(*wqueue, ltab); - break; - } - } - - pfree(pc); -} - -/* - * SplitPartitionMoveRows: scan split partition (splitRel) of partitioned table - * (rel) and move rows into new partitions. - * - * New partitions description: - * partlist: list of pointers to SinglePartitionSpec structures. It contains - * the partition specification details for all new partitions. - * newPartRels: list of Relations, new partitions created in - * ATExecSplitPartition. - */ -static void -SplitPartitionMoveRows(List **wqueue, Relation rel, Relation splitRel, - List *partlist, List *newPartRels) -{ - /* The FSM is empty, so don't bother using it. */ - int ti_options = TABLE_INSERT_SKIP_FSM; - CommandId mycid; - EState *estate; - ListCell *listptr, - *listptr2; - TupleTableSlot *srcslot; - ExprContext *econtext; - TableScanDesc scan; - Snapshot snapshot; - MemoryContext oldCxt; - List *partContexts = NIL; - TupleConversionMap *tuple_map; - SplitPartitionContext *defaultPartCtx = NULL, - *pc; - - mycid = GetCurrentCommandId(true); - - estate = CreateExecutorState(); - - forboth(listptr, partlist, listptr2, newPartRels) - { - SinglePartitionSpec *sps = (SinglePartitionSpec *) lfirst(listptr); - - pc = createSplitPartitionContext((Relation) lfirst(listptr2)); - - /* Find the work queue entry for the new partition table: newPartRel. */ - pc->tab = ATGetQueueEntry(wqueue, pc->partRel); - - buildExpressionExecutionStates(pc->tab, pc->partRel, estate); - - if (sps->bound->is_default) - { - /* - * We should not create a structure to check the partition - * constraint for the new DEFAULT partition. - */ - defaultPartCtx = pc; - } - else - { - List *partConstraint; - - /* Build expression execution states for partition check quals. */ - partConstraint = get_qual_from_partbound(rel, sps->bound); - partConstraint = - (List *) eval_const_expressions(NULL, - (Node *) partConstraint); - /* Make a boolean expression for ExecCheck(). */ - partConstraint = list_make1(make_ands_explicit(partConstraint)); - - /* - * Map the vars in the constraint expression from rel's attnos to - * splitRel's. - */ - partConstraint = map_partition_varattnos(partConstraint, - 1, splitRel, rel); - - pc->partqualstate = - ExecPrepareExpr((Expr *) linitial(partConstraint), estate); - Assert(pc->partqualstate != NULL); - } - - /* Store partition context into a list. */ - partContexts = lappend(partContexts, pc); - } - - econtext = GetPerTupleExprContext(estate); - - /* Create the necessary tuple slot. */ - srcslot = table_slot_create(splitRel, NULL); - - /* - * Map computing for moving attributes of the split partition to the new - * partition (for the first new partition, but other new partitions can - * use the same map). - */ - pc = (SplitPartitionContext *) lfirst(list_head(partContexts)); - tuple_map = convert_tuples_by_name(RelationGetDescr(splitRel), - RelationGetDescr(pc->partRel)); - - /* Scan through the rows. */ - snapshot = RegisterSnapshot(GetLatestSnapshot()); - scan = table_beginscan(splitRel, snapshot, 0, NULL); - - /* - * Switch to per-tuple memory context and reset it for each tuple - * produced, so we don't leak memory. - */ - oldCxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); - - while (table_scan_getnextslot(scan, ForwardScanDirection, srcslot)) - { - bool found = false; - TupleTableSlot *insertslot; - - CHECK_FOR_INTERRUPTS(); - - econtext->ecxt_scantuple = srcslot; - - /* Search partition for the current slot, srcslot. */ - foreach(listptr, partContexts) - { - pc = (SplitPartitionContext *) lfirst(listptr); - - /* skip DEFAULT partition */ - if (pc->partqualstate && ExecCheck(pc->partqualstate, econtext)) - { - found = true; - break; - } - } - if (!found) - { - /* Use the DEFAULT partition if it exists. */ - if (defaultPartCtx) - pc = defaultPartCtx; - else - ereport(ERROR, - errcode(ERRCODE_CHECK_VIOLATION), - errmsg("can not find partition for split partition row"), - errtable(splitRel)); - } - - if (tuple_map) - { - /* Need to use a map to copy attributes. */ - insertslot = execute_attr_map_slot(tuple_map->attrMap, srcslot, pc->dstslot); - } - else - { - /* Extract data from the old tuple. */ - slot_getallattrs(srcslot); - - /* Copy attributes directly. */ - insertslot = pc->dstslot; - - ExecClearTuple(insertslot); - - memcpy(insertslot->tts_values, srcslot->tts_values, - sizeof(Datum) * srcslot->tts_nvalid); - memcpy(insertslot->tts_isnull, srcslot->tts_isnull, - sizeof(bool) * srcslot->tts_nvalid); - - ExecStoreVirtualTuple(insertslot); - } - - /* - * Constraints and GENERATED expressions might reference the tableoid - * column, so fill tts_tableOid with the desired value. (We must do - * this each time, because it gets overwritten with newrel's OID - * during storing.) - */ - insertslot->tts_tableOid = RelationGetRelid(pc->partRel); - - /* - * Now, evaluate any generated expressions whose inputs come from the - * new tuple. We assume these columns won't reference each other, so - * that there's no ordering dependency. - */ - evaluateGeneratedExpressionsAndCheckConstraints(pc->tab, pc->partRel, - insertslot, econtext); - - /* Write the tuple out to the new relation. */ - table_tuple_insert(pc->partRel, insertslot, mycid, - ti_options, pc->bistate); - - ResetExprContext(econtext); - } - - MemoryContextSwitchTo(oldCxt); - - table_endscan(scan); - UnregisterSnapshot(snapshot); - - if (tuple_map) - free_conversion_map(tuple_map); - - ExecDropSingleTupleTableSlot(srcslot); - - FreeExecutorState(estate); - - foreach_ptr(SplitPartitionContext, spc, partContexts) - deleteSplitPartitionContext(spc, wqueue, ti_options); -} - -/* - * ALTER TABLE <name> SPLIT PARTITION <partition-name> INTO <partition-list> - */ -static void -ATExecSplitPartition(List **wqueue, AlteredTableInfo *tab, Relation rel, - PartitionCmd *cmd, AlterTableUtilityContext *context) -{ - Relation splitRel; - Oid splitRelOid; - ListCell *listptr, - *listptr2; - bool isSameName = false; - char tmpRelName[NAMEDATALEN]; - List *newPartRels = NIL; - ObjectAddress object; - Oid defaultPartOid; - Oid save_userid; - int save_sec_context; - int save_nestlevel; - - defaultPartOid = get_default_oid_from_partdesc(RelationGetPartitionDesc(rel, true)); - - /* - * Partition is already locked in the transformPartitionCmdForSplit - * function. - */ - splitRel = table_openrv(cmd->name, NoLock); - - splitRelOid = RelationGetRelid(splitRel); - - /* Check descriptions of new partitions. */ - foreach_node(SinglePartitionSpec, sps, cmd->partlist) - { - Oid existingRelid; - - /* Look up the existing relation by the new partition name. */ - RangeVarGetAndCheckCreationNamespace(sps->name, NoLock, &existingRelid); - - /* - * This would fail later on anyway if the relation already exists. But - * by catching it here, we can emit a nicer error message. - */ - if (existingRelid == splitRelOid && !isSameName) - /* One new partition can have the same name as a split partition. */ - isSameName = true; - else if (OidIsValid(existingRelid)) - ereport(ERROR, - errcode(ERRCODE_DUPLICATE_TABLE), - errmsg("relation \"%s\" already exists", sps->name->relname)); - } - - /* Detach the split partition. */ - detachPartitionTable(rel, splitRel, defaultPartOid); - - /* - * Perform a preliminary check to determine whether it's safe to drop the - * split partition before we actually do so later. After merging rows into - * the new partitions via SplitPartitionMoveRows, all old partitions need - * to be dropped. However, since the drop behavior is DROP_RESTRICT and - * the merge process (SplitPartitionMoveRows) can be time-consuming, - * performing an early check on the drop eligibility of old partitions is - * preferable. - */ - object.objectId = splitRelOid; - object.classId = RelationRelationId; - object.objectSubId = 0; - performDeletionCheck(&object, DROP_RESTRICT, PERFORM_DELETION_INTERNAL); - - /* - * If a new partition has the same name as the split partition, then we - * should rename the split partition to reuse its name. - */ - if (isSameName) - { - /* - * We must bump the command counter to make the split partition tuple - * visible for renaming. - */ - CommandCounterIncrement(); - /* Rename partition. */ - sprintf(tmpRelName, "split-%u-%X-tmp", RelationGetRelid(rel), MyProcPid); - RenameRelationInternal(splitRelOid, tmpRelName, true, false); - - /* - * We must bump the command counter to make the split partition tuple - * visible after renaming. - */ - CommandCounterIncrement(); - } - - /* Create new partitions (like a split partition), without indexes. */ - foreach_node(SinglePartitionSpec, sps, cmd->partlist) - { - Relation newPartRel; - - newPartRel = createPartitionTable(wqueue, sps->name, rel, - splitRel->rd_rel->relowner); - newPartRels = lappend(newPartRels, newPartRel); - } - - /* - * Switch to the table owner's userid, so that any index functions are run - * as that user. Also, lockdown security-restricted operations and - * arrange to make GUC variable changes local to this command. - * - * Need to do it after determining the namespace in the - * createPartitionTable() call. - */ - GetUserIdAndSecContext(&save_userid, &save_sec_context); - SetUserIdAndSecContext(splitRel->rd_rel->relowner, - save_sec_context | SECURITY_RESTRICTED_OPERATION); - save_nestlevel = NewGUCNestLevel(); - RestrictSearchPath(); - - /* Copy data from the split partition to the new partitions. */ - SplitPartitionMoveRows(wqueue, rel, splitRel, cmd->partlist, newPartRels); - /* Keep the lock until commit. */ - table_close(splitRel, NoLock); - - /* Attach new partitions to the partitioned table. */ - forboth(listptr, cmd->partlist, listptr2, newPartRels) - { - SinglePartitionSpec *sps = (SinglePartitionSpec *) lfirst(listptr); - Relation newPartRel = (Relation) lfirst(listptr2); - - /* - * wqueue = NULL: verification for each cloned constraint is not - * needed. - */ - attachPartitionTable(NULL, rel, newPartRel, sps->bound); - /* Keep the lock until commit. */ - table_close(newPartRel, NoLock); - } - - /* Drop the split partition. */ - object.classId = RelationRelationId; - object.objectId = splitRelOid; - object.objectSubId = 0; - /* Probably DROP_CASCADE is not needed. */ - performDeletion(&object, DROP_RESTRICT, 0); - - /* Roll back any GUC changes executed by index functions. */ - AtEOXact_GUC(false, save_nestlevel); - - /* Restore the userid and security context. */ - SetUserIdAndSecContext(save_userid, save_sec_context); -} diff --git a/src/backend/commands/tablecmds_partition.c b/src/backend/commands/tablecmds_partition.c new file mode 100644 index 00000000000..1e8e7f5b669 --- /dev/null +++ b/src/backend/commands/tablecmds_partition.c @@ -0,0 +1,4627 @@ +/*------------------------------------------------------------------------- + * + * tablecmds_partition.c + * TODO + * + * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/commands/tablecmds_partition.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/genam.h" +#include "access/heapam.h" +#include "access/htup_details.h" +#include "access/toast_compression.h" +#include "utils/lsyscache.h" +#include "access/relation.h" +#include "access/skey.h" +#include "access/stratnum.h" +#include "access/table.h" +#include "catalog/heap.h" +#include "catalog/index.h" +#include "catalog/indexing.h" +#include "catalog/namespace.h" +#include "catalog/partition.h" +#include "catalog/pg_am.h" +#include "catalog/pg_attrdef.h" +#include "catalog/pg_constraint.h" +#include "catalog/pg_inherits.h" +#include "catalog/pg_trigger.h" +#include "commands/defrem.h" +#include "commands/tablecmds.h" +#include "commands/tablecmds_internal.h" +#include "commands/tablecmds_partition.h" +#include "commands/trigger.h" +#include "executor/executor.h" +#include "miscadmin.h" +#include "nodes/makefuncs.h" +#include "nodes/nodeFuncs.h" +#include "optimizer/optimizer.h" +#include "parser/parse_collate.h" +#include "parser/parse_expr.h" +#include "parser/parse_node.h" +#include "parser/parse_relation.h" +#include "parser/parse_utilcmd.h" +#include "partitioning/partbounds.h" +#include "partitioning/partdesc.h" +#include "rewrite/rewriteHandler.h" +#include "rewrite/rewriteManip.h" +#include "storage/lmgr.h" +#include "tcop/utility.h" +#include "utils/builtins.h" +#include "utils/fmgroids.h" +#include "utils/inval.h" +#include "utils/memutils.h" +#include "utils/partcache.h" +#include "utils/rel.h" +#include "utils/syscache.h" + +static void CloneFkReferenced(Relation parentRel, Relation partitionRel); +static void CloneFkReferencing(List **wqueue, Relation parentRel, + Relation partRel); +static void AttachPartitionForeignKey(List **wqueue, Relation partition, + Oid partConstrOid, Oid parentConstrOid, + Oid parentInsTrigger, Oid parentUpdTrigger, + Relation trigrel); +static void RemoveInheritedConstraint(Relation conrel, Relation trigrel, + Oid conoid, Oid conrelid); +static void GetForeignKeyActionTriggers(Relation trigrel, + Oid conoid, Oid confrelid, Oid conrelid, + Oid *deleteTriggerOid, + Oid *updateTriggerOid); +static void GetForeignKeyCheckTriggers(Relation trigrel, + Oid conoid, Oid confrelid, Oid conrelid, + Oid *insertTriggerOid, + Oid *updateTriggerOid); +static void AttachPartitionEnsureIndexes(List **wqueue, Relation rel, Relation attachrel); +static void QueuePartitionConstraintValidation(List **wqueue, Relation scanrel, + List *partConstraint, + bool validate_default); +static void DropClonedTriggersFromPartition(Oid partitionId); +static void DetachPartitionFinalize(Relation rel, Relation partRel, + bool concurrent, Oid defaultPartOid); +static void validatePartitionedIndex(Relation partedIdx, Relation partedTbl); +static void refuseDupeIndexAttach(Relation parentIdx, Relation partIdx, + Relation partitionTbl); +static void verifyPartitionIndexNotNull(IndexInfo *iinfo, Relation partition); +static List *GetParentedForeignKeyRefs(Relation partition); +static void ATDetachCheckNoForeignKeyRefs(Relation partition); + +/* + * Obtain list of partitions of the given table, locking them all at the given + * lockmode and ensuring that they all pass CheckAlterTableIsSafe. + * + * This function is a no-op if the given relation is not a partitioned table; + * in particular, nothing is done if it's a legacy inheritance parent. + */ +void +ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode) +{ + if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + { + List *inh; + ListCell *cell; + + inh = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL); + /* first element is the parent rel; must ignore it */ + for_each_from(cell, inh, 1) + { + Relation childrel; + + /* find_all_inheritors already got lock */ + childrel = table_open(lfirst_oid(cell), NoLock); + CheckAlterTableIsSafe(childrel); + table_close(childrel, NoLock); + } + list_free(inh); + } +} + +/* + * CloneForeignKeyConstraints + * Clone foreign keys from a partitioned table to a newly acquired + * partition. + * + * partitionRel is a partition of parentRel, so we can be certain that it has + * the same columns with the same datatypes. The columns may be in different + * order, though. + * + * wqueue must be passed to set up phase 3 constraint checking, unless the + * referencing-side partition is known to be empty (such as in CREATE TABLE / + * PARTITION OF). + */ +void +CloneForeignKeyConstraints(List **wqueue, Relation parentRel, + Relation partitionRel) +{ + /* This only works for declarative partitioning */ + Assert(parentRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE); + + /* + * First, clone constraints where the parent is on the referencing side. + */ + CloneFkReferencing(wqueue, parentRel, partitionRel); + + /* + * Clone constraints for which the parent is on the referenced side. + */ + CloneFkReferenced(parentRel, partitionRel); +} + +/* + * CloneFkReferenced + * Subroutine for CloneForeignKeyConstraints + * + * Find all the FKs that have the parent relation on the referenced side; + * clone those constraints to the given partition. This is to be called + * when the partition is being created or attached. + * + * This recurses to partitions, if the relation being attached is partitioned. + * Recursion is done by calling addFkRecurseReferenced. + */ +static void +CloneFkReferenced(Relation parentRel, Relation partitionRel) +{ + Relation pg_constraint; + AttrMap *attmap; + ListCell *cell; + SysScanDesc scan; + ScanKeyData key[2]; + HeapTuple tuple; + List *clone = NIL; + Relation trigrel; + + /* + * Search for any constraints where this partition's parent is in the + * referenced side. However, we must not clone any constraint whose + * parent constraint is also going to be cloned, to avoid duplicates. So + * do it in two steps: first construct the list of constraints to clone, + * then go over that list cloning those whose parents are not in the list. + * (We must not rely on the parent being seen first, since the catalog + * scan could return children first.) + */ + pg_constraint = table_open(ConstraintRelationId, RowShareLock); + ScanKeyInit(&key[0], + Anum_pg_constraint_confrelid, BTEqualStrategyNumber, + F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parentRel))); + ScanKeyInit(&key[1], + Anum_pg_constraint_contype, BTEqualStrategyNumber, + F_CHAREQ, CharGetDatum(CONSTRAINT_FOREIGN)); + /* This is a seqscan, as we don't have a usable index ... */ + scan = systable_beginscan(pg_constraint, InvalidOid, true, + NULL, 2, key); + while ((tuple = systable_getnext(scan)) != NULL) + { + Form_pg_constraint constrForm = (Form_pg_constraint) GETSTRUCT(tuple); + + clone = lappend_oid(clone, constrForm->oid); + } + systable_endscan(scan); + table_close(pg_constraint, RowShareLock); + + /* + * Triggers of the foreign keys will be manipulated a bunch of times in + * the loop below. To avoid repeatedly opening/closing the trigger + * catalog relation, we open it here and pass it to the subroutines called + * below. + */ + trigrel = table_open(TriggerRelationId, RowExclusiveLock); + + attmap = build_attrmap_by_name(RelationGetDescr(partitionRel), + RelationGetDescr(parentRel), + false); + foreach(cell, clone) + { + Oid constrOid = lfirst_oid(cell); + Form_pg_constraint constrForm; + Relation fkRel; + Oid indexOid; + Oid partIndexId; + int numfks; + AttrNumber conkey[INDEX_MAX_KEYS]; + AttrNumber mapped_confkey[INDEX_MAX_KEYS]; + AttrNumber confkey[INDEX_MAX_KEYS]; + Oid conpfeqop[INDEX_MAX_KEYS]; + Oid conppeqop[INDEX_MAX_KEYS]; + Oid conffeqop[INDEX_MAX_KEYS]; + int numfkdelsetcols; + AttrNumber confdelsetcols[INDEX_MAX_KEYS]; + Constraint *fkconstraint; + ObjectAddress address; + Oid deleteTriggerOid = InvalidOid, + updateTriggerOid = InvalidOid; + + tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for constraint %u", constrOid); + constrForm = (Form_pg_constraint) GETSTRUCT(tuple); + + /* + * As explained above: don't try to clone a constraint for which we're + * going to clone the parent. + */ + if (list_member_oid(clone, constrForm->conparentid)) + { + ReleaseSysCache(tuple); + continue; + } + + /* We need the same lock level that CreateTrigger will acquire */ + fkRel = table_open(constrForm->conrelid, ShareRowExclusiveLock); + + indexOid = constrForm->conindid; + DeconstructFkConstraintRow(tuple, + &numfks, + conkey, + confkey, + conpfeqop, + conppeqop, + conffeqop, + &numfkdelsetcols, + confdelsetcols); + + for (int i = 0; i < numfks; i++) + mapped_confkey[i] = attmap->attnums[confkey[i] - 1]; + + fkconstraint = makeNode(Constraint); + fkconstraint->contype = CONSTRAINT_FOREIGN; + fkconstraint->conname = NameStr(constrForm->conname); + fkconstraint->deferrable = constrForm->condeferrable; + fkconstraint->initdeferred = constrForm->condeferred; + fkconstraint->location = -1; + fkconstraint->pktable = NULL; + /* ->fk_attrs determined below */ + fkconstraint->pk_attrs = NIL; + fkconstraint->fk_matchtype = constrForm->confmatchtype; + fkconstraint->fk_upd_action = constrForm->confupdtype; + fkconstraint->fk_del_action = constrForm->confdeltype; + fkconstraint->fk_del_set_cols = NIL; + fkconstraint->old_conpfeqop = NIL; + fkconstraint->old_pktable_oid = InvalidOid; + fkconstraint->is_enforced = constrForm->conenforced; + fkconstraint->skip_validation = false; + fkconstraint->initially_valid = constrForm->convalidated; + + /* set up colnames that are used to generate the constraint name */ + for (int i = 0; i < numfks; i++) + { + Form_pg_attribute att; + + att = TupleDescAttr(RelationGetDescr(fkRel), + conkey[i] - 1); + fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs, + makeString(NameStr(att->attname))); + } + + /* + * Add the new foreign key constraint pointing to the new partition. + * Because this new partition appears in the referenced side of the + * constraint, we don't need to set up for Phase 3 check. + */ + partIndexId = index_get_partition(partitionRel, indexOid); + if (!OidIsValid(partIndexId)) + elog(ERROR, "index for %u not found in partition %s", + indexOid, RelationGetRelationName(partitionRel)); + + /* + * Get the "action" triggers belonging to the constraint to pass as + * parent OIDs for similar triggers that will be created on the + * partition in addFkRecurseReferenced(). + */ + if (constrForm->conenforced) + GetForeignKeyActionTriggers(trigrel, constrOid, + constrForm->confrelid, constrForm->conrelid, + &deleteTriggerOid, &updateTriggerOid); + + /* Add this constraint ... */ + address = addFkConstraint(addFkReferencedSide, + fkconstraint->conname, fkconstraint, fkRel, + partitionRel, partIndexId, constrOid, + numfks, mapped_confkey, + conkey, conpfeqop, conppeqop, conffeqop, + numfkdelsetcols, confdelsetcols, false, + constrForm->conperiod); + /* ... and recurse */ + addFkRecurseReferenced(fkconstraint, + fkRel, + partitionRel, + partIndexId, + address.objectId, + numfks, + mapped_confkey, + conkey, + conpfeqop, + conppeqop, + conffeqop, + numfkdelsetcols, + confdelsetcols, + true, + deleteTriggerOid, + updateTriggerOid, + constrForm->conperiod); + + table_close(fkRel, NoLock); + ReleaseSysCache(tuple); + } + + table_close(trigrel, RowExclusiveLock); +} + +/* + * CloneFkReferencing + * Subroutine for CloneForeignKeyConstraints + * + * For each FK constraint of the parent relation in the given list, find an + * equivalent constraint in its partition relation that can be reparented; + * if one cannot be found, create a new constraint in the partition as its + * child. + * + * If wqueue is given, it is used to set up phase-3 verification for each + * cloned constraint; omit it if such verification is not needed + * (example: the partition is being created anew). + */ +static void +CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel) +{ + AttrMap *attmap; + List *partFKs; + List *clone = NIL; + ListCell *cell; + Relation trigrel; + + /* obtain a list of constraints that we need to clone */ + foreach(cell, RelationGetFKeyList(parentRel)) + { + ForeignKeyCacheInfo *fk = lfirst(cell); + + /* + * Refuse to attach a table as partition that this partitioned table + * already has a foreign key to. This isn't useful schema, which is + * proven by the fact that there have been no user complaints that + * it's already impossible to achieve this in the opposite direction, + * i.e., creating a foreign key that references a partition. This + * restriction allows us to dodge some complexities around + * pg_constraint and pg_trigger row creations that would be needed + * during ATTACH/DETACH for this kind of relationship. + */ + if (fk->confrelid == RelationGetRelid(partRel)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot attach table \"%s\" as a partition because it is referenced by foreign key \"%s\"", + RelationGetRelationName(partRel), + get_constraint_name(fk->conoid)))); + + clone = lappend_oid(clone, fk->conoid); + } + + /* + * Silently do nothing if there's nothing to do. In particular, this + * avoids throwing a spurious error for foreign tables. + */ + if (clone == NIL) + return; + + if (partRel->rd_rel->relkind == RELKIND_FOREIGN_TABLE) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("foreign key constraints are not supported on foreign tables"))); + + /* + * Triggers of the foreign keys will be manipulated a bunch of times in + * the loop below. To avoid repeatedly opening/closing the trigger + * catalog relation, we open it here and pass it to the subroutines called + * below. + */ + trigrel = table_open(TriggerRelationId, RowExclusiveLock); + + /* + * The constraint key may differ, if the columns in the partition are + * different. This map is used to convert them. + */ + attmap = build_attrmap_by_name(RelationGetDescr(partRel), + RelationGetDescr(parentRel), + false); + + partFKs = copyObject(RelationGetFKeyList(partRel)); + + foreach(cell, clone) + { + Oid parentConstrOid = lfirst_oid(cell); + Form_pg_constraint constrForm; + Relation pkrel; + HeapTuple tuple; + int numfks; + AttrNumber conkey[INDEX_MAX_KEYS]; + AttrNumber mapped_conkey[INDEX_MAX_KEYS]; + AttrNumber confkey[INDEX_MAX_KEYS]; + Oid conpfeqop[INDEX_MAX_KEYS]; + Oid conppeqop[INDEX_MAX_KEYS]; + Oid conffeqop[INDEX_MAX_KEYS]; + int numfkdelsetcols; + AttrNumber confdelsetcols[INDEX_MAX_KEYS]; + Constraint *fkconstraint; + bool attached; + Oid indexOid; + ObjectAddress address; + ListCell *lc; + Oid insertTriggerOid = InvalidOid, + updateTriggerOid = InvalidOid; + bool with_period; + + tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(parentConstrOid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for constraint %u", + parentConstrOid); + constrForm = (Form_pg_constraint) GETSTRUCT(tuple); + + /* Don't clone constraints whose parents are being cloned */ + if (list_member_oid(clone, constrForm->conparentid)) + { + ReleaseSysCache(tuple); + continue; + } + + /* + * Need to prevent concurrent deletions. If pkrel is a partitioned + * relation, that means to lock all partitions. + */ + pkrel = table_open(constrForm->confrelid, ShareRowExclusiveLock); + if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + (void) find_all_inheritors(RelationGetRelid(pkrel), + ShareRowExclusiveLock, NULL); + + DeconstructFkConstraintRow(tuple, &numfks, conkey, confkey, + conpfeqop, conppeqop, conffeqop, + &numfkdelsetcols, confdelsetcols); + for (int i = 0; i < numfks; i++) + mapped_conkey[i] = attmap->attnums[conkey[i] - 1]; + + /* + * Get the "check" triggers belonging to the constraint, if it is + * ENFORCED, to pass as parent OIDs for similar triggers that will be + * created on the partition in addFkRecurseReferencing(). They are + * also passed to tryAttachPartitionForeignKey() below to simply + * assign as parents to the partition's existing "check" triggers, + * that is, if the corresponding constraints is deemed attachable to + * the parent constraint. + */ + if (constrForm->conenforced) + GetForeignKeyCheckTriggers(trigrel, constrForm->oid, + constrForm->confrelid, constrForm->conrelid, + &insertTriggerOid, &updateTriggerOid); + + /* + * Before creating a new constraint, see whether any existing FKs are + * fit for the purpose. If one is, attach the parent constraint to + * it, and don't clone anything. This way we avoid the expensive + * verification step and don't end up with a duplicate FK, and we + * don't need to recurse to partitions for this constraint. + */ + attached = false; + foreach(lc, partFKs) + { + ForeignKeyCacheInfo *fk = lfirst_node(ForeignKeyCacheInfo, lc); + + if (tryAttachPartitionForeignKey(wqueue, + fk, + partRel, + parentConstrOid, + numfks, + mapped_conkey, + confkey, + conpfeqop, + insertTriggerOid, + updateTriggerOid, + trigrel)) + { + attached = true; + table_close(pkrel, NoLock); + break; + } + } + if (attached) + { + ReleaseSysCache(tuple); + continue; + } + + /* No dice. Set up to create our own constraint */ + fkconstraint = makeNode(Constraint); + fkconstraint->contype = CONSTRAINT_FOREIGN; + /* ->conname determined below */ + fkconstraint->deferrable = constrForm->condeferrable; + fkconstraint->initdeferred = constrForm->condeferred; + fkconstraint->location = -1; + fkconstraint->pktable = NULL; + /* ->fk_attrs determined below */ + fkconstraint->pk_attrs = NIL; + fkconstraint->fk_matchtype = constrForm->confmatchtype; + fkconstraint->fk_upd_action = constrForm->confupdtype; + fkconstraint->fk_del_action = constrForm->confdeltype; + fkconstraint->fk_del_set_cols = NIL; + fkconstraint->old_conpfeqop = NIL; + fkconstraint->old_pktable_oid = InvalidOid; + fkconstraint->is_enforced = constrForm->conenforced; + fkconstraint->skip_validation = false; + fkconstraint->initially_valid = constrForm->convalidated; + for (int i = 0; i < numfks; i++) + { + Form_pg_attribute att; + + att = TupleDescAttr(RelationGetDescr(partRel), + mapped_conkey[i] - 1); + fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs, + makeString(NameStr(att->attname))); + } + + indexOid = constrForm->conindid; + with_period = constrForm->conperiod; + + /* Create the pg_constraint entry at this level */ + address = addFkConstraint(addFkReferencingSide, + NameStr(constrForm->conname), fkconstraint, + partRel, pkrel, indexOid, parentConstrOid, + numfks, confkey, + mapped_conkey, conpfeqop, + conppeqop, conffeqop, + numfkdelsetcols, confdelsetcols, + false, with_period); + + /* Done with the cloned constraint's tuple */ + ReleaseSysCache(tuple); + + /* Create the check triggers, and recurse to partitions, if any */ + addFkRecurseReferencing(wqueue, + fkconstraint, + partRel, + pkrel, + indexOid, + address.objectId, + numfks, + confkey, + mapped_conkey, + conpfeqop, + conppeqop, + conffeqop, + numfkdelsetcols, + confdelsetcols, + false, /* no old check exists */ + AccessExclusiveLock, + insertTriggerOid, + updateTriggerOid, + with_period); + table_close(pkrel, NoLock); + } + + table_close(trigrel, RowExclusiveLock); +} + +/* + * When the parent of a partition receives [the referencing side of] a foreign + * key, we must propagate that foreign key to the partition. However, the + * partition might already have an equivalent foreign key; this routine + * compares the given ForeignKeyCacheInfo (in the partition) to the FK defined + * by the other parameters. If they are equivalent, create the link between + * the two constraints and return true. + * + * If the given FK does not match the one defined by rest of the params, + * return false. + */ +bool +tryAttachPartitionForeignKey(List **wqueue, + ForeignKeyCacheInfo *fk, + Relation partition, + Oid parentConstrOid, + int numfks, + AttrNumber *mapped_conkey, + AttrNumber *confkey, + Oid *conpfeqop, + Oid parentInsTrigger, + Oid parentUpdTrigger, + Relation trigrel) +{ + HeapTuple parentConstrTup; + Form_pg_constraint parentConstr; + HeapTuple partcontup; + Form_pg_constraint partConstr; + + parentConstrTup = SearchSysCache1(CONSTROID, + ObjectIdGetDatum(parentConstrOid)); + if (!HeapTupleIsValid(parentConstrTup)) + elog(ERROR, "cache lookup failed for constraint %u", parentConstrOid); + parentConstr = (Form_pg_constraint) GETSTRUCT(parentConstrTup); + + /* + * Do some quick & easy initial checks. If any of these fail, we cannot + * use this constraint. + */ + if (fk->confrelid != parentConstr->confrelid || fk->nkeys != numfks) + { + ReleaseSysCache(parentConstrTup); + return false; + } + for (int i = 0; i < numfks; i++) + { + if (fk->conkey[i] != mapped_conkey[i] || + fk->confkey[i] != confkey[i] || + fk->conpfeqop[i] != conpfeqop[i]) + { + ReleaseSysCache(parentConstrTup); + return false; + } + } + + /* Looks good so far; perform more extensive checks. */ + partcontup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(fk->conoid)); + if (!HeapTupleIsValid(partcontup)) + elog(ERROR, "cache lookup failed for constraint %u", fk->conoid); + partConstr = (Form_pg_constraint) GETSTRUCT(partcontup); + + /* + * An error should be raised if the constraint enforceability is + * different. Returning false without raising an error, as we do for other + * attributes, could lead to a duplicate constraint with the same + * enforceability as the parent. While this may be acceptable, it may not + * be ideal. Therefore, it's better to raise an error and allow the user + * to correct the enforceability before proceeding. + */ + if (partConstr->conenforced != parentConstr->conenforced) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("constraint \"%s\" enforceability conflicts with constraint \"%s\" on relation \"%s\"", + NameStr(parentConstr->conname), + NameStr(partConstr->conname), + RelationGetRelationName(partition)))); + + if (OidIsValid(partConstr->conparentid) || + partConstr->condeferrable != parentConstr->condeferrable || + partConstr->condeferred != parentConstr->condeferred || + partConstr->confupdtype != parentConstr->confupdtype || + partConstr->confdeltype != parentConstr->confdeltype || + partConstr->confmatchtype != parentConstr->confmatchtype) + { + ReleaseSysCache(parentConstrTup); + ReleaseSysCache(partcontup); + return false; + } + + ReleaseSysCache(parentConstrTup); + ReleaseSysCache(partcontup); + + /* Looks good! Attach this constraint. */ + AttachPartitionForeignKey(wqueue, partition, fk->conoid, + parentConstrOid, parentInsTrigger, + parentUpdTrigger, trigrel); + + return true; +} + +/* + * AttachPartitionForeignKey + * + * The subroutine for tryAttachPartitionForeignKey performs the final tasks of + * attaching the constraint, removing redundant triggers and entries from + * pg_constraint, and setting the constraint's parent. + */ +static void +AttachPartitionForeignKey(List **wqueue, + Relation partition, + Oid partConstrOid, + Oid parentConstrOid, + Oid parentInsTrigger, + Oid parentUpdTrigger, + Relation trigrel) +{ + HeapTuple parentConstrTup; + Form_pg_constraint parentConstr; + HeapTuple partcontup; + Form_pg_constraint partConstr; + bool queueValidation; + Oid partConstrFrelid; + Oid partConstrRelid; + bool parentConstrIsEnforced; + + /* Fetch the parent constraint tuple */ + parentConstrTup = SearchSysCache1(CONSTROID, + ObjectIdGetDatum(parentConstrOid)); + if (!HeapTupleIsValid(parentConstrTup)) + elog(ERROR, "cache lookup failed for constraint %u", parentConstrOid); + parentConstr = (Form_pg_constraint) GETSTRUCT(parentConstrTup); + parentConstrIsEnforced = parentConstr->conenforced; + + /* Fetch the child constraint tuple */ + partcontup = SearchSysCache1(CONSTROID, + ObjectIdGetDatum(partConstrOid)); + if (!HeapTupleIsValid(partcontup)) + elog(ERROR, "cache lookup failed for constraint %u", partConstrOid); + partConstr = (Form_pg_constraint) GETSTRUCT(partcontup); + partConstrFrelid = partConstr->confrelid; + partConstrRelid = partConstr->conrelid; + + /* + * If the referenced table is partitioned, then the partition we're + * attaching now has extra pg_constraint rows and action triggers that are + * no longer needed. Remove those. + */ + if (get_rel_relkind(partConstrFrelid) == RELKIND_PARTITIONED_TABLE) + { + Relation pg_constraint = table_open(ConstraintRelationId, RowShareLock); + + RemoveInheritedConstraint(pg_constraint, trigrel, partConstrOid, + partConstrRelid); + + table_close(pg_constraint, RowShareLock); + } + + /* + * Will we need to validate this constraint? A valid parent constraint + * implies that all child constraints have been validated, so if this one + * isn't, we must trigger phase 3 validation. + */ + queueValidation = parentConstr->convalidated && !partConstr->convalidated; + + ReleaseSysCache(partcontup); + ReleaseSysCache(parentConstrTup); + + /* + * The action triggers in the new partition become redundant -- the parent + * table already has equivalent ones, and those will be able to reach the + * partition. Remove the ones in the partition. We identify them because + * they have our constraint OID, as well as being on the referenced rel. + */ + DropForeignKeyConstraintTriggers(trigrel, partConstrOid, partConstrFrelid, + partConstrRelid); + + ConstraintSetParentConstraint(partConstrOid, parentConstrOid, + RelationGetRelid(partition)); + + /* + * Like the constraint, attach partition's "check" triggers to the + * corresponding parent triggers if the constraint is ENFORCED. NOT + * ENFORCED constraints do not have these triggers. + */ + if (parentConstrIsEnforced) + { + Oid insertTriggerOid, + updateTriggerOid; + + GetForeignKeyCheckTriggers(trigrel, + partConstrOid, partConstrFrelid, partConstrRelid, + &insertTriggerOid, &updateTriggerOid); + Assert(OidIsValid(insertTriggerOid) && OidIsValid(parentInsTrigger)); + TriggerSetParentTrigger(trigrel, insertTriggerOid, parentInsTrigger, + RelationGetRelid(partition)); + Assert(OidIsValid(updateTriggerOid) && OidIsValid(parentUpdTrigger)); + TriggerSetParentTrigger(trigrel, updateTriggerOid, parentUpdTrigger, + RelationGetRelid(partition)); + } + + /* + * We updated this pg_constraint row above to set its parent; validating + * it will cause its convalidated flag to change, so we need CCI here. In + * addition, we need it unconditionally for the rare case where the parent + * table has *two* identical constraints; when reaching this function for + * the second one, we must have made our changes visible, otherwise we + * would try to attach both to this one. + */ + CommandCounterIncrement(); + + /* If validation is needed, put it in the queue now. */ + if (queueValidation) + { + Relation conrel; + Oid confrelid; + + conrel = table_open(ConstraintRelationId, RowExclusiveLock); + + partcontup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(partConstrOid)); + if (!HeapTupleIsValid(partcontup)) + elog(ERROR, "cache lookup failed for constraint %u", partConstrOid); + + confrelid = ((Form_pg_constraint) GETSTRUCT(partcontup))->confrelid; + + /* Use the same lock as for AT_ValidateConstraint */ + QueueFKConstraintValidation(wqueue, conrel, partition, confrelid, + partcontup, ShareUpdateExclusiveLock); + ReleaseSysCache(partcontup); + table_close(conrel, RowExclusiveLock); + } +} + +/* + * RemoveInheritedConstraint + * + * Removes the constraint and its associated trigger from the specified + * relation, which inherited the given constraint. + */ +static void +RemoveInheritedConstraint(Relation conrel, Relation trigrel, Oid conoid, + Oid conrelid) +{ + ObjectAddresses *objs; + HeapTuple consttup; + ScanKeyData key; + SysScanDesc scan; + HeapTuple trigtup; + + ScanKeyInit(&key, + Anum_pg_constraint_conrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(conrelid)); + + scan = systable_beginscan(conrel, + ConstraintRelidTypidNameIndexId, + true, NULL, 1, &key); + objs = new_object_addresses(); + while ((consttup = systable_getnext(scan)) != NULL) + { + Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(consttup); + + if (conform->conparentid != conoid) + continue; + else + { + ObjectAddress addr; + SysScanDesc scan2; + ScanKeyData key2; + int n PG_USED_FOR_ASSERTS_ONLY; + + ObjectAddressSet(addr, ConstraintRelationId, conform->oid); + add_exact_object_address(&addr, objs); + + /* + * First we must delete the dependency record that binds the + * constraint records together. + */ + n = deleteDependencyRecordsForSpecific(ConstraintRelationId, + conform->oid, + DEPENDENCY_INTERNAL, + ConstraintRelationId, + conoid); + Assert(n == 1); /* actually only one is expected */ + + /* + * Now search for the triggers for this constraint and set them up + * for deletion too + */ + ScanKeyInit(&key2, + Anum_pg_trigger_tgconstraint, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(conform->oid)); + scan2 = systable_beginscan(trigrel, TriggerConstraintIndexId, + true, NULL, 1, &key2); + while ((trigtup = systable_getnext(scan2)) != NULL) + { + ObjectAddressSet(addr, TriggerRelationId, + ((Form_pg_trigger) GETSTRUCT(trigtup))->oid); + add_exact_object_address(&addr, objs); + } + systable_endscan(scan2); + } + } + /* make the dependency deletions visible */ + CommandCounterIncrement(); + performMultipleDeletions(objs, DROP_RESTRICT, + PERFORM_DELETION_INTERNAL); + systable_endscan(scan); +} + +/* + * GetForeignKeyActionTriggers + * Returns delete and update "action" triggers of the given relation + * belonging to the given constraint + */ +static void +GetForeignKeyActionTriggers(Relation trigrel, + Oid conoid, Oid confrelid, Oid conrelid, + Oid *deleteTriggerOid, + Oid *updateTriggerOid) +{ + ScanKeyData key; + SysScanDesc scan; + HeapTuple trigtup; + + *deleteTriggerOid = *updateTriggerOid = InvalidOid; + ScanKeyInit(&key, + Anum_pg_trigger_tgconstraint, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(conoid)); + + scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true, + NULL, 1, &key); + while ((trigtup = systable_getnext(scan)) != NULL) + { + Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup); + + if (trgform->tgconstrrelid != conrelid) + continue; + if (trgform->tgrelid != confrelid) + continue; + /* Only ever look at "action" triggers on the PK side. */ + if (RI_FKey_trigger_type(trgform->tgfoid) != RI_TRIGGER_PK) + continue; + if (TRIGGER_FOR_DELETE(trgform->tgtype)) + { + Assert(*deleteTriggerOid == InvalidOid); + *deleteTriggerOid = trgform->oid; + } + else if (TRIGGER_FOR_UPDATE(trgform->tgtype)) + { + Assert(*updateTriggerOid == InvalidOid); + *updateTriggerOid = trgform->oid; + } +#ifndef USE_ASSERT_CHECKING + /* In an assert-enabled build, continue looking to find duplicates */ + if (OidIsValid(*deleteTriggerOid) && OidIsValid(*updateTriggerOid)) + break; +#endif + } + + if (!OidIsValid(*deleteTriggerOid)) + elog(ERROR, "could not find ON DELETE action trigger of foreign key constraint %u", + conoid); + if (!OidIsValid(*updateTriggerOid)) + elog(ERROR, "could not find ON UPDATE action trigger of foreign key constraint %u", + conoid); + + systable_endscan(scan); +} + +/* + * GetForeignKeyCheckTriggers + * Returns insert and update "check" triggers of the given relation + * belonging to the given constraint + */ +static void +GetForeignKeyCheckTriggers(Relation trigrel, + Oid conoid, Oid confrelid, Oid conrelid, + Oid *insertTriggerOid, + Oid *updateTriggerOid) +{ + ScanKeyData key; + SysScanDesc scan; + HeapTuple trigtup; + + *insertTriggerOid = *updateTriggerOid = InvalidOid; + ScanKeyInit(&key, + Anum_pg_trigger_tgconstraint, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(conoid)); + + scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true, + NULL, 1, &key); + while ((trigtup = systable_getnext(scan)) != NULL) + { + Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup); + + if (trgform->tgconstrrelid != confrelid) + continue; + if (trgform->tgrelid != conrelid) + continue; + /* Only ever look at "check" triggers on the FK side. */ + if (RI_FKey_trigger_type(trgform->tgfoid) != RI_TRIGGER_FK) + continue; + if (TRIGGER_FOR_INSERT(trgform->tgtype)) + { + Assert(*insertTriggerOid == InvalidOid); + *insertTriggerOid = trgform->oid; + } + else if (TRIGGER_FOR_UPDATE(trgform->tgtype)) + { + Assert(*updateTriggerOid == InvalidOid); + *updateTriggerOid = trgform->oid; + } +#ifndef USE_ASSERT_CHECKING + /* In an assert-enabled build, continue looking to find duplicates. */ + if (OidIsValid(*insertTriggerOid) && OidIsValid(*updateTriggerOid)) + break; +#endif + } + + if (!OidIsValid(*insertTriggerOid)) + elog(ERROR, "could not find ON INSERT check triggers of foreign key constraint %u", + conoid); + if (!OidIsValid(*updateTriggerOid)) + elog(ERROR, "could not find ON UPDATE check triggers of foreign key constraint %u", + conoid); + + systable_endscan(scan); +} + +/* + * MarkInheritDetached + * + * Set inhdetachpending for a partition, for ATExecDetachPartition + * in concurrent mode. While at it, verify that no other partition is + * already pending detach. + */ +static void +MarkInheritDetached(Relation child_rel, Relation parent_rel) +{ + Relation catalogRelation; + SysScanDesc scan; + ScanKeyData key; + HeapTuple inheritsTuple; + bool found = false; + + Assert(parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE); + + /* + * Find pg_inherits entries by inhparent. (We need to scan them all in + * order to verify that no other partition is pending detach.) + */ + catalogRelation = table_open(InheritsRelationId, RowExclusiveLock); + ScanKeyInit(&key, + Anum_pg_inherits_inhparent, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelationGetRelid(parent_rel))); + scan = systable_beginscan(catalogRelation, InheritsParentIndexId, + true, NULL, 1, &key); + + while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan))) + { + Form_pg_inherits inhForm; + + inhForm = (Form_pg_inherits) GETSTRUCT(inheritsTuple); + if (inhForm->inhdetachpending) + ereport(ERROR, + errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("partition \"%s\" already pending detach in partitioned table \"%s.%s\"", + get_rel_name(inhForm->inhrelid), + get_namespace_name(parent_rel->rd_rel->relnamespace), + RelationGetRelationName(parent_rel)), + errhint("Use ALTER TABLE ... DETACH PARTITION ... FINALIZE to complete the pending detach operation.")); + + if (inhForm->inhrelid == RelationGetRelid(child_rel)) + { + HeapTuple newtup; + + newtup = heap_copytuple(inheritsTuple); + ((Form_pg_inherits) GETSTRUCT(newtup))->inhdetachpending = true; + + CatalogTupleUpdate(catalogRelation, + &inheritsTuple->t_self, + newtup); + found = true; + heap_freetuple(newtup); + /* keep looking, to ensure we catch others pending detach */ + } + } + + /* Done */ + systable_endscan(scan); + table_close(catalogRelation, RowExclusiveLock); + + if (!found) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_TABLE), + errmsg("relation \"%s\" is not a partition of relation \"%s\"", + RelationGetRelationName(child_rel), + RelationGetRelationName(parent_rel)))); +} + +/* + * Transform any expressions present in the partition key + * + * Returns a transformed PartitionSpec. + */ +PartitionSpec * +transformPartitionSpec(Relation rel, PartitionSpec *partspec) +{ + PartitionSpec *newspec; + ParseState *pstate; + ParseNamespaceItem *nsitem; + ListCell *l; + + newspec = makeNode(PartitionSpec); + + newspec->strategy = partspec->strategy; + newspec->partParams = NIL; + newspec->location = partspec->location; + + /* Check valid number of columns for strategy */ + if (partspec->strategy == PARTITION_STRATEGY_LIST && + list_length(partspec->partParams) != 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("cannot use \"list\" partition strategy with more than one column"))); + + /* + * Create a dummy ParseState and insert the target relation as its sole + * rangetable entry. We need a ParseState for transformExpr. + */ + pstate = make_parsestate(NULL); + nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock, + NULL, false, true); + addNSItemToQuery(pstate, nsitem, true, true, true); + + /* take care of any partition expressions */ + foreach(l, partspec->partParams) + { + PartitionElem *pelem = lfirst_node(PartitionElem, l); + + if (pelem->expr) + { + /* Copy, to avoid scribbling on the input */ + pelem = copyObject(pelem); + + /* Now do parse transformation of the expression */ + pelem->expr = transformExpr(pstate, pelem->expr, + EXPR_KIND_PARTITION_EXPRESSION); + + /* we have to fix its collations too */ + assign_expr_collations(pstate, pelem->expr); + } + + newspec->partParams = lappend(newspec->partParams, pelem); + } + + return newspec; +} + +/* + * Compute per-partition-column information from a list of PartitionElems. + * Expressions in the PartitionElems must be parse-analyzed already. + */ +void +ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs, + List **partexprs, Oid *partopclass, Oid *partcollation, + PartitionStrategy strategy) +{ + int attn; + ListCell *lc; + Oid am_oid; + + attn = 0; + foreach(lc, partParams) + { + PartitionElem *pelem = lfirst_node(PartitionElem, lc); + Oid atttype; + Oid attcollation; + + if (pelem->name != NULL) + { + /* Simple attribute reference */ + HeapTuple atttuple; + Form_pg_attribute attform; + + atttuple = SearchSysCacheAttName(RelationGetRelid(rel), + pelem->name); + if (!HeapTupleIsValid(atttuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" named in partition key does not exist", + pelem->name), + parser_errposition(pstate, pelem->location))); + attform = (Form_pg_attribute) GETSTRUCT(atttuple); + + if (attform->attnum <= 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("cannot use system column \"%s\" in partition key", + pelem->name), + parser_errposition(pstate, pelem->location))); + + /* + * Stored generated columns cannot work: They are computed after + * BEFORE triggers, but partition routing is done before all + * triggers. Maybe virtual generated columns could be made to + * work, but then they would need to be handled as an expression + * below. + */ + if (attform->attgenerated) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("cannot use generated column in partition key"), + errdetail("Column \"%s\" is a generated column.", + pelem->name), + parser_errposition(pstate, pelem->location))); + + partattrs[attn] = attform->attnum; + atttype = attform->atttypid; + attcollation = attform->attcollation; + ReleaseSysCache(atttuple); + } + else + { + /* Expression */ + Node *expr = pelem->expr; + char partattname[16]; + Bitmapset *expr_attrs = NULL; + int i; + + Assert(expr != NULL); + atttype = exprType(expr); + attcollation = exprCollation(expr); + + /* + * The expression must be of a storable type (e.g., not RECORD). + * The test is the same as for whether a table column is of a safe + * type (which is why we needn't check for the non-expression + * case). + */ + snprintf(partattname, sizeof(partattname), "%d", attn + 1); + CheckAttributeType(partattname, + atttype, attcollation, + NIL, CHKATYPE_IS_PARTKEY); + + /* + * Strip any top-level COLLATE clause. This ensures that we treat + * "x COLLATE y" and "(x COLLATE y)" alike. + */ + while (IsA(expr, CollateExpr)) + expr = (Node *) ((CollateExpr *) expr)->arg; + + /* + * Examine all the columns in the partition key expression. When + * the whole-row reference is present, examine all the columns of + * the partitioned table. + */ + pull_varattnos(expr, 1, &expr_attrs); + if (bms_is_member(0 - FirstLowInvalidHeapAttributeNumber, expr_attrs)) + { + expr_attrs = bms_add_range(expr_attrs, + 1 - FirstLowInvalidHeapAttributeNumber, + RelationGetNumberOfAttributes(rel) - FirstLowInvalidHeapAttributeNumber); + expr_attrs = bms_del_member(expr_attrs, 0 - FirstLowInvalidHeapAttributeNumber); + } + + i = -1; + while ((i = bms_next_member(expr_attrs, i)) >= 0) + { + AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber; + + Assert(attno != 0); + + /* + * Cannot allow system column references, since that would + * make partition routing impossible: their values won't be + * known yet when we need to do that. + */ + if (attno < 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("partition key expressions cannot contain system column references"))); + + /* + * Stored generated columns cannot work: They are computed + * after BEFORE triggers, but partition routing is done before + * all triggers. Virtual generated columns could probably + * work, but it would require more work elsewhere (for example + * SET EXPRESSION would need to check whether the column is + * used in partition keys). Seems safer to prohibit for now. + */ + if (TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("cannot use generated column in partition key"), + errdetail("Column \"%s\" is a generated column.", + get_attname(RelationGetRelid(rel), attno, false)), + parser_errposition(pstate, pelem->location))); + } + + if (IsA(expr, Var) && + ((Var *) expr)->varattno > 0) + { + + /* + * User wrote "(column)" or "(column COLLATE something)". + * Treat it like simple attribute anyway. + */ + partattrs[attn] = ((Var *) expr)->varattno; + } + else + { + partattrs[attn] = 0; /* marks the column as expression */ + *partexprs = lappend(*partexprs, expr); + + /* + * transformPartitionSpec() should have already rejected + * subqueries, aggregates, window functions, and SRFs, based + * on the EXPR_KIND_ for partition expressions. + */ + + /* + * Preprocess the expression before checking for mutability. + * This is essential for the reasons described in + * contain_mutable_functions_after_planning. However, we call + * expression_planner for ourselves rather than using that + * function, because if constant-folding reduces the + * expression to a constant, we'd like to know that so we can + * complain below. + * + * Like contain_mutable_functions_after_planning, assume that + * expression_planner won't scribble on its input, so this + * won't affect the partexprs entry we saved above. + */ + expr = (Node *) expression_planner((Expr *) expr); + + /* + * Partition expressions cannot contain mutable functions, + * because a given row must always map to the same partition + * as long as there is no change in the partition boundary + * structure. + */ + if (contain_mutable_functions(expr)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("functions in partition key expression must be marked IMMUTABLE"))); + + /* + * While it is not exactly *wrong* for a partition expression + * to be a constant, it seems better to reject such keys. + */ + if (IsA(expr, Const)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("cannot use constant expression as partition key"))); + } + } + + /* + * Apply collation override if any + */ + if (pelem->collation) + attcollation = get_collation_oid(pelem->collation, false); + + /* + * Check we have a collation iff it's a collatable type. The only + * expected failures here are (1) COLLATE applied to a noncollatable + * type, or (2) partition expression had an unresolved collation. But + * we might as well code this to be a complete consistency check. + */ + if (type_is_collatable(atttype)) + { + if (!OidIsValid(attcollation)) + ereport(ERROR, + (errcode(ERRCODE_INDETERMINATE_COLLATION), + errmsg("could not determine which collation to use for partition expression"), + errhint("Use the COLLATE clause to set the collation explicitly."))); + } + else + { + if (OidIsValid(attcollation)) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("collations are not supported by type %s", + format_type_be(atttype)))); + } + + partcollation[attn] = attcollation; + + /* + * Identify the appropriate operator class. For list and range + * partitioning, we use a btree operator class; hash partitioning uses + * a hash operator class. + */ + if (strategy == PARTITION_STRATEGY_HASH) + am_oid = HASH_AM_OID; + else + am_oid = BTREE_AM_OID; + + if (!pelem->opclass) + { + partopclass[attn] = GetDefaultOpClass(atttype, am_oid); + + if (!OidIsValid(partopclass[attn])) + { + if (strategy == PARTITION_STRATEGY_HASH) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("data type %s has no default operator class for access method \"%s\"", + format_type_be(atttype), "hash"), + errhint("You must specify a hash operator class or define a default hash operator class for the data type."))); + else + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("data type %s has no default operator class for access method \"%s\"", + format_type_be(atttype), "btree"), + errhint("You must specify a btree operator class or define a default btree operator class for the data type."))); + } + } + else + partopclass[attn] = ResolveOpClass(pelem->opclass, + atttype, + am_oid == HASH_AM_OID ? "hash" : "btree", + am_oid); + + attn++; + } +} + +/* + * PartConstraintImpliedByRelConstraint + * Do scanrel's existing constraints imply the partition constraint? + * + * "Existing constraints" include its check constraints and column-level + * not-null constraints. partConstraint describes the partition constraint, + * in implicit-AND form. + */ +bool +PartConstraintImpliedByRelConstraint(Relation scanrel, + List *partConstraint) +{ + List *existConstraint = NIL; + TupleConstr *constr = RelationGetDescr(scanrel)->constr; + int i; + + if (constr && constr->has_not_null) + { + int natts = scanrel->rd_att->natts; + + for (i = 1; i <= natts; i++) + { + CompactAttribute *att = TupleDescCompactAttr(scanrel->rd_att, i - 1); + + /* invalid not-null constraint must be ignored here */ + if (att->attnullability == ATTNULLABLE_VALID && !att->attisdropped) + { + Form_pg_attribute wholeatt = TupleDescAttr(scanrel->rd_att, i - 1); + NullTest *ntest = makeNode(NullTest); + + ntest->arg = (Expr *) makeVar(1, + i, + wholeatt->atttypid, + wholeatt->atttypmod, + wholeatt->attcollation, + 0); + ntest->nulltesttype = IS_NOT_NULL; + + /* + * argisrow=false is correct even for a composite column, + * because attnotnull does not represent a SQL-spec IS NOT + * NULL test in such a case, just IS DISTINCT FROM NULL. + */ + ntest->argisrow = false; + ntest->location = -1; + existConstraint = lappend(existConstraint, ntest); + } + } + } + + return ConstraintImpliedByRelConstraint(scanrel, partConstraint, existConstraint); +} + +/* + * ConstraintImpliedByRelConstraint + * Do scanrel's existing constraints imply the given constraint? + * + * testConstraint is the constraint to validate. provenConstraint is a + * caller-provided list of conditions which this function may assume + * to be true. Both provenConstraint and testConstraint must be in + * implicit-AND form, must only contain immutable clauses, and must + * contain only Vars with varno = 1. + */ +bool +ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint) +{ + List *existConstraint = list_copy(provenConstraint); + TupleConstr *constr = RelationGetDescr(scanrel)->constr; + int num_check, + i; + + num_check = (constr != NULL) ? constr->num_check : 0; + for (i = 0; i < num_check; i++) + { + Node *cexpr; + + /* + * If this constraint hasn't been fully validated yet, we must ignore + * it here. + */ + if (!constr->check[i].ccvalid) + continue; + + /* + * NOT ENFORCED constraints are always marked as invalid, which should + * have been ignored. + */ + Assert(constr->check[i].ccenforced); + + cexpr = stringToNode(constr->check[i].ccbin); + + /* + * Run each expression through const-simplification and + * canonicalization. It is necessary, because we will be comparing it + * to similarly-processed partition constraint expressions, and may + * fail to detect valid matches without this. + */ + cexpr = eval_const_expressions(NULL, cexpr); + cexpr = (Node *) canonicalize_qual((Expr *) cexpr, true); + + existConstraint = list_concat(existConstraint, + make_ands_implicit((Expr *) cexpr)); + } + + /* + * Try to make the proof. Since we are comparing CHECK constraints, we + * need to use weak implication, i.e., we assume existConstraint is + * not-false and try to prove the same for testConstraint. + * + * Note that predicate_implied_by assumes its first argument is known + * immutable. That should always be true for both NOT NULL and partition + * constraints, so we don't test it here. + */ + return predicate_implied_by(testConstraint, existConstraint, true); +} + +/* + * QueuePartitionConstraintValidation + * + * Add an entry to wqueue to have the given partition constraint validated by + * Phase 3, for the given relation, and all its children. + * + * We first verify whether the given constraint is implied by pre-existing + * relation constraints; if it is, there's no need to scan the table to + * validate, so don't queue in that case. + */ +static void +QueuePartitionConstraintValidation(List **wqueue, Relation scanrel, + List *partConstraint, + bool validate_default) +{ + /* + * Based on the table's existing constraints, determine whether or not we + * may skip scanning the table. + */ + if (PartConstraintImpliedByRelConstraint(scanrel, partConstraint)) + { + if (!validate_default) + ereport(DEBUG1, + (errmsg_internal("partition constraint for table \"%s\" is implied by existing constraints", + RelationGetRelationName(scanrel)))); + else + ereport(DEBUG1, + (errmsg_internal("updated partition constraint for default partition \"%s\" is implied by existing constraints", + RelationGetRelationName(scanrel)))); + return; + } + + /* + * Constraints proved insufficient. For plain relations, queue a + * validation item now; for partitioned tables, recurse to process each + * partition. + */ + if (scanrel->rd_rel->relkind == RELKIND_RELATION) + { + AlteredTableInfo *tab; + + /* Grab a work queue entry. */ + tab = ATGetQueueEntry(wqueue, scanrel); + Assert(tab->partition_constraint == NULL); + tab->partition_constraint = (Expr *) linitial(partConstraint); + tab->validate_default = validate_default; + } + else if (scanrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + { + PartitionDesc partdesc = RelationGetPartitionDesc(scanrel, true); + int i; + + for (i = 0; i < partdesc->nparts; i++) + { + Relation part_rel; + List *thisPartConstraint; + + /* + * This is the minimum lock we need to prevent deadlocks. + */ + part_rel = table_open(partdesc->oids[i], AccessExclusiveLock); + + /* + * Adjust the constraint for scanrel so that it matches this + * partition's attribute numbers. + */ + thisPartConstraint = + map_partition_varattnos(partConstraint, 1, + part_rel, scanrel); + + QueuePartitionConstraintValidation(wqueue, part_rel, + thisPartConstraint, + validate_default); + table_close(part_rel, NoLock); /* keep lock till commit */ + } + } +} + +/* + * attachPartitionTable: attach a new partition to the partitioned table + * + * wqueue: the ALTER TABLE work queue; can be NULL when not running as part + * of an ALTER TABLE sequence. + * rel: partitioned relation; + * attachrel: relation of attached partition; + * bound: bounds of attached relation. + */ +static void +attachPartitionTable(List **wqueue, Relation rel, Relation attachrel, PartitionBoundSpec *bound) +{ + /* + * Create an inheritance; the relevant checks are performed inside the + * function. + */ + CreateInheritance(attachrel, rel, true); + + /* Update the pg_class entry. */ + StorePartitionBound(attachrel, rel, bound); + + /* Ensure there exists a correct set of indexes in the partition. */ + AttachPartitionEnsureIndexes(wqueue, rel, attachrel); + + /* and triggers */ + CloneRowTriggersToPartition(rel, attachrel); + + /* + * Clone foreign key constraints. Callee is responsible for setting up + * for phase 3 constraint verification. + */ + CloneForeignKeyConstraints(wqueue, rel, attachrel); +} + +/* + * ALTER TABLE <name> ATTACH PARTITION <partition-name> FOR VALUES + * + * Return the address of the newly attached partition. + */ +ObjectAddress +ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd, + AlterTableUtilityContext *context) +{ + Relation attachrel, + catalog; + List *attachrel_children; + List *partConstraint; + SysScanDesc scan; + ScanKeyData skey; + AttrNumber attno; + int natts; + TupleDesc tupleDesc; + ObjectAddress address; + const char *trigger_name; + Oid defaultPartOid; + List *partBoundConstraint; + ParseState *pstate = make_parsestate(NULL); + + pstate->p_sourcetext = context->queryString; + + /* + * We must lock the default partition if one exists, because attaching a + * new partition will change its partition constraint. + */ + defaultPartOid = + get_default_oid_from_partdesc(RelationGetPartitionDesc(rel, true)); + if (OidIsValid(defaultPartOid)) + LockRelationOid(defaultPartOid, AccessExclusiveLock); + + attachrel = table_openrv(cmd->name, AccessExclusiveLock); + + /* + * XXX I think it'd be a good idea to grab locks on all tables referenced + * by FKs at this point also. + */ + + /* + * Must be owner of both parent and source table -- parent was checked by + * ATSimplePermissions call in ATPrepCmd + */ + ATSimplePermissions(AT_AttachPartition, attachrel, + ATT_TABLE | ATT_PARTITIONED_TABLE | ATT_FOREIGN_TABLE); + + /* A partition can only have one parent */ + if (attachrel->rd_rel->relispartition) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is already a partition", + RelationGetRelationName(attachrel)))); + + if (OidIsValid(attachrel->rd_rel->reloftype)) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot attach a typed table as partition"))); + + /* + * Table being attached should not already be part of inheritance; either + * as a child table... + */ + catalog = table_open(InheritsRelationId, AccessShareLock); + ScanKeyInit(&skey, + Anum_pg_inherits_inhrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelationGetRelid(attachrel))); + scan = systable_beginscan(catalog, InheritsRelidSeqnoIndexId, true, + NULL, 1, &skey); + if (HeapTupleIsValid(systable_getnext(scan))) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot attach inheritance child as partition"))); + systable_endscan(scan); + + /* ...or as a parent table (except the case when it is partitioned) */ + ScanKeyInit(&skey, + Anum_pg_inherits_inhparent, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelationGetRelid(attachrel))); + scan = systable_beginscan(catalog, InheritsParentIndexId, true, NULL, + 1, &skey); + if (HeapTupleIsValid(systable_getnext(scan)) && + attachrel->rd_rel->relkind == RELKIND_RELATION) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot attach inheritance parent as partition"))); + systable_endscan(scan); + table_close(catalog, AccessShareLock); + + /* + * Prevent circularity by seeing if rel is a partition of attachrel. (In + * particular, this disallows making a rel a partition of itself.) + * + * We do that by checking if rel is a member of the list of attachrel's + * partitions provided the latter is partitioned at all. We want to avoid + * having to construct this list again, so we request the strongest lock + * on all partitions. We need the strongest lock, because we may decide + * to scan them if we find out that the table being attached (or its leaf + * partitions) may contain rows that violate the partition constraint. If + * the table has a constraint that would prevent such rows, which by + * definition is present in all the partitions, we need not scan the + * table, nor its partitions. But we cannot risk a deadlock by taking a + * weaker lock now and the stronger one only when needed. + */ + attachrel_children = find_all_inheritors(RelationGetRelid(attachrel), + AccessExclusiveLock, NULL); + if (list_member_oid(attachrel_children, RelationGetRelid(rel))) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_TABLE), + errmsg("circular inheritance not allowed"), + errdetail("\"%s\" is already a child of \"%s\".", + RelationGetRelationName(rel), + RelationGetRelationName(attachrel)))); + + /* If the parent is permanent, so must be all of its partitions. */ + if (rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP && + attachrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot attach a temporary relation as partition of permanent relation \"%s\"", + RelationGetRelationName(rel)))); + + /* Temp parent cannot have a partition that is itself not a temp */ + if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP && + attachrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot attach a permanent relation as partition of temporary relation \"%s\"", + RelationGetRelationName(rel)))); + + /* If the parent is temp, it must belong to this session */ + if (RELATION_IS_OTHER_TEMP(rel)) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot attach as partition of temporary relation of another session"))); + + /* Ditto for the partition */ + if (RELATION_IS_OTHER_TEMP(attachrel)) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot attach temporary relation of another session as partition"))); + + /* + * Check if attachrel has any identity columns or any columns that aren't + * in the parent. + */ + tupleDesc = RelationGetDescr(attachrel); + natts = tupleDesc->natts; + for (attno = 1; attno <= natts; attno++) + { + Form_pg_attribute attribute = TupleDescAttr(tupleDesc, attno - 1); + char *attributeName = NameStr(attribute->attname); + + /* Ignore dropped */ + if (attribute->attisdropped) + continue; + + if (attribute->attidentity) + ereport(ERROR, + errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("table \"%s\" being attached contains an identity column \"%s\"", + RelationGetRelationName(attachrel), attributeName), + errdetail("The new partition may not contain an identity column.")); + + /* Try to find the column in parent (matching on column name) */ + if (!SearchSysCacheExists2(ATTNAME, + ObjectIdGetDatum(RelationGetRelid(rel)), + CStringGetDatum(attributeName))) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("table \"%s\" contains column \"%s\" not found in parent \"%s\"", + RelationGetRelationName(attachrel), attributeName, + RelationGetRelationName(rel)), + errdetail("The new partition may contain only the columns present in parent."))); + } + + /* + * If child_rel has row-level triggers with transition tables, we + * currently don't allow it to become a partition. See also prohibitions + * in ATExecAddInherit() and CreateTrigger(). + */ + trigger_name = FindTriggerIncompatibleWithInheritance(attachrel->trigdesc); + if (trigger_name != NULL) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("trigger \"%s\" prevents table \"%s\" from becoming a partition", + trigger_name, RelationGetRelationName(attachrel)), + errdetail("ROW triggers with transition tables are not supported on partitions."))); + + /* + * Check that the new partition's bound is valid and does not overlap any + * of existing partitions of the parent - note that it does not return on + * error. + */ + check_new_partition_bound(RelationGetRelationName(attachrel), rel, + cmd->bound, pstate); + + attachPartitionTable(wqueue, rel, attachrel, cmd->bound); + + /* + * Generate a partition constraint from the partition bound specification. + * If the parent itself is a partition, make sure to include its + * constraint as well. + */ + partBoundConstraint = get_qual_from_partbound(rel, cmd->bound); + + /* + * Use list_concat_copy() to avoid modifying partBoundConstraint in place, + * since it's needed later to construct the constraint expression for + * validating against the default partition, if any. + */ + partConstraint = list_concat_copy(partBoundConstraint, + RelationGetPartitionQual(rel)); + + /* Skip validation if there are no constraints to validate. */ + if (partConstraint) + { + /* + * Run the partition quals through const-simplification similar to + * check constraints. We skip canonicalize_qual, though, because + * partition quals should be in canonical form already. + */ + partConstraint = + (List *) eval_const_expressions(NULL, + (Node *) partConstraint); + + /* XXX this sure looks wrong */ + partConstraint = list_make1(make_ands_explicit(partConstraint)); + + /* + * Adjust the generated constraint to match this partition's attribute + * numbers. + */ + partConstraint = map_partition_varattnos(partConstraint, 1, attachrel, + rel); + + /* Validate partition constraints against the table being attached. */ + QueuePartitionConstraintValidation(wqueue, attachrel, partConstraint, + false); + } + + /* + * If we're attaching a partition other than the default partition and a + * default one exists, then that partition's partition constraint changes, + * so add an entry to the work queue to validate it, too. (We must not do + * this when the partition being attached is the default one; we already + * did it above!) + */ + if (OidIsValid(defaultPartOid)) + { + Relation defaultrel; + List *defPartConstraint; + + Assert(!cmd->bound->is_default); + + /* we already hold a lock on the default partition */ + defaultrel = table_open(defaultPartOid, NoLock); + defPartConstraint = + get_proposed_default_constraint(partBoundConstraint); + + /* + * Map the Vars in the constraint expression from rel's attnos to + * defaultrel's. + */ + defPartConstraint = + map_partition_varattnos(defPartConstraint, + 1, defaultrel, rel); + QueuePartitionConstraintValidation(wqueue, defaultrel, + defPartConstraint, true); + + /* keep our lock until commit. */ + table_close(defaultrel, NoLock); + } + + ObjectAddressSet(address, RelationRelationId, RelationGetRelid(attachrel)); + + /* + * If the partition we just attached is partitioned itself, invalidate + * relcache for all descendent partitions too to ensure that their + * rd_partcheck expression trees are rebuilt; partitions already locked at + * the beginning of this function. + */ + if (attachrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + { + ListCell *l; + + foreach(l, attachrel_children) + { + CacheInvalidateRelcacheByRelid(lfirst_oid(l)); + } + } + + /* keep our lock until commit */ + table_close(attachrel, NoLock); + + return address; +} + +/* + * AttachPartitionEnsureIndexes + * subroutine for ATExecAttachPartition to create/match indexes + * + * Enforce the indexing rule for partitioned tables during ALTER TABLE / ATTACH + * PARTITION: every partition must have an index attached to each index on the + * partitioned table. + */ +static void +AttachPartitionEnsureIndexes(List **wqueue, Relation rel, Relation attachrel) +{ + List *idxes; + List *attachRelIdxs; + Relation *attachrelIdxRels; + IndexInfo **attachInfos; + ListCell *cell; + MemoryContext cxt; + MemoryContext oldcxt; + + cxt = AllocSetContextCreate(CurrentMemoryContext, + "AttachPartitionEnsureIndexes", + ALLOCSET_DEFAULT_SIZES); + oldcxt = MemoryContextSwitchTo(cxt); + + idxes = RelationGetIndexList(rel); + attachRelIdxs = RelationGetIndexList(attachrel); + attachrelIdxRels = palloc_array(Relation, list_length(attachRelIdxs)); + attachInfos = palloc_array(IndexInfo *, list_length(attachRelIdxs)); + + /* Build arrays of all existing indexes and their IndexInfos */ + foreach_oid(cldIdxId, attachRelIdxs) + { + int i = foreach_current_index(cldIdxId); + + attachrelIdxRels[i] = index_open(cldIdxId, AccessShareLock); + attachInfos[i] = BuildIndexInfo(attachrelIdxRels[i]); + } + + /* + * If we're attaching a foreign table, we must fail if any of the indexes + * is a constraint index; otherwise, there's nothing to do here. Do this + * before starting work, to avoid wasting the effort of building a few + * non-unique indexes before coming across a unique one. + */ + if (attachrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE) + { + foreach(cell, idxes) + { + Oid idx = lfirst_oid(cell); + Relation idxRel = index_open(idx, AccessShareLock); + + if (idxRel->rd_index->indisunique || + idxRel->rd_index->indisprimary) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot attach foreign table \"%s\" as partition of partitioned table \"%s\"", + RelationGetRelationName(attachrel), + RelationGetRelationName(rel)), + errdetail("Partitioned table \"%s\" contains unique indexes.", + RelationGetRelationName(rel)))); + index_close(idxRel, AccessShareLock); + } + + goto out; + } + + /* + * For each index on the partitioned table, find a matching one in the + * partition-to-be; if one is not found, create one. + */ + foreach(cell, idxes) + { + Oid idx = lfirst_oid(cell); + Relation idxRel = index_open(idx, AccessShareLock); + IndexInfo *info; + AttrMap *attmap; + bool found = false; + Oid constraintOid; + + /* + * Ignore indexes in the partitioned table other than partitioned + * indexes. + */ + if (idxRel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX) + { + index_close(idxRel, AccessShareLock); + continue; + } + + /* construct an indexinfo to compare existing indexes against */ + info = BuildIndexInfo(idxRel); + attmap = build_attrmap_by_name(RelationGetDescr(attachrel), + RelationGetDescr(rel), + false); + constraintOid = get_relation_idx_constraint_oid(RelationGetRelid(rel), idx); + + /* + * Scan the list of existing indexes in the partition-to-be, and mark + * the first matching, valid, unattached one we find, if any, as + * partition of the parent index. If we find one, we're done. + */ + for (int i = 0; i < list_length(attachRelIdxs); i++) + { + Oid cldIdxId = RelationGetRelid(attachrelIdxRels[i]); + Oid cldConstrOid = InvalidOid; + + /* does this index have a parent? if so, can't use it */ + if (attachrelIdxRels[i]->rd_rel->relispartition) + continue; + + /* If this index is invalid, can't use it */ + if (!attachrelIdxRels[i]->rd_index->indisvalid) + continue; + + if (CompareIndexInfo(attachInfos[i], info, + attachrelIdxRels[i]->rd_indcollation, + idxRel->rd_indcollation, + attachrelIdxRels[i]->rd_opfamily, + idxRel->rd_opfamily, + attmap)) + { + /* + * If this index is being created in the parent because of a + * constraint, then the child needs to have a constraint also, + * so look for one. If there is no such constraint, this + * index is no good, so keep looking. + */ + if (OidIsValid(constraintOid)) + { + cldConstrOid = + get_relation_idx_constraint_oid(RelationGetRelid(attachrel), + cldIdxId); + /* no dice */ + if (!OidIsValid(cldConstrOid)) + continue; + + /* Ensure they're both the same type of constraint */ + if (get_constraint_type(constraintOid) != + get_constraint_type(cldConstrOid)) + continue; + } + + /* bingo. */ + IndexSetParentIndex(attachrelIdxRels[i], idx); + if (OidIsValid(constraintOid)) + ConstraintSetParentConstraint(cldConstrOid, constraintOid, + RelationGetRelid(attachrel)); + found = true; + + CommandCounterIncrement(); + break; + } + } + + /* + * If no suitable index was found in the partition-to-be, create one + * now. Note that if this is a PK, not-null constraints must already + * exist. + */ + if (!found) + { + IndexStmt *stmt; + Oid conOid; + + stmt = generateClonedIndexStmt(NULL, + idxRel, attmap, + &conOid); + DefineIndex(NULL, + RelationGetRelid(attachrel), stmt, InvalidOid, + RelationGetRelid(idxRel), + conOid, + -1, + true, false, false, false, false); + } + + index_close(idxRel, AccessShareLock); + } + +out: + /* Clean up. */ + for (int i = 0; i < list_length(attachRelIdxs); i++) + index_close(attachrelIdxRels[i], AccessShareLock); + MemoryContextSwitchTo(oldcxt); + MemoryContextDelete(cxt); +} + +/* + * CloneRowTriggersToPartition + * subroutine for ATExecAttachPartition/DefineRelation to create row + * triggers on partitions + */ +void +CloneRowTriggersToPartition(Relation parent, Relation partition) +{ + Relation pg_trigger; + ScanKeyData key; + SysScanDesc scan; + HeapTuple tuple; + MemoryContext perTupCxt; + + ScanKeyInit(&key, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber, + F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parent))); + pg_trigger = table_open(TriggerRelationId, RowExclusiveLock); + scan = systable_beginscan(pg_trigger, TriggerRelidNameIndexId, + true, NULL, 1, &key); + + perTupCxt = AllocSetContextCreate(CurrentMemoryContext, + "clone trig", ALLOCSET_SMALL_SIZES); + + while (HeapTupleIsValid(tuple = systable_getnext(scan))) + { + Form_pg_trigger trigForm = (Form_pg_trigger) GETSTRUCT(tuple); + CreateTrigStmt *trigStmt; + Node *qual = NULL; + Datum value; + bool isnull; + List *cols = NIL; + List *trigargs = NIL; + MemoryContext oldcxt; + + /* + * Ignore statement-level triggers; those are not cloned. + */ + if (!TRIGGER_FOR_ROW(trigForm->tgtype)) + continue; + + /* + * Don't clone internal triggers, because the constraint cloning code + * will. + */ + if (trigForm->tgisinternal) + continue; + + /* + * Complain if we find an unexpected trigger type. + */ + if (!TRIGGER_FOR_BEFORE(trigForm->tgtype) && + !TRIGGER_FOR_AFTER(trigForm->tgtype)) + elog(ERROR, "unexpected trigger \"%s\" found", + NameStr(trigForm->tgname)); + + /* Use short-lived context for CREATE TRIGGER */ + oldcxt = MemoryContextSwitchTo(perTupCxt); + + /* + * If there is a WHEN clause, generate a 'cooked' version of it that's + * appropriate for the partition. + */ + value = heap_getattr(tuple, Anum_pg_trigger_tgqual, + RelationGetDescr(pg_trigger), &isnull); + if (!isnull) + { + qual = stringToNode(TextDatumGetCString(value)); + qual = (Node *) map_partition_varattnos((List *) qual, PRS2_OLD_VARNO, + partition, parent); + qual = (Node *) map_partition_varattnos((List *) qual, PRS2_NEW_VARNO, + partition, parent); + } + + /* + * If there is a column list, transform it to a list of column names. + * Note we don't need to map this list in any way ... + */ + if (trigForm->tgattr.dim1 > 0) + { + int i; + + for (i = 0; i < trigForm->tgattr.dim1; i++) + { + Form_pg_attribute col; + + col = TupleDescAttr(parent->rd_att, + trigForm->tgattr.values[i] - 1); + cols = lappend(cols, + makeString(pstrdup(NameStr(col->attname)))); + } + } + + /* Reconstruct trigger arguments list. */ + if (trigForm->tgnargs > 0) + { + char *p; + + value = heap_getattr(tuple, Anum_pg_trigger_tgargs, + RelationGetDescr(pg_trigger), &isnull); + if (isnull) + elog(ERROR, "tgargs is null for trigger \"%s\" in partition \"%s\"", + NameStr(trigForm->tgname), RelationGetRelationName(partition)); + + p = (char *) VARDATA_ANY(DatumGetByteaPP(value)); + + for (int i = 0; i < trigForm->tgnargs; i++) + { + trigargs = lappend(trigargs, makeString(pstrdup(p))); + p += strlen(p) + 1; + } + } + + trigStmt = makeNode(CreateTrigStmt); + trigStmt->replace = false; + trigStmt->isconstraint = OidIsValid(trigForm->tgconstraint); + trigStmt->trigname = NameStr(trigForm->tgname); + trigStmt->relation = NULL; + trigStmt->funcname = NULL; /* passed separately */ + trigStmt->args = trigargs; + trigStmt->row = true; + trigStmt->timing = trigForm->tgtype & TRIGGER_TYPE_TIMING_MASK; + trigStmt->events = trigForm->tgtype & TRIGGER_TYPE_EVENT_MASK; + trigStmt->columns = cols; + trigStmt->whenClause = NULL; /* passed separately */ + trigStmt->transitionRels = NIL; /* not supported at present */ + trigStmt->deferrable = trigForm->tgdeferrable; + trigStmt->initdeferred = trigForm->tginitdeferred; + trigStmt->constrrel = NULL; /* passed separately */ + + CreateTriggerFiringOn(trigStmt, NULL, RelationGetRelid(partition), + trigForm->tgconstrrelid, InvalidOid, InvalidOid, + trigForm->tgfoid, trigForm->oid, qual, + false, true, trigForm->tgenabled); + + MemoryContextSwitchTo(oldcxt); + MemoryContextReset(perTupCxt); + } + + MemoryContextDelete(perTupCxt); + + systable_endscan(scan); + table_close(pg_trigger, RowExclusiveLock); +} + +/* + * ALTER TABLE DETACH PARTITION + * + * Return the address of the relation that is no longer a partition of rel. + * + * If concurrent mode is requested, we run in two transactions. A side- + * effect is that this command cannot run in a multi-part ALTER TABLE. + * Currently, that's enforced by the grammar. + * + * The strategy for concurrency is to first modify the partition's + * pg_inherit catalog row to make it visible to everyone that the + * partition is detached, lock the partition against writes, and commit + * the transaction; anyone who requests the partition descriptor from + * that point onwards has to ignore such a partition. In a second + * transaction, we wait until all transactions that could have seen the + * partition as attached are gone, then we remove the rest of partition + * metadata (pg_inherits and pg_class.relpartbounds). + */ +ObjectAddress +ATExecDetachPartition(List **wqueue, AlteredTableInfo *tab, Relation rel, + RangeVar *name, bool concurrent) +{ + Relation partRel; + ObjectAddress address; + Oid defaultPartOid; + + /* + * We must lock the default partition, because detaching this partition + * will change its partition constraint. + */ + defaultPartOid = + get_default_oid_from_partdesc(RelationGetPartitionDesc(rel, true)); + if (OidIsValid(defaultPartOid)) + { + /* + * Concurrent detaching when a default partition exists is not + * supported. The main problem is that the default partition + * constraint would change. And there's a definitional problem: what + * should happen to the tuples that are being inserted that belong to + * the partition being detached? Putting them on the partition being + * detached would be wrong, since they'd become "lost" after the + * detaching completes but we cannot put them in the default partition + * either until we alter its partition constraint. + * + * I think we could solve this problem if we effected the constraint + * change before committing the first transaction. But the lock would + * have to remain AEL and it would cause concurrent query planning to + * be blocked, so changing it that way would be even worse. + */ + if (concurrent) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("cannot detach partitions concurrently when a default partition exists"))); + LockRelationOid(defaultPartOid, AccessExclusiveLock); + } + + /* + * In concurrent mode, the partition is locked with share-update-exclusive + * in the first transaction. This allows concurrent transactions to be + * doing DML to the partition. + */ + partRel = table_openrv(name, concurrent ? ShareUpdateExclusiveLock : + AccessExclusiveLock); + + /* + * Check inheritance conditions and either delete the pg_inherits row (in + * non-concurrent mode) or just set the inhdetachpending flag. + */ + if (!concurrent) + RemoveInheritance(partRel, rel, false); + else + MarkInheritDetached(partRel, rel); + + /* + * Ensure that foreign keys still hold after this detach. This keeps + * locks on the referencing tables, which prevents concurrent transactions + * from adding rows that we wouldn't see. For this to work in concurrent + * mode, it is critical that the partition appears as no longer attached + * for the RI queries as soon as the first transaction commits. + */ + ATDetachCheckNoForeignKeyRefs(partRel); + + /* + * Concurrent mode has to work harder; first we add a new constraint to + * the partition that matches the partition constraint. Then we close our + * existing transaction, and in a new one wait for all processes to catch + * up on the catalog updates we've done so far; at that point we can + * complete the operation. + */ + if (concurrent) + { + Oid partrelid, + parentrelid; + LOCKTAG tag; + char *parentrelname; + char *partrelname; + + /* + * We're almost done now; the only traces that remain are the + * pg_inherits tuple and the partition's relpartbounds. Before we can + * remove those, we need to wait until all transactions that know that + * this is a partition are gone. + */ + + /* + * Remember relation OIDs to re-acquire them later; and relation names + * too, for error messages if something is dropped in between. + */ + partrelid = RelationGetRelid(partRel); + parentrelid = RelationGetRelid(rel); + parentrelname = MemoryContextStrdup(PortalContext, + RelationGetRelationName(rel)); + partrelname = MemoryContextStrdup(PortalContext, + RelationGetRelationName(partRel)); + + /* Invalidate relcache entries for the parent -- must be before close */ + CacheInvalidateRelcache(rel); + + table_close(partRel, NoLock); + table_close(rel, NoLock); + tab->rel = NULL; + + /* Make updated catalog entry visible */ + PopActiveSnapshot(); + CommitTransactionCommand(); + + StartTransactionCommand(); + + /* + * Now wait. This ensures that all queries that were planned + * including the partition are finished before we remove the rest of + * catalog entries. We don't need or indeed want to acquire this + * lock, though -- that would block later queries. + * + * We don't need to concern ourselves with waiting for a lock on the + * partition itself, since we will acquire AccessExclusiveLock below. + */ + SET_LOCKTAG_RELATION(tag, MyDatabaseId, parentrelid); + WaitForLockersMultiple(list_make1(&tag), AccessExclusiveLock, false); + + /* + * Now acquire locks in both relations again. Note they may have been + * removed in the meantime, so care is required. + */ + rel = try_relation_open(parentrelid, ShareUpdateExclusiveLock); + partRel = try_relation_open(partrelid, AccessExclusiveLock); + + /* If the relations aren't there, something bad happened; bail out */ + if (rel == NULL) + { + if (partRel != NULL) /* shouldn't happen */ + elog(WARNING, "dangling partition \"%s\" remains, can't fix", + partrelname); + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("partitioned table \"%s\" was removed concurrently", + parentrelname))); + } + if (partRel == NULL) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("partition \"%s\" was removed concurrently", partrelname))); + + tab->rel = rel; + } + + /* + * Detaching the partition might involve TOAST table access, so ensure we + * have a valid snapshot. + */ + PushActiveSnapshot(GetTransactionSnapshot()); + + /* Do the final part of detaching */ + DetachPartitionFinalize(rel, partRel, concurrent, defaultPartOid); + + PopActiveSnapshot(); + + ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel)); + + /* keep our lock until commit */ + table_close(partRel, NoLock); + + return address; +} + +/* + * Second part of ALTER TABLE .. DETACH. + * + * This is separate so that it can be run independently when the second + * transaction of the concurrent algorithm fails (crash or abort). + */ +static void +DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent, + Oid defaultPartOid) +{ + Relation classRel; + List *fks; + ListCell *cell; + List *indexes; + Datum new_val[Natts_pg_class]; + bool new_null[Natts_pg_class], + new_repl[Natts_pg_class]; + HeapTuple tuple, + newtuple; + Relation trigrel = NULL; + List *fkoids = NIL; + + if (concurrent) + { + /* + * We can remove the pg_inherits row now. (In the non-concurrent case, + * this was already done). + */ + RemoveInheritance(partRel, rel, true); + } + + /* Drop any triggers that were cloned on creation/attach. */ + DropClonedTriggersFromPartition(RelationGetRelid(partRel)); + + /* + * Detach any foreign keys that are inherited. This includes creating + * additional action triggers. + */ + fks = copyObject(RelationGetFKeyList(partRel)); + if (fks != NIL) + trigrel = table_open(TriggerRelationId, RowExclusiveLock); + + /* + * It's possible that the partition being detached has a foreign key that + * references a partitioned table. When that happens, there are multiple + * pg_constraint rows for the partition: one points to the partitioned + * table itself, while the others point to each of its partitions. Only + * the topmost one is to be considered here; the child constraints must be + * left alone, because conceptually those aren't coming from our parent + * partitioned table, but from this partition itself. + * + * We implement this by collecting all the constraint OIDs in a first scan + * of the FK array, and skipping in the loop below those constraints whose + * parents are listed here. + */ + foreach_node(ForeignKeyCacheInfo, fk, fks) + fkoids = lappend_oid(fkoids, fk->conoid); + + foreach(cell, fks) + { + ForeignKeyCacheInfo *fk = lfirst(cell); + HeapTuple contup; + Form_pg_constraint conform; + + contup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(fk->conoid)); + if (!HeapTupleIsValid(contup)) + elog(ERROR, "cache lookup failed for constraint %u", fk->conoid); + conform = (Form_pg_constraint) GETSTRUCT(contup); + + /* + * Consider only inherited foreign keys, and only if their parents + * aren't in the list. + */ + if (conform->contype != CONSTRAINT_FOREIGN || + !OidIsValid(conform->conparentid) || + list_member_oid(fkoids, conform->conparentid)) + { + ReleaseSysCache(contup); + continue; + } + + /* + * The constraint on this table must be marked no longer a child of + * the parent's constraint, as do its check triggers. + */ + ConstraintSetParentConstraint(fk->conoid, InvalidOid, InvalidOid); + + /* + * Also, look up the partition's "check" triggers corresponding to the + * ENFORCED constraint being detached and detach them from the parent + * triggers. NOT ENFORCED constraints do not have these triggers; + * therefore, this step is not needed. + */ + if (fk->conenforced) + { + Oid insertTriggerOid, + updateTriggerOid; + + GetForeignKeyCheckTriggers(trigrel, + fk->conoid, fk->confrelid, fk->conrelid, + &insertTriggerOid, &updateTriggerOid); + Assert(OidIsValid(insertTriggerOid)); + TriggerSetParentTrigger(trigrel, insertTriggerOid, InvalidOid, + RelationGetRelid(partRel)); + Assert(OidIsValid(updateTriggerOid)); + TriggerSetParentTrigger(trigrel, updateTriggerOid, InvalidOid, + RelationGetRelid(partRel)); + } + + /* + * Lastly, create the action triggers on the referenced table, using + * addFkRecurseReferenced, which requires some elaborate setup (so put + * it in a separate block). While at it, if the table is partitioned, + * that function will recurse to create the pg_constraint rows and + * action triggers for each partition. + * + * Note there's no need to do addFkConstraint() here, because the + * pg_constraint row already exists. + */ + { + Constraint *fkconstraint; + int numfks; + AttrNumber conkey[INDEX_MAX_KEYS]; + AttrNumber confkey[INDEX_MAX_KEYS]; + Oid conpfeqop[INDEX_MAX_KEYS]; + Oid conppeqop[INDEX_MAX_KEYS]; + Oid conffeqop[INDEX_MAX_KEYS]; + int numfkdelsetcols; + AttrNumber confdelsetcols[INDEX_MAX_KEYS]; + Relation refdRel; + + DeconstructFkConstraintRow(contup, + &numfks, + conkey, + confkey, + conpfeqop, + conppeqop, + conffeqop, + &numfkdelsetcols, + confdelsetcols); + + /* Create a synthetic node we'll use throughout */ + fkconstraint = makeNode(Constraint); + fkconstraint->contype = CONSTRAINT_FOREIGN; + fkconstraint->conname = pstrdup(NameStr(conform->conname)); + fkconstraint->deferrable = conform->condeferrable; + fkconstraint->initdeferred = conform->condeferred; + fkconstraint->is_enforced = conform->conenforced; + fkconstraint->skip_validation = true; + fkconstraint->initially_valid = conform->convalidated; + /* a few irrelevant fields omitted here */ + fkconstraint->pktable = NULL; + fkconstraint->fk_attrs = NIL; + fkconstraint->pk_attrs = NIL; + fkconstraint->fk_matchtype = conform->confmatchtype; + fkconstraint->fk_upd_action = conform->confupdtype; + fkconstraint->fk_del_action = conform->confdeltype; + fkconstraint->fk_del_set_cols = NIL; + fkconstraint->old_conpfeqop = NIL; + fkconstraint->old_pktable_oid = InvalidOid; + fkconstraint->location = -1; + + /* set up colnames, used to generate the constraint name */ + for (int i = 0; i < numfks; i++) + { + Form_pg_attribute att; + + att = TupleDescAttr(RelationGetDescr(partRel), + conkey[i] - 1); + + fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs, + makeString(NameStr(att->attname))); + } + + refdRel = table_open(fk->confrelid, ShareRowExclusiveLock); + + addFkRecurseReferenced(fkconstraint, partRel, + refdRel, + conform->conindid, + fk->conoid, + numfks, + confkey, + conkey, + conpfeqop, + conppeqop, + conffeqop, + numfkdelsetcols, + confdelsetcols, + true, + InvalidOid, InvalidOid, + conform->conperiod); + table_close(refdRel, NoLock); /* keep lock till end of xact */ + } + + ReleaseSysCache(contup); + } + list_free_deep(fks); + if (trigrel) + table_close(trigrel, RowExclusiveLock); + + /* + * Any sub-constraints that are in the referenced-side of a larger + * constraint have to be removed. This partition is no longer part of the + * key space of the constraint. + */ + foreach(cell, GetParentedForeignKeyRefs(partRel)) + { + Oid constrOid = lfirst_oid(cell); + ObjectAddress constraint; + + ConstraintSetParentConstraint(constrOid, InvalidOid, InvalidOid); + deleteDependencyRecordsForClass(ConstraintRelationId, + constrOid, + ConstraintRelationId, + DEPENDENCY_INTERNAL); + CommandCounterIncrement(); + + ObjectAddressSet(constraint, ConstraintRelationId, constrOid); + performDeletion(&constraint, DROP_RESTRICT, 0); + } + + /* Now we can detach indexes */ + indexes = RelationGetIndexList(partRel); + foreach(cell, indexes) + { + Oid idxid = lfirst_oid(cell); + Oid parentidx; + Relation idx; + Oid constrOid; + Oid parentConstrOid; + + if (!has_superclass(idxid)) + continue; + + parentidx = get_partition_parent(idxid, false); + Assert((IndexGetRelation(parentidx, false) == RelationGetRelid(rel))); + + idx = index_open(idxid, AccessExclusiveLock); + IndexSetParentIndex(idx, InvalidOid); + + /* + * If there's a constraint associated with the index, detach it too. + * Careful: it is possible for a constraint index in a partition to be + * the child of a non-constraint index, so verify whether the parent + * index does actually have a constraint. + */ + constrOid = get_relation_idx_constraint_oid(RelationGetRelid(partRel), + idxid); + parentConstrOid = get_relation_idx_constraint_oid(RelationGetRelid(rel), + parentidx); + if (OidIsValid(parentConstrOid) && OidIsValid(constrOid)) + ConstraintSetParentConstraint(constrOid, InvalidOid, InvalidOid); + + index_close(idx, NoLock); + } + + /* Update pg_class tuple */ + classRel = table_open(RelationRelationId, RowExclusiveLock); + tuple = SearchSysCacheCopy1(RELOID, + ObjectIdGetDatum(RelationGetRelid(partRel))); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for relation %u", + RelationGetRelid(partRel)); + Assert(((Form_pg_class) GETSTRUCT(tuple))->relispartition); + + /* Clear relpartbound and reset relispartition */ + memset(new_val, 0, sizeof(new_val)); + memset(new_null, false, sizeof(new_null)); + memset(new_repl, false, sizeof(new_repl)); + new_val[Anum_pg_class_relpartbound - 1] = (Datum) 0; + new_null[Anum_pg_class_relpartbound - 1] = true; + new_repl[Anum_pg_class_relpartbound - 1] = true; + newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel), + new_val, new_null, new_repl); + + ((Form_pg_class) GETSTRUCT(newtuple))->relispartition = false; + CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple); + heap_freetuple(newtuple); + table_close(classRel, RowExclusiveLock); + + /* + * Drop identity property from all identity columns of partition. + */ + for (int attno = 0; attno < RelationGetNumberOfAttributes(partRel); attno++) + { + Form_pg_attribute attr = TupleDescAttr(partRel->rd_att, attno); + + if (!attr->attisdropped && attr->attidentity) + ATExecDropIdentity(partRel, NameStr(attr->attname), false, + AccessExclusiveLock, true, true); + } + + if (OidIsValid(defaultPartOid)) + { + /* + * If the relation being detached is the default partition itself, + * remove it from the parent's pg_partitioned_table entry. + * + * If not, we must invalidate default partition's relcache entry, as + * in StorePartitionBound: its partition constraint depends on every + * other partition's partition constraint. + */ + if (RelationGetRelid(partRel) == defaultPartOid) + update_default_partition_oid(RelationGetRelid(rel), InvalidOid); + else + CacheInvalidateRelcacheByRelid(defaultPartOid); + } + + /* + * Invalidate the parent's relcache so that the partition is no longer + * included in its partition descriptor. + */ + CacheInvalidateRelcache(rel); + + /* + * If the partition we just detached is partitioned itself, invalidate + * relcache for all descendent partitions too to ensure that their + * rd_partcheck expression trees are rebuilt; must lock partitions before + * doing so, using the same lockmode as what partRel has been locked with + * by the caller. + */ + if (partRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + { + List *children; + + children = find_all_inheritors(RelationGetRelid(partRel), + AccessExclusiveLock, NULL); + foreach(cell, children) + { + CacheInvalidateRelcacheByRelid(lfirst_oid(cell)); + } + } +} + +/* + * ALTER TABLE ... DETACH PARTITION ... FINALIZE + * + * To use when a DETACH PARTITION command previously did not run to + * completion; this completes the detaching process. + */ +ObjectAddress +ATExecDetachPartitionFinalize(Relation rel, RangeVar *name) +{ + Relation partRel; + ObjectAddress address; + Snapshot snap = GetActiveSnapshot(); + + partRel = table_openrv(name, AccessExclusiveLock); + + /* + * Wait until existing snapshots are gone. This is important if the + * second transaction of DETACH PARTITION CONCURRENTLY is canceled: the + * user could immediately run DETACH FINALIZE without actually waiting for + * existing transactions. We must not complete the detach action until + * all such queries are complete (otherwise we would present them with an + * inconsistent view of catalogs). + */ + WaitForOlderSnapshots(snap->xmin, false); + + DetachPartitionFinalize(rel, partRel, true, InvalidOid); + + ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel)); + + table_close(partRel, NoLock); + + return address; +} + +/* + * DropClonedTriggersFromPartition + * subroutine for ATExecDetachPartition to remove any triggers that were + * cloned to the partition when it was created-as-partition or attached. + * This undoes what CloneRowTriggersToPartition did. + */ +static void +DropClonedTriggersFromPartition(Oid partitionId) +{ + ScanKeyData skey; + SysScanDesc scan; + HeapTuple trigtup; + Relation tgrel; + ObjectAddresses *objects; + + objects = new_object_addresses(); + + /* + * Scan pg_trigger to search for all triggers on this rel. + */ + ScanKeyInit(&skey, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber, + F_OIDEQ, ObjectIdGetDatum(partitionId)); + tgrel = table_open(TriggerRelationId, RowExclusiveLock); + scan = systable_beginscan(tgrel, TriggerRelidNameIndexId, + true, NULL, 1, &skey); + while (HeapTupleIsValid(trigtup = systable_getnext(scan))) + { + Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(trigtup); + ObjectAddress trig; + + /* Ignore triggers that weren't cloned */ + if (!OidIsValid(pg_trigger->tgparentid)) + continue; + + /* + * Ignore internal triggers that are implementation objects of foreign + * keys, because these will be detached when the foreign keys + * themselves are. + */ + if (OidIsValid(pg_trigger->tgconstrrelid)) + continue; + + /* + * This is ugly, but necessary: remove the dependency markings on the + * trigger so that it can be removed. + */ + deleteDependencyRecordsForClass(TriggerRelationId, pg_trigger->oid, + TriggerRelationId, + DEPENDENCY_PARTITION_PRI); + deleteDependencyRecordsForClass(TriggerRelationId, pg_trigger->oid, + RelationRelationId, + DEPENDENCY_PARTITION_SEC); + + /* remember this trigger to remove it below */ + ObjectAddressSet(trig, TriggerRelationId, pg_trigger->oid); + add_exact_object_address(&trig, objects); + } + + /* make the dependency removal visible to the deletion below */ + CommandCounterIncrement(); + performMultipleDeletions(objects, DROP_RESTRICT, PERFORM_DELETION_INTERNAL); + + /* done */ + free_object_addresses(objects); + systable_endscan(scan); + table_close(tgrel, RowExclusiveLock); +} + +/* + * Before acquiring lock on an index, acquire the same lock on the owning + * table. + */ +struct AttachIndexCallbackState +{ + Oid partitionOid; + Oid parentTblOid; + bool lockedParentTbl; +}; + +static void +RangeVarCallbackForAttachIndex(const RangeVar *rv, Oid relOid, Oid oldRelOid, + void *arg) +{ + struct AttachIndexCallbackState *state; + Form_pg_class classform; + HeapTuple tuple; + + state = (struct AttachIndexCallbackState *) arg; + + if (!state->lockedParentTbl) + { + LockRelationOid(state->parentTblOid, AccessShareLock); + state->lockedParentTbl = true; + } + + /* + * If we previously locked some other heap, and the name we're looking up + * no longer refers to an index on that relation, release the now-useless + * lock. XXX maybe we should do *after* we verify whether the index does + * not actually belong to the same relation ... + */ + if (relOid != oldRelOid && OidIsValid(state->partitionOid)) + { + UnlockRelationOid(state->partitionOid, AccessShareLock); + state->partitionOid = InvalidOid; + } + + /* Didn't find a relation, so no need for locking or permission checks. */ + if (!OidIsValid(relOid)) + return; + + tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid)); + if (!HeapTupleIsValid(tuple)) + return; /* concurrently dropped, so nothing to do */ + classform = (Form_pg_class) GETSTRUCT(tuple); + if (classform->relkind != RELKIND_PARTITIONED_INDEX && + classform->relkind != RELKIND_INDEX) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("\"%s\" is not an index", rv->relname))); + ReleaseSysCache(tuple); + + /* + * Since we need only examine the heap's tupledesc, an access share lock + * on it (preventing any DDL) is sufficient. + */ + state->partitionOid = IndexGetRelation(relOid, false); + LockRelationOid(state->partitionOid, AccessShareLock); +} + +/* + * ALTER INDEX i1 ATTACH PARTITION i2 + */ +ObjectAddress +ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx, RangeVar *name) +{ + Relation partIdx; + Relation partTbl; + Relation parentTbl; + ObjectAddress address; + Oid partIdxId; + Oid currParent; + struct AttachIndexCallbackState state; + + /* + * We need to obtain lock on the index 'name' to modify it, but we also + * need to read its owning table's tuple descriptor -- so we need to lock + * both. To avoid deadlocks, obtain lock on the table before doing so on + * the index. Furthermore, we need to examine the parent table of the + * partition, so lock that one too. + */ + state.partitionOid = InvalidOid; + state.parentTblOid = parentIdx->rd_index->indrelid; + state.lockedParentTbl = false; + partIdxId = + RangeVarGetRelidExtended(name, AccessExclusiveLock, 0, + RangeVarCallbackForAttachIndex, + &state); + /* Not there? */ + if (!OidIsValid(partIdxId)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("index \"%s\" does not exist", name->relname))); + + /* no deadlock risk: RangeVarGetRelidExtended already acquired the lock */ + partIdx = relation_open(partIdxId, AccessExclusiveLock); + + /* we already hold locks on both tables, so this is safe: */ + parentTbl = relation_open(parentIdx->rd_index->indrelid, AccessShareLock); + partTbl = relation_open(partIdx->rd_index->indrelid, NoLock); + + ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partIdx)); + + /* Silently do nothing if already in the right state */ + currParent = partIdx->rd_rel->relispartition ? + get_partition_parent(partIdxId, false) : InvalidOid; + if (currParent != RelationGetRelid(parentIdx)) + { + IndexInfo *childInfo; + IndexInfo *parentInfo; + AttrMap *attmap; + bool found; + int i; + PartitionDesc partDesc; + Oid constraintOid, + cldConstrId = InvalidOid; + + /* + * If this partition already has an index attached, refuse the + * operation. + */ + refuseDupeIndexAttach(parentIdx, partIdx, partTbl); + + if (OidIsValid(currParent)) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("cannot attach index \"%s\" as a partition of index \"%s\"", + RelationGetRelationName(partIdx), + RelationGetRelationName(parentIdx)), + errdetail("Index \"%s\" is already attached to another index.", + RelationGetRelationName(partIdx)))); + + /* Make sure it indexes a partition of the other index's table */ + partDesc = RelationGetPartitionDesc(parentTbl, true); + found = false; + for (i = 0; i < partDesc->nparts; i++) + { + if (partDesc->oids[i] == state.partitionOid) + { + found = true; + break; + } + } + if (!found) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("cannot attach index \"%s\" as a partition of index \"%s\"", + RelationGetRelationName(partIdx), + RelationGetRelationName(parentIdx)), + errdetail("Index \"%s\" is not an index on any partition of table \"%s\".", + RelationGetRelationName(partIdx), + RelationGetRelationName(parentTbl)))); + + /* Ensure the indexes are compatible */ + childInfo = BuildIndexInfo(partIdx); + parentInfo = BuildIndexInfo(parentIdx); + attmap = build_attrmap_by_name(RelationGetDescr(partTbl), + RelationGetDescr(parentTbl), + false); + if (!CompareIndexInfo(childInfo, parentInfo, + partIdx->rd_indcollation, + parentIdx->rd_indcollation, + partIdx->rd_opfamily, + parentIdx->rd_opfamily, + attmap)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("cannot attach index \"%s\" as a partition of index \"%s\"", + RelationGetRelationName(partIdx), + RelationGetRelationName(parentIdx)), + errdetail("The index definitions do not match."))); + + /* + * If there is a constraint in the parent, make sure there is one in + * the child too. + */ + constraintOid = get_relation_idx_constraint_oid(RelationGetRelid(parentTbl), + RelationGetRelid(parentIdx)); + + if (OidIsValid(constraintOid)) + { + cldConstrId = get_relation_idx_constraint_oid(RelationGetRelid(partTbl), + partIdxId); + if (!OidIsValid(cldConstrId)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("cannot attach index \"%s\" as a partition of index \"%s\"", + RelationGetRelationName(partIdx), + RelationGetRelationName(parentIdx)), + errdetail("The index \"%s\" belongs to a constraint in table \"%s\" but no constraint exists for index \"%s\".", + RelationGetRelationName(parentIdx), + RelationGetRelationName(parentTbl), + RelationGetRelationName(partIdx)))); + } + + /* + * If it's a primary key, make sure the columns in the partition are + * NOT NULL. + */ + if (parentIdx->rd_index->indisprimary) + verifyPartitionIndexNotNull(childInfo, partTbl); + + /* All good -- do it */ + IndexSetParentIndex(partIdx, RelationGetRelid(parentIdx)); + if (OidIsValid(constraintOid)) + ConstraintSetParentConstraint(cldConstrId, constraintOid, + RelationGetRelid(partTbl)); + + free_attrmap(attmap); + + validatePartitionedIndex(parentIdx, parentTbl); + } + + relation_close(parentTbl, AccessShareLock); + /* keep these locks till commit */ + relation_close(partTbl, NoLock); + relation_close(partIdx, NoLock); + + return address; +} + +/* + * Verify whether the given partition already contains an index attached + * to the given partitioned index. If so, raise an error. + */ +static void +refuseDupeIndexAttach(Relation parentIdx, Relation partIdx, Relation partitionTbl) +{ + Oid existingIdx; + + existingIdx = index_get_partition(partitionTbl, + RelationGetRelid(parentIdx)); + if (OidIsValid(existingIdx)) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("cannot attach index \"%s\" as a partition of index \"%s\"", + RelationGetRelationName(partIdx), + RelationGetRelationName(parentIdx)), + errdetail("Another index \"%s\" is already attached for partition \"%s\".", + get_rel_name(existingIdx), + RelationGetRelationName(partitionTbl)))); +} + +/* + * Verify whether the set of attached partition indexes to a parent index on + * a partitioned table is complete. If it is, mark the parent index valid. + * + * This should be called each time a partition index is attached. + */ +static void +validatePartitionedIndex(Relation partedIdx, Relation partedTbl) +{ + Relation inheritsRel; + SysScanDesc scan; + ScanKeyData key; + int tuples = 0; + HeapTuple inhTup; + bool updated = false; + + Assert(partedIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX); + + /* + * Scan pg_inherits for this parent index. Count each valid index we find + * (verifying the pg_index entry for each), and if we reach the total + * amount we expect, we can mark this parent index as valid. + */ + inheritsRel = table_open(InheritsRelationId, AccessShareLock); + ScanKeyInit(&key, Anum_pg_inherits_inhparent, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelationGetRelid(partedIdx))); + scan = systable_beginscan(inheritsRel, InheritsParentIndexId, true, + NULL, 1, &key); + while ((inhTup = systable_getnext(scan)) != NULL) + { + Form_pg_inherits inhForm = (Form_pg_inherits) GETSTRUCT(inhTup); + HeapTuple indTup; + Form_pg_index indexForm; + + indTup = SearchSysCache1(INDEXRELID, + ObjectIdGetDatum(inhForm->inhrelid)); + if (!HeapTupleIsValid(indTup)) + elog(ERROR, "cache lookup failed for index %u", inhForm->inhrelid); + indexForm = (Form_pg_index) GETSTRUCT(indTup); + if (indexForm->indisvalid) + tuples += 1; + ReleaseSysCache(indTup); + } + + /* Done with pg_inherits */ + systable_endscan(scan); + table_close(inheritsRel, AccessShareLock); + + /* + * If we found as many inherited indexes as the partitioned table has + * partitions, we're good; update pg_index to set indisvalid. + */ + if (tuples == RelationGetPartitionDesc(partedTbl, true)->nparts) + { + Relation idxRel; + HeapTuple indTup; + Form_pg_index indexForm; + + idxRel = table_open(IndexRelationId, RowExclusiveLock); + indTup = SearchSysCacheCopy1(INDEXRELID, + ObjectIdGetDatum(RelationGetRelid(partedIdx))); + if (!HeapTupleIsValid(indTup)) + elog(ERROR, "cache lookup failed for index %u", + RelationGetRelid(partedIdx)); + indexForm = (Form_pg_index) GETSTRUCT(indTup); + + indexForm->indisvalid = true; + updated = true; + + CatalogTupleUpdate(idxRel, &indTup->t_self, indTup); + + table_close(idxRel, RowExclusiveLock); + heap_freetuple(indTup); + } + + /* + * If this index is in turn a partition of a larger index, validating it + * might cause the parent to become valid also. Try that. + */ + if (updated && partedIdx->rd_rel->relispartition) + { + Oid parentIdxId, + parentTblId; + Relation parentIdx, + parentTbl; + + /* make sure we see the validation we just did */ + CommandCounterIncrement(); + + parentIdxId = get_partition_parent(RelationGetRelid(partedIdx), false); + parentTblId = get_partition_parent(RelationGetRelid(partedTbl), false); + parentIdx = relation_open(parentIdxId, AccessExclusiveLock); + parentTbl = relation_open(parentTblId, AccessExclusiveLock); + Assert(!parentIdx->rd_index->indisvalid); + + validatePartitionedIndex(parentIdx, parentTbl); + + relation_close(parentIdx, AccessExclusiveLock); + relation_close(parentTbl, AccessExclusiveLock); + } +} + +/* + * When attaching an index as a partition of a partitioned index which is a + * primary key, verify that all the columns in the partition are marked NOT + * NULL. + */ +static void +verifyPartitionIndexNotNull(IndexInfo *iinfo, Relation partition) +{ + for (int i = 0; i < iinfo->ii_NumIndexKeyAttrs; i++) + { + Form_pg_attribute att = TupleDescAttr(RelationGetDescr(partition), + iinfo->ii_IndexAttrNumbers[i] - 1); + + if (!att->attnotnull) + ereport(ERROR, + errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("invalid primary key definition"), + errdetail("Column \"%s\" of relation \"%s\" is not marked NOT NULL.", + NameStr(att->attname), + RelationGetRelationName(partition))); + } +} + +/* + * Return an OID list of constraints that reference the given relation + * that are marked as having a parent constraints. + */ +static List * +GetParentedForeignKeyRefs(Relation partition) +{ + Relation pg_constraint; + HeapTuple tuple; + SysScanDesc scan; + ScanKeyData key[2]; + List *constraints = NIL; + + /* + * If no indexes, or no columns are referenceable by FKs, we can avoid the + * scan. + */ + if (RelationGetIndexList(partition) == NIL || + bms_is_empty(RelationGetIndexAttrBitmap(partition, + INDEX_ATTR_BITMAP_KEY))) + return NIL; + + /* Search for constraints referencing this table */ + pg_constraint = table_open(ConstraintRelationId, AccessShareLock); + ScanKeyInit(&key[0], + Anum_pg_constraint_confrelid, BTEqualStrategyNumber, + F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(partition))); + ScanKeyInit(&key[1], + Anum_pg_constraint_contype, BTEqualStrategyNumber, + F_CHAREQ, CharGetDatum(CONSTRAINT_FOREIGN)); + + /* XXX This is a seqscan, as we don't have a usable index */ + scan = systable_beginscan(pg_constraint, InvalidOid, true, NULL, 2, key); + while ((tuple = systable_getnext(scan)) != NULL) + { + Form_pg_constraint constrForm = (Form_pg_constraint) GETSTRUCT(tuple); + + /* + * We only need to process constraints that are part of larger ones. + */ + if (!OidIsValid(constrForm->conparentid)) + continue; + + constraints = lappend_oid(constraints, constrForm->oid); + } + + systable_endscan(scan); + table_close(pg_constraint, AccessShareLock); + + return constraints; +} + +/* + * During DETACH PARTITION, verify that any foreign keys pointing to the + * partitioned table would not become invalid. An error is raised if any + * referenced values exist. + */ +static void +ATDetachCheckNoForeignKeyRefs(Relation partition) +{ + List *constraints; + ListCell *cell; + + constraints = GetParentedForeignKeyRefs(partition); + + foreach(cell, constraints) + { + Oid constrOid = lfirst_oid(cell); + HeapTuple tuple; + Form_pg_constraint constrForm; + Relation rel; + Trigger trig = {0}; + + tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for constraint %u", constrOid); + constrForm = (Form_pg_constraint) GETSTRUCT(tuple); + + Assert(OidIsValid(constrForm->conparentid)); + Assert(constrForm->confrelid == RelationGetRelid(partition)); + + /* prevent data changes into the referencing table until commit */ + rel = table_open(constrForm->conrelid, ShareLock); + + trig.tgoid = InvalidOid; + trig.tgname = NameStr(constrForm->conname); + trig.tgenabled = TRIGGER_FIRES_ON_ORIGIN; + trig.tgisinternal = true; + trig.tgconstrrelid = RelationGetRelid(partition); + trig.tgconstrindid = constrForm->conindid; + trig.tgconstraint = constrForm->oid; + trig.tgdeferrable = false; + trig.tginitdeferred = false; + /* we needn't fill in remaining fields */ + + RI_PartitionRemove_Check(&trig, rel, partition); + + ReleaseSysCache(tuple); + + table_close(rel, NoLock); + } +} + +/* + * buildExpressionExecutionStates: build the needed expression execution states + * for new partition (newPartRel) checks and initialize expressions for + * generated columns. All expressions should be created in "tab" + * (AlteredTableInfo structure). + */ +static void +buildExpressionExecutionStates(AlteredTableInfo *tab, Relation newPartRel, EState *estate) +{ + /* + * Build the needed expression execution states. Here, we expect only NOT + * NULL and CHECK constraint. + */ + foreach_ptr(NewConstraint, con, tab->constraints) + { + switch (con->contype) + { + case CONSTR_CHECK: + + /* + * We already expanded virtual expression in + * createTableConstraints. + */ + con->qualstate = ExecPrepareExpr((Expr *) con->qual, estate); + break; + case CONSTR_NOTNULL: + /* Nothing to do here. */ + break; + default: + elog(ERROR, "unrecognized constraint type: %d", + (int) con->contype); + } + } + + /* Expression already planned in createTableConstraints */ + foreach_ptr(NewColumnValue, ex, tab->newvals) + ex->exprstate = ExecInitExpr((Expr *) ex->expr, NULL); +} + +/* + * evaluateGeneratedExpressionsAndCheckConstraints: evaluate any generated + * expressions for "tab" (AlteredTableInfo structure) whose inputs come from + * the new tuple (insertslot) of the new partition (newPartRel). + */ +static void +evaluateGeneratedExpressionsAndCheckConstraints(AlteredTableInfo *tab, + Relation newPartRel, + TupleTableSlot *insertslot, + ExprContext *econtext) +{ + econtext->ecxt_scantuple = insertslot; + + foreach_ptr(NewColumnValue, ex, tab->newvals) + { + if (!ex->is_generated) + continue; + + insertslot->tts_values[ex->attnum - 1] + = ExecEvalExpr(ex->exprstate, + econtext, + &insertslot->tts_isnull[ex->attnum - 1]); + } + + foreach_ptr(NewConstraint, con, tab->constraints) + { + switch (con->contype) + { + case CONSTR_CHECK: + if (!ExecCheck(con->qualstate, econtext)) + ereport(ERROR, + errcode(ERRCODE_CHECK_VIOLATION), + errmsg("check constraint \"%s\" of relation \"%s\" is violated by some row", + con->name, RelationGetRelationName(newPartRel)), + errtableconstraint(newPartRel, con->name)); + break; + case CONSTR_NOTNULL: + case CONSTR_FOREIGN: + /* Nothing to do here */ + break; + default: + elog(ERROR, "unrecognized constraint type: %d", + (int) con->contype); + } + } +} + +/* + * getAttributesList: build a list of columns (ColumnDef) based on parent_rel + */ +static List * +getAttributesList(Relation parent_rel) +{ + AttrNumber parent_attno; + TupleDesc modelDesc; + List *colList = NIL; + + modelDesc = RelationGetDescr(parent_rel); + + for (parent_attno = 1; parent_attno <= modelDesc->natts; + parent_attno++) + { + Form_pg_attribute attribute = TupleDescAttr(modelDesc, + parent_attno - 1); + ColumnDef *def; + + /* Ignore dropped columns in the parent. */ + if (attribute->attisdropped) + continue; + + def = makeColumnDef(NameStr(attribute->attname), attribute->atttypid, + attribute->atttypmod, attribute->attcollation); + + def->is_not_null = attribute->attnotnull; + + /* Copy identity. */ + def->identity = attribute->attidentity; + + /* Copy attgenerated. */ + def->generated = attribute->attgenerated; + + def->storage = attribute->attstorage; + + /* Likewise, copy compression. */ + if (CompressionMethodIsValid(attribute->attcompression)) + def->compression = + pstrdup(GetCompressionMethodName(attribute->attcompression)); + else + def->compression = NULL; + + /* Add to column list. */ + colList = lappend(colList, def); + } + + return colList; +} + +/* + * createTableConstraints: + * create check constraints, default values, and generated values for newRel + * based on parent_rel. tab is pending-work queue for newRel, we may need it in + * MergePartitionsMoveRows. + */ +static void +createTableConstraints(List **wqueue, AlteredTableInfo *tab, + Relation parent_rel, Relation newRel) +{ + TupleDesc tupleDesc; + TupleConstr *constr; + AttrMap *attmap; + AttrNumber parent_attno; + int ccnum; + List *constraints = NIL; + List *cookedConstraints = NIL; + + tupleDesc = RelationGetDescr(parent_rel); + constr = tupleDesc->constr; + + if (!constr) + return; + + /* + * Construct a map from the parent relation's attnos to the child rel's. + * This re-checks type match, etc, although it shouldn't be possible to + * have a failure since both tables are locked. + */ + attmap = build_attrmap_by_name(RelationGetDescr(newRel), + tupleDesc, + false); + + /* Cycle for default values. */ + for (parent_attno = 1; parent_attno <= tupleDesc->natts; parent_attno++) + { + Form_pg_attribute attribute = TupleDescAttr(tupleDesc, + parent_attno - 1); + + /* Ignore dropped columns in the parent. */ + if (attribute->attisdropped) + continue; + + /* Copy the default, if present, and it should be copied. */ + if (attribute->atthasdef) + { + Node *this_default = NULL; + bool found_whole_row; + AttrNumber num; + Node *def; + NewColumnValue *newval; + + if (attribute->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL) + this_default = build_generation_expression(parent_rel, attribute->attnum); + else + { + this_default = TupleDescGetDefault(tupleDesc, attribute->attnum); + if (this_default == NULL) + elog(ERROR, "default expression not found for attribute %d of relation \"%s\"", + attribute->attnum, RelationGetRelationName(parent_rel)); + } + + num = attmap->attnums[parent_attno - 1]; + def = map_variable_attnos(this_default, 1, 0, attmap, InvalidOid, &found_whole_row); + + if (found_whole_row && attribute->attgenerated != '\0') + elog(ERROR, "cannot convert whole-row table reference"); + + /* Add a pre-cooked default expression. */ + StoreAttrDefault(newRel, num, def, true); + + /* + * Stored generated column expressions in parent_rel might + * reference the tableoid. newRel, parent_rel tableoid clear is + * not the same. If so, these stored generated columns require + * recomputation for newRel within MergePartitionsMoveRows. + */ + if (attribute->attgenerated == ATTRIBUTE_GENERATED_STORED) + { + newval = palloc0_object(NewColumnValue); + newval->attnum = num; + newval->expr = expression_planner((Expr *) def); + newval->is_generated = (attribute->attgenerated != '\0'); + tab->newvals = lappend(tab->newvals, newval); + } + } + } + + /* Cycle for CHECK constraints. */ + for (ccnum = 0; ccnum < constr->num_check; ccnum++) + { + char *ccname = constr->check[ccnum].ccname; + char *ccbin = constr->check[ccnum].ccbin; + bool ccenforced = constr->check[ccnum].ccenforced; + bool ccnoinherit = constr->check[ccnum].ccnoinherit; + bool ccvalid = constr->check[ccnum].ccvalid; + Node *ccbin_node; + bool found_whole_row; + Constraint *constr; + + /* + * The partitioned table can not have a NO INHERIT check constraint + * (see StoreRelCheck function for details). + */ + Assert(!ccnoinherit); + + ccbin_node = map_variable_attnos(stringToNode(ccbin), + 1, 0, + attmap, + InvalidOid, &found_whole_row); + + /* + * For the moment we have to reject whole-row variables (as for CREATE + * TABLE LIKE and inheritances). + */ + if (found_whole_row) + elog(ERROR, "Constraint \"%s\" contains a whole-row reference to table \"%s\".", + ccname, + RelationGetRelationName(parent_rel)); + + constr = makeNode(Constraint); + constr->contype = CONSTR_CHECK; + constr->conname = pstrdup(ccname); + constr->deferrable = false; + constr->initdeferred = false; + constr->is_enforced = ccenforced; + constr->skip_validation = !ccvalid; + constr->initially_valid = ccvalid; + constr->is_no_inherit = ccnoinherit; + constr->raw_expr = NULL; + constr->cooked_expr = nodeToString(ccbin_node); + constr->location = -1; + constraints = lappend(constraints, constr); + } + + /* Install all CHECK constraints. */ + cookedConstraints = AddRelationNewConstraints(newRel, NIL, constraints, + false, true, true, NULL); + + /* Make the additional catalog changes visible. */ + CommandCounterIncrement(); + + /* + * parent_rel check constraint expression may reference tableoid, so later + * in MergePartitionsMoveRows, we need to evaluate the check constraint + * again for the newRel. We can check whether the check constraint + * contains a tableoid reference via pull_varattnos. + */ + foreach_ptr(CookedConstraint, ccon, cookedConstraints) + { + if (!ccon->skip_validation) + { + Node *qual; + Bitmapset *attnums = NULL; + + Assert(ccon->contype == CONSTR_CHECK); + qual = expand_generated_columns_in_expr(ccon->expr, newRel, 1); + pull_varattnos(qual, 1, &attnums); + + /* + * Add a check only if it contains a tableoid + * (TableOidAttributeNumber). + */ + if (bms_is_member(TableOidAttributeNumber - FirstLowInvalidHeapAttributeNumber, + attnums)) + { + NewConstraint *newcon; + + newcon = palloc0_object(NewConstraint); + newcon->name = ccon->name; + newcon->contype = CONSTR_CHECK; + newcon->qual = qual; + + tab->constraints = lappend(tab->constraints, newcon); + } + } + } + + /* Don't need the cookedConstraints anymore. */ + list_free_deep(cookedConstraints); + + /* Reproduce not-null constraints. */ + if (constr->has_not_null) + { + List *nnconstraints; + + /* + * The "include_noinh" argument is false because a partitioned table + * can't have NO INHERIT constraint. + */ + nnconstraints = RelationGetNotNullConstraints(RelationGetRelid(parent_rel), + false, false); + + Assert(list_length(nnconstraints) > 0); + + /* + * We already set pg_attribute.attnotnull in createPartitionTable. No + * need call set_attnotnull again. + */ + AddRelationNewConstraints(newRel, NIL, nnconstraints, false, true, true, NULL); + } +} + +/* + * createPartitionTable: + * + * Create a new partition (newPartName) for the partitioned table (parent_rel). + * ownerId is determined by the partition on which the operation is performed, + * so it is passed separately. The new partition will inherit the access method + * and persistence type from the parent table. + * + * Returns the created relation (locked in AccessExclusiveLock mode). + */ +static Relation +createPartitionTable(List **wqueue, RangeVar *newPartName, + Relation parent_rel, Oid ownerId) +{ + Relation newRel; + Oid newRelId; + Oid existingRelid; + TupleDesc descriptor; + List *colList = NIL; + Oid relamId; + Oid namespaceId; + AlteredTableInfo *new_partrel_tab; + Form_pg_class parent_relform = parent_rel->rd_rel; + + /* If the existing rel is temp, it must belong to this session. */ + if (RELATION_IS_OTHER_TEMP(parent_rel)) + ereport(ERROR, + errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot create as partition of temporary relation of another session")); + + /* Look up inheritance ancestors and generate the relation schema. */ + colList = getAttributesList(parent_rel); + + /* Create a tuple descriptor from the relation schema. */ + descriptor = BuildDescForRelation(colList); + + /* Look up the access method for the new relation. */ + relamId = (parent_relform->relam != InvalidOid) ? parent_relform->relam : HEAP_TABLE_AM_OID; + + /* Look up the namespace in which we are supposed to create the relation. */ + namespaceId = + RangeVarGetAndCheckCreationNamespace(newPartName, NoLock, &existingRelid); + if (OidIsValid(existingRelid)) + ereport(ERROR, + errcode(ERRCODE_DUPLICATE_TABLE), + errmsg("relation \"%s\" already exists", newPartName->relname)); + + /* + * We intended to create the partition with the same persistence as the + * parent table, but we still need to recheck because that might be + * affected by the search_path. If the parent is permanent, so must be + * all of its partitions. + */ + if (parent_relform->relpersistence != RELPERSISTENCE_TEMP && + newPartName->relpersistence == RELPERSISTENCE_TEMP) + ereport(ERROR, + errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot create a temporary relation as partition of permanent relation \"%s\"", + RelationGetRelationName(parent_rel))); + + /* Permanent rels cannot be partitions belonging to a temporary parent. */ + if (newPartName->relpersistence != RELPERSISTENCE_TEMP && + parent_relform->relpersistence == RELPERSISTENCE_TEMP) + ereport(ERROR, + errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot create a permanent relation as partition of temporary relation \"%s\"", + RelationGetRelationName(parent_rel))); + + /* Create the relation. */ + newRelId = heap_create_with_catalog(newPartName->relname, + namespaceId, + parent_relform->reltablespace, + InvalidOid, + InvalidOid, + InvalidOid, + ownerId, + relamId, + descriptor, + NIL, + RELKIND_RELATION, + newPartName->relpersistence, + false, + false, + ONCOMMIT_NOOP, + (Datum) 0, + true, + allowSystemTableMods, + true, + InvalidOid, + NULL); + + /* + * We must bump the command counter to make the newly-created relation + * tuple visible for opening. + */ + CommandCounterIncrement(); + + /* + * Open the new partition with no lock, because we already have an + * AccessExclusiveLock placed there after creation. + */ + newRel = table_open(newRelId, NoLock); + + /* Find or create a work queue entry for the newly created table. */ + new_partrel_tab = ATGetQueueEntry(wqueue, newRel); + + /* Create constraints, default values, and generated values. */ + createTableConstraints(wqueue, new_partrel_tab, parent_rel, newRel); + + /* + * Need to call CommandCounterIncrement, so a fresh relcache entry has + * newly installed constraint info. + */ + CommandCounterIncrement(); + + return newRel; +} + +/* + * MergePartitionsMoveRows: scan partitions to be merged (mergingPartitions) + * of the partitioned table and move rows into the new partition + * (newPartRel). We also verify check constraints against these rows. + */ +static void +MergePartitionsMoveRows(List **wqueue, List *mergingPartitions, Relation newPartRel) +{ + CommandId mycid; + EState *estate; + AlteredTableInfo *tab; + ListCell *ltab; + + /* The FSM is empty, so don't bother using it. */ + int ti_options = TABLE_INSERT_SKIP_FSM; + BulkInsertState bistate; /* state of bulk inserts for partition */ + TupleTableSlot *dstslot; + + /* Find the work queue entry for the new partition table: newPartRel. */ + tab = ATGetQueueEntry(wqueue, newPartRel); + + /* Generate the constraint and default execution states. */ + estate = CreateExecutorState(); + + buildExpressionExecutionStates(tab, newPartRel, estate); + + mycid = GetCurrentCommandId(true); + + /* Prepare a BulkInsertState for table_tuple_insert. */ + bistate = GetBulkInsertState(); + + /* Create the necessary tuple slot. */ + dstslot = table_slot_create(newPartRel, NULL); + + foreach_oid(merging_oid, mergingPartitions) + { + ExprContext *econtext; + TupleTableSlot *srcslot; + TupleConversionMap *tuple_map; + TableScanDesc scan; + MemoryContext oldCxt; + Snapshot snapshot; + Relation mergingPartition; + + econtext = GetPerTupleExprContext(estate); + + /* + * Partition is already locked in the transformPartitionCmdForMerge + * function. + */ + mergingPartition = table_open(merging_oid, NoLock); + + /* Create a source tuple slot for the partition being merged. */ + srcslot = table_slot_create(mergingPartition, NULL); + + /* + * Map computing for moving attributes of the merged partition to the + * new partition. + */ + tuple_map = convert_tuples_by_name(RelationGetDescr(mergingPartition), + RelationGetDescr(newPartRel)); + + /* Scan through the rows. */ + snapshot = RegisterSnapshot(GetLatestSnapshot()); + scan = table_beginscan(mergingPartition, snapshot, 0, NULL); + + /* + * Switch to per-tuple memory context and reset it for each tuple + * produced, so we don't leak memory. + */ + oldCxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); + + while (table_scan_getnextslot(scan, ForwardScanDirection, srcslot)) + { + TupleTableSlot *insertslot; + + CHECK_FOR_INTERRUPTS(); + + if (tuple_map) + { + /* Need to use a map to copy attributes. */ + insertslot = execute_attr_map_slot(tuple_map->attrMap, srcslot, dstslot); + } + else + { + slot_getallattrs(srcslot); + + /* Copy attributes directly. */ + insertslot = dstslot; + + ExecClearTuple(insertslot); + + memcpy(insertslot->tts_values, srcslot->tts_values, + sizeof(Datum) * srcslot->tts_nvalid); + memcpy(insertslot->tts_isnull, srcslot->tts_isnull, + sizeof(bool) * srcslot->tts_nvalid); + + ExecStoreVirtualTuple(insertslot); + } + + /* + * Constraints and GENERATED expressions might reference the + * tableoid column, so fill tts_tableOid with the desired value. + * (We must do this each time, because it gets overwritten with + * newrel's OID during storing.) + */ + insertslot->tts_tableOid = RelationGetRelid(newPartRel); + + /* + * Now, evaluate any generated expressions whose inputs come from + * the new tuple. We assume these columns won't reference each + * other, so that there's no ordering dependency. + */ + evaluateGeneratedExpressionsAndCheckConstraints(tab, newPartRel, + insertslot, econtext); + + /* Write the tuple out to the new relation. */ + table_tuple_insert(newPartRel, insertslot, mycid, + ti_options, bistate); + + ResetExprContext(econtext); + } + + MemoryContextSwitchTo(oldCxt); + table_endscan(scan); + UnregisterSnapshot(snapshot); + + if (tuple_map) + free_conversion_map(tuple_map); + + ExecDropSingleTupleTableSlot(srcslot); + table_close(mergingPartition, NoLock); + } + + FreeExecutorState(estate); + ExecDropSingleTupleTableSlot(dstslot); + FreeBulkInsertState(bistate); + + table_finish_bulk_insert(newPartRel, ti_options); + + /* + * We don't need to process this newPartRel since we already processed it + * here, so delete the ALTER TABLE queue for it. + */ + foreach(ltab, *wqueue) + { + tab = (AlteredTableInfo *) lfirst(ltab); + if (tab->relid == RelationGetRelid(newPartRel)) + { + *wqueue = list_delete_cell(*wqueue, ltab); + break; + } + } +} + +/* + * detachPartitionTable: detach partition "child_rel" from partitioned table + * "parent_rel" with default partition identifier "defaultPartOid" + */ +static void +detachPartitionTable(Relation parent_rel, Relation child_rel, Oid defaultPartOid) +{ + /* Remove the pg_inherits row first. */ + RemoveInheritance(child_rel, parent_rel, false); + + /* + * Detaching the partition might involve TOAST table access, so ensure we + * have a valid snapshot. + */ + PushActiveSnapshot(GetTransactionSnapshot()); + + /* Do the final part of detaching. */ + DetachPartitionFinalize(parent_rel, child_rel, false, defaultPartOid); + + PopActiveSnapshot(); +} + +/* + * ALTER TABLE <name> MERGE PARTITIONS <partition-list> INTO <partition-name> + */ +void +ATExecMergePartitions(List **wqueue, AlteredTableInfo *tab, Relation rel, + PartitionCmd *cmd, AlterTableUtilityContext *context) +{ + Relation newPartRel; + List *mergingPartitions = NIL; + Oid defaultPartOid; + Oid existingRelid; + Oid ownerId = InvalidOid; + Oid save_userid; + int save_sec_context; + int save_nestlevel; + + /* + * Check ownership of merged partitions - partitions with different owners + * cannot be merged. Also, collect the OIDs of these partitions during the + * check. + */ + foreach_node(RangeVar, name, cmd->partlist) + { + Relation mergingPartition; + + /* + * We are going to detach and remove this partition. We already took + * AccessExclusiveLock lock on transformPartitionCmdForMerge, so here, + * NoLock is fine. + */ + mergingPartition = table_openrv_extended(name, NoLock, false); + Assert(CheckRelationLockedByMe(mergingPartition, AccessExclusiveLock, false)); + + if (OidIsValid(ownerId)) + { + /* Do the partitions being merged have different owners? */ + if (ownerId != mergingPartition->rd_rel->relowner) + ereport(ERROR, + errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("partitions being merged have different owners")); + } + else + ownerId = mergingPartition->rd_rel->relowner; + + /* Store the next merging partition into the list. */ + mergingPartitions = lappend_oid(mergingPartitions, + RelationGetRelid(mergingPartition)); + + table_close(mergingPartition, NoLock); + } + + /* Look up the existing relation by the new partition name. */ + RangeVarGetAndCheckCreationNamespace(cmd->name, NoLock, &existingRelid); + + /* + * Check if this name is already taken. This helps us to detect the + * situation when one of the merging partitions has the same name as the + * new partition. Otherwise, this would fail later on anyway, but + * catching this here allows us to emit a nicer error message. + */ + if (OidIsValid(existingRelid)) + { + if (list_member_oid(mergingPartitions, existingRelid)) + { + /* + * The new partition has the same name as one of the merging + * partitions. + */ + char tmpRelName[NAMEDATALEN]; + + /* Generate a temporary name. */ + sprintf(tmpRelName, "merge-%u-%X-tmp", RelationGetRelid(rel), MyProcPid); + + /* + * Rename the existing partition with a temporary name, leaving it + * free for the new partition. We don't need to care about this + * in the future because we're going to eventually drop the + * existing partition anyway. + */ + RenameRelationInternal(existingRelid, tmpRelName, true, false); + + /* + * We must bump the command counter to make the new partition + * tuple visible for rename. + */ + CommandCounterIncrement(); + } + else + { + ereport(ERROR, + errcode(ERRCODE_DUPLICATE_TABLE), + errmsg("relation \"%s\" already exists", cmd->name->relname)); + } + } + + defaultPartOid = + get_default_oid_from_partdesc(RelationGetPartitionDesc(rel, true)); + + /* Detach all merging partitions. */ + foreach_oid(mergingPartitionOid, mergingPartitions) + { + Relation child_rel; + + child_rel = table_open(mergingPartitionOid, NoLock); + + detachPartitionTable(rel, child_rel, defaultPartOid); + + table_close(child_rel, NoLock); + } + + /* + * Perform a preliminary check to determine whether it's safe to drop all + * merging partitions before we actually do so later. After merging rows + * into the new partitions via MergePartitionsMoveRows, all old partitions + * need to be dropped. However, since the drop behavior is DROP_RESTRICT + * and the merge process (MergePartitionsMoveRows) can be time-consuming, + * performing an early check on the drop eligibility of old partitions is + * preferable. + */ + foreach_oid(mergingPartitionOid, mergingPartitions) + { + ObjectAddress object; + + /* Get oid of the later to be dropped relation. */ + object.objectId = mergingPartitionOid; + object.classId = RelationRelationId; + object.objectSubId = 0; + + performDeletionCheck(&object, DROP_RESTRICT, PERFORM_DELETION_INTERNAL); + } + + /* + * Create a table for the new partition, using the partitioned table as a + * model. + */ + Assert(OidIsValid(ownerId)); + newPartRel = createPartitionTable(wqueue, cmd->name, rel, ownerId); + + /* + * Switch to the table owner's userid, so that any index functions are run + * as that user. Also, lockdown security-restricted operations and + * arrange to make GUC variable changes local to this command. + * + * Need to do it after determining the namespace in the + * createPartitionTable() call. + */ + GetUserIdAndSecContext(&save_userid, &save_sec_context); + SetUserIdAndSecContext(ownerId, + save_sec_context | SECURITY_RESTRICTED_OPERATION); + save_nestlevel = NewGUCNestLevel(); + RestrictSearchPath(); + + /* Copy data from merged partitions to the new partition. */ + MergePartitionsMoveRows(wqueue, mergingPartitions, newPartRel); + + /* Drop the current partitions before attaching the new one. */ + foreach_oid(mergingPartitionOid, mergingPartitions) + { + ObjectAddress object; + + object.objectId = mergingPartitionOid; + object.classId = RelationRelationId; + object.objectSubId = 0; + + performDeletion(&object, DROP_RESTRICT, 0); + } + + list_free(mergingPartitions); + + /* + * Attach a new partition to the partitioned table. wqueue = NULL: + * verification for each cloned constraint is not needed. + */ + attachPartitionTable(NULL, rel, newPartRel, cmd->bound); + + /* Keep the lock until commit. */ + table_close(newPartRel, NoLock); + + /* Roll back any GUC changes executed by index functions. */ + AtEOXact_GUC(false, save_nestlevel); + + /* Restore the userid and security context. */ + SetUserIdAndSecContext(save_userid, save_sec_context); +} + +/* + * Struct with the context of the new partition for inserting rows from the + * split partition. + */ +typedef struct SplitPartitionContext +{ + ExprState *partqualstate; /* expression for checking a slot for a + * partition (NULL for DEFAULT partition) */ + BulkInsertState bistate; /* state of bulk inserts for partition */ + TupleTableSlot *dstslot; /* slot for inserting row into partition */ + AlteredTableInfo *tab; /* structure with generated column expressions + * and check constraint expressions. */ + Relation partRel; /* relation for partition */ +} SplitPartitionContext; + +/* + * createSplitPartitionContext: create context for partition and fill it + */ +static SplitPartitionContext * +createSplitPartitionContext(Relation partRel) +{ + SplitPartitionContext *pc; + + pc = palloc0_object(SplitPartitionContext); + pc->partRel = partRel; + + /* + * Prepare a BulkInsertState for table_tuple_insert. The FSM is empty, so + * don't bother using it. + */ + pc->bistate = GetBulkInsertState(); + + /* Create a destination tuple slot for the new partition. */ + pc->dstslot = table_slot_create(pc->partRel, NULL); + + return pc; +} + +/* + * deleteSplitPartitionContext: delete context for partition + */ +static void +deleteSplitPartitionContext(SplitPartitionContext *pc, List **wqueue, int ti_options) +{ + ListCell *ltab; + + ExecDropSingleTupleTableSlot(pc->dstslot); + FreeBulkInsertState(pc->bistate); + + table_finish_bulk_insert(pc->partRel, ti_options); + + /* + * We don't need to process this pc->partRel so delete the ALTER TABLE + * queue of it. + */ + foreach(ltab, *wqueue) + { + AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab); + + if (tab->relid == RelationGetRelid(pc->partRel)) + { + *wqueue = list_delete_cell(*wqueue, ltab); + break; + } + } + + pfree(pc); +} + +/* + * SplitPartitionMoveRows: scan split partition (splitRel) of partitioned table + * (rel) and move rows into new partitions. + * + * New partitions description: + * partlist: list of pointers to SinglePartitionSpec structures. It contains + * the partition specification details for all new partitions. + * newPartRels: list of Relations, new partitions created in + * ATExecSplitPartition. + */ +static void +SplitPartitionMoveRows(List **wqueue, Relation rel, Relation splitRel, + List *partlist, List *newPartRels) +{ + /* The FSM is empty, so don't bother using it. */ + int ti_options = TABLE_INSERT_SKIP_FSM; + CommandId mycid; + EState *estate; + ListCell *listptr, + *listptr2; + TupleTableSlot *srcslot; + ExprContext *econtext; + TableScanDesc scan; + Snapshot snapshot; + MemoryContext oldCxt; + List *partContexts = NIL; + TupleConversionMap *tuple_map; + SplitPartitionContext *defaultPartCtx = NULL, + *pc; + + mycid = GetCurrentCommandId(true); + + estate = CreateExecutorState(); + + forboth(listptr, partlist, listptr2, newPartRels) + { + SinglePartitionSpec *sps = (SinglePartitionSpec *) lfirst(listptr); + + pc = createSplitPartitionContext((Relation) lfirst(listptr2)); + + /* Find the work queue entry for the new partition table: newPartRel. */ + pc->tab = ATGetQueueEntry(wqueue, pc->partRel); + + buildExpressionExecutionStates(pc->tab, pc->partRel, estate); + + if (sps->bound->is_default) + { + /* + * We should not create a structure to check the partition + * constraint for the new DEFAULT partition. + */ + defaultPartCtx = pc; + } + else + { + List *partConstraint; + + /* Build expression execution states for partition check quals. */ + partConstraint = get_qual_from_partbound(rel, sps->bound); + partConstraint = + (List *) eval_const_expressions(NULL, + (Node *) partConstraint); + /* Make a boolean expression for ExecCheck(). */ + partConstraint = list_make1(make_ands_explicit(partConstraint)); + + /* + * Map the vars in the constraint expression from rel's attnos to + * splitRel's. + */ + partConstraint = map_partition_varattnos(partConstraint, + 1, splitRel, rel); + + pc->partqualstate = + ExecPrepareExpr((Expr *) linitial(partConstraint), estate); + Assert(pc->partqualstate != NULL); + } + + /* Store partition context into a list. */ + partContexts = lappend(partContexts, pc); + } + + econtext = GetPerTupleExprContext(estate); + + /* Create the necessary tuple slot. */ + srcslot = table_slot_create(splitRel, NULL); + + /* + * Map computing for moving attributes of the split partition to the new + * partition (for the first new partition, but other new partitions can + * use the same map). + */ + pc = (SplitPartitionContext *) lfirst(list_head(partContexts)); + tuple_map = convert_tuples_by_name(RelationGetDescr(splitRel), + RelationGetDescr(pc->partRel)); + + /* Scan through the rows. */ + snapshot = RegisterSnapshot(GetLatestSnapshot()); + scan = table_beginscan(splitRel, snapshot, 0, NULL); + + /* + * Switch to per-tuple memory context and reset it for each tuple + * produced, so we don't leak memory. + */ + oldCxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); + + while (table_scan_getnextslot(scan, ForwardScanDirection, srcslot)) + { + bool found = false; + TupleTableSlot *insertslot; + + CHECK_FOR_INTERRUPTS(); + + econtext->ecxt_scantuple = srcslot; + + /* Search partition for the current slot, srcslot. */ + foreach(listptr, partContexts) + { + pc = (SplitPartitionContext *) lfirst(listptr); + + /* skip DEFAULT partition */ + if (pc->partqualstate && ExecCheck(pc->partqualstate, econtext)) + { + found = true; + break; + } + } + if (!found) + { + /* Use the DEFAULT partition if it exists. */ + if (defaultPartCtx) + pc = defaultPartCtx; + else + ereport(ERROR, + errcode(ERRCODE_CHECK_VIOLATION), + errmsg("can not find partition for split partition row"), + errtable(splitRel)); + } + + if (tuple_map) + { + /* Need to use a map to copy attributes. */ + insertslot = execute_attr_map_slot(tuple_map->attrMap, srcslot, pc->dstslot); + } + else + { + /* Extract data from the old tuple. */ + slot_getallattrs(srcslot); + + /* Copy attributes directly. */ + insertslot = pc->dstslot; + + ExecClearTuple(insertslot); + + memcpy(insertslot->tts_values, srcslot->tts_values, + sizeof(Datum) * srcslot->tts_nvalid); + memcpy(insertslot->tts_isnull, srcslot->tts_isnull, + sizeof(bool) * srcslot->tts_nvalid); + + ExecStoreVirtualTuple(insertslot); + } + + /* + * Constraints and GENERATED expressions might reference the tableoid + * column, so fill tts_tableOid with the desired value. (We must do + * this each time, because it gets overwritten with newrel's OID + * during storing.) + */ + insertslot->tts_tableOid = RelationGetRelid(pc->partRel); + + /* + * Now, evaluate any generated expressions whose inputs come from the + * new tuple. We assume these columns won't reference each other, so + * that there's no ordering dependency. + */ + evaluateGeneratedExpressionsAndCheckConstraints(pc->tab, pc->partRel, + insertslot, econtext); + + /* Write the tuple out to the new relation. */ + table_tuple_insert(pc->partRel, insertslot, mycid, + ti_options, pc->bistate); + + ResetExprContext(econtext); + } + + MemoryContextSwitchTo(oldCxt); + + table_endscan(scan); + UnregisterSnapshot(snapshot); + + if (tuple_map) + free_conversion_map(tuple_map); + + ExecDropSingleTupleTableSlot(srcslot); + + FreeExecutorState(estate); + + foreach_ptr(SplitPartitionContext, spc, partContexts) + deleteSplitPartitionContext(spc, wqueue, ti_options); +} + +/* + * ALTER TABLE <name> SPLIT PARTITION <partition-name> INTO <partition-list> + */ +void +ATExecSplitPartition(List **wqueue, AlteredTableInfo *tab, Relation rel, + PartitionCmd *cmd, AlterTableUtilityContext *context) +{ + Relation splitRel; + Oid splitRelOid; + ListCell *listptr, + *listptr2; + bool isSameName = false; + char tmpRelName[NAMEDATALEN]; + List *newPartRels = NIL; + ObjectAddress object; + Oid defaultPartOid; + Oid save_userid; + int save_sec_context; + int save_nestlevel; + + defaultPartOid = get_default_oid_from_partdesc(RelationGetPartitionDesc(rel, true)); + + /* + * Partition is already locked in the transformPartitionCmdForSplit + * function. + */ + splitRel = table_openrv(cmd->name, NoLock); + + splitRelOid = RelationGetRelid(splitRel); + + /* Check descriptions of new partitions. */ + foreach_node(SinglePartitionSpec, sps, cmd->partlist) + { + Oid existingRelid; + + /* Look up the existing relation by the new partition name. */ + RangeVarGetAndCheckCreationNamespace(sps->name, NoLock, &existingRelid); + + /* + * This would fail later on anyway if the relation already exists. But + * by catching it here, we can emit a nicer error message. + */ + if (existingRelid == splitRelOid && !isSameName) + /* One new partition can have the same name as a split partition. */ + isSameName = true; + else if (OidIsValid(existingRelid)) + ereport(ERROR, + errcode(ERRCODE_DUPLICATE_TABLE), + errmsg("relation \"%s\" already exists", sps->name->relname)); + } + + /* Detach the split partition. */ + detachPartitionTable(rel, splitRel, defaultPartOid); + + /* + * Perform a preliminary check to determine whether it's safe to drop the + * split partition before we actually do so later. After merging rows into + * the new partitions via SplitPartitionMoveRows, all old partitions need + * to be dropped. However, since the drop behavior is DROP_RESTRICT and + * the merge process (SplitPartitionMoveRows) can be time-consuming, + * performing an early check on the drop eligibility of old partitions is + * preferable. + */ + object.objectId = splitRelOid; + object.classId = RelationRelationId; + object.objectSubId = 0; + performDeletionCheck(&object, DROP_RESTRICT, PERFORM_DELETION_INTERNAL); + + /* + * If a new partition has the same name as the split partition, then we + * should rename the split partition to reuse its name. + */ + if (isSameName) + { + /* + * We must bump the command counter to make the split partition tuple + * visible for renaming. + */ + CommandCounterIncrement(); + /* Rename partition. */ + sprintf(tmpRelName, "split-%u-%X-tmp", RelationGetRelid(rel), MyProcPid); + RenameRelationInternal(splitRelOid, tmpRelName, true, false); + + /* + * We must bump the command counter to make the split partition tuple + * visible after renaming. + */ + CommandCounterIncrement(); + } + + /* Create new partitions (like a split partition), without indexes. */ + foreach_node(SinglePartitionSpec, sps, cmd->partlist) + { + Relation newPartRel; + + newPartRel = createPartitionTable(wqueue, sps->name, rel, + splitRel->rd_rel->relowner); + newPartRels = lappend(newPartRels, newPartRel); + } + + /* + * Switch to the table owner's userid, so that any index functions are run + * as that user. Also, lockdown security-restricted operations and + * arrange to make GUC variable changes local to this command. + * + * Need to do it after determining the namespace in the + * createPartitionTable() call. + */ + GetUserIdAndSecContext(&save_userid, &save_sec_context); + SetUserIdAndSecContext(splitRel->rd_rel->relowner, + save_sec_context | SECURITY_RESTRICTED_OPERATION); + save_nestlevel = NewGUCNestLevel(); + RestrictSearchPath(); + + /* Copy data from the split partition to the new partitions. */ + SplitPartitionMoveRows(wqueue, rel, splitRel, cmd->partlist, newPartRels); + /* Keep the lock until commit. */ + table_close(splitRel, NoLock); + + /* Attach new partitions to the partitioned table. */ + forboth(listptr, cmd->partlist, listptr2, newPartRels) + { + SinglePartitionSpec *sps = (SinglePartitionSpec *) lfirst(listptr); + Relation newPartRel = (Relation) lfirst(listptr2); + + /* + * wqueue = NULL: verification for each cloned constraint is not + * needed. + */ + attachPartitionTable(NULL, rel, newPartRel, sps->bound); + /* Keep the lock until commit. */ + table_close(newPartRel, NoLock); + } + + /* Drop the split partition. */ + object.classId = RelationRelationId; + object.objectId = splitRelOid; + object.objectSubId = 0; + /* Probably DROP_CASCADE is not needed. */ + performDeletion(&object, DROP_RESTRICT, 0); + + /* Roll back any GUC changes executed by index functions. */ + AtEOXact_GUC(false, save_nestlevel); + + /* Restore the userid and security context. */ + SetUserIdAndSecContext(save_userid, save_sec_context); +} diff --git a/src/backend/partitioning/partbounds.c b/src/backend/partitioning/partbounds.c index 0ca312ac27d..195c9f30a36 100644 --- a/src/backend/partitioning/partbounds.c +++ b/src/backend/partitioning/partbounds.c @@ -22,6 +22,7 @@ #include "catalog/pg_inherits.h" #include "catalog/pg_type.h" #include "commands/tablecmds.h" +#include "commands/tablecmds_partition.h" #include "common/hashfn.h" #include "executor/executor.h" #include "miscadmin.h" diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h index ed38b311ddf..eae0f123f54 100644 --- a/src/include/commands/tablecmds.h +++ b/src/include/commands/tablecmds.h @@ -105,7 +105,5 @@ extern void RangeVarCallbackMaintainsTable(const RangeVar *relation, extern void RangeVarCallbackOwnsRelation(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg); -extern bool PartConstraintImpliedByRelConstraint(Relation scanrel, - List *partConstraint); #endif /* TABLECMDS_H */ diff --git a/src/include/commands/tablecmds_internal.h b/src/include/commands/tablecmds_internal.h new file mode 100644 index 00000000000..4e91fe3c20e --- /dev/null +++ b/src/include/commands/tablecmds_internal.h @@ -0,0 +1,183 @@ +/*------------------------------------------------------------------------- + * + * tablecmds_internal.h + * TODO + * + * + * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/tablecmds_internal.h + * + *------------------------------------------------------------------------- + */ +#ifndef TABLECMDS_INTERNAL_H +#define TABLECMDS_INTERNAL_H + +/* + * State information for ALTER TABLE + * + * The pending-work queue for an ALTER TABLE is a List of AlteredTableInfo + * structs, one for each table modified by the operation (the named table + * plus any child tables that are affected). We save lists of subcommands + * to apply to this table (possibly modified by parse transformation steps); + * these lists will be executed in Phase 2. If a Phase 3 step is needed, + * necessary information is stored in the constraints and newvals lists. + * + * Phase 2 is divided into multiple passes; subcommands are executed in + * a pass determined by subcommand type. + */ + +typedef enum AlterTablePass +{ + AT_PASS_UNSET = -1, /* UNSET will cause ERROR */ + AT_PASS_DROP, /* DROP (all flavors) */ + AT_PASS_ALTER_TYPE, /* ALTER COLUMN TYPE */ + AT_PASS_ADD_COL, /* ADD COLUMN */ + AT_PASS_SET_EXPRESSION, /* ALTER SET EXPRESSION */ + AT_PASS_OLD_INDEX, /* re-add existing indexes */ + AT_PASS_OLD_CONSTR, /* re-add existing constraints */ + /* We could support a RENAME COLUMN pass here, but not currently used */ + AT_PASS_ADD_CONSTR, /* ADD constraints (initial examination) */ + AT_PASS_COL_ATTRS, /* set column attributes, eg NOT NULL */ + AT_PASS_ADD_INDEXCONSTR, /* ADD index-based constraints */ + AT_PASS_ADD_INDEX, /* ADD indexes */ + AT_PASS_ADD_OTHERCONSTR, /* ADD other constraints, defaults */ + AT_PASS_MISC, /* other stuff */ +} AlterTablePass; + +#define AT_NUM_PASSES (AT_PASS_MISC + 1) + +typedef struct AlteredTableInfo +{ + /* Information saved before any work commences: */ + Oid relid; /* Relation to work on */ + char relkind; /* Its relkind */ + TupleDesc oldDesc; /* Pre-modification tuple descriptor */ + + /* + * Transiently set during Phase 2, normally set to NULL. + * + * ATRewriteCatalogs sets this when it starts, and closes when ATExecCmd + * returns control. This can be exploited by ATExecCmd subroutines to + * close/reopen across transaction boundaries. + */ + Relation rel; + + /* Information saved by Phase 1 for Phase 2: */ + List *subcmds[AT_NUM_PASSES]; /* Lists of AlterTableCmd */ + /* Information saved by Phases 1/2 for Phase 3: */ + List *constraints; /* List of NewConstraint */ + List *newvals; /* List of NewColumnValue */ + List *afterStmts; /* List of utility command parsetrees */ + bool verify_new_notnull; /* T if we should recheck NOT NULL */ + int rewrite; /* Reason for forced rewrite, if any */ + bool chgAccessMethod; /* T if SET ACCESS METHOD is used */ + Oid newAccessMethod; /* new access method; 0 means no change, + * if above is true */ + Oid newTableSpace; /* new tablespace; 0 means no change */ + bool chgPersistence; /* T if SET LOGGED/UNLOGGED is used */ + char newrelpersistence; /* if above is true */ + Expr *partition_constraint; /* for attach partition validation */ + /* true, if validating default due to some other attach/detach */ + bool validate_default; + /* Objects to rebuild after completing ALTER TYPE operations */ + List *changedConstraintOids; /* OIDs of constraints to rebuild */ + List *changedConstraintDefs; /* string definitions of same */ + List *changedIndexOids; /* OIDs of indexes to rebuild */ + List *changedIndexDefs; /* string definitions of same */ + char *replicaIdentityIndex; /* index to reset as REPLICA IDENTITY */ + char *clusterOnIndex; /* index to use for CLUSTER */ + List *changedStatisticsOids; /* OIDs of statistics to rebuild */ + List *changedStatisticsDefs; /* string definitions of same */ +} AlteredTableInfo; + +/* Struct describing one new constraint to check in Phase 3 scan */ +/* Note: new not-null constraints are handled elsewhere */ +typedef struct NewConstraint +{ + char *name; /* Constraint name, or NULL if none */ + ConstrType contype; /* CHECK or FOREIGN */ + Oid refrelid; /* PK rel, if FOREIGN */ + Oid refindid; /* OID of PK's index, if FOREIGN */ + bool conwithperiod; /* Whether the new FOREIGN KEY uses PERIOD */ + Oid conid; /* OID of pg_constraint entry, if FOREIGN */ + Node *qual; /* Check expr or CONSTR_FOREIGN Constraint */ + ExprState *qualstate; /* Execution state for CHECK expr */ +} NewConstraint; + +/* + * Struct describing one new column value that needs to be computed during + * Phase 3 copy (this could be either a new column with a non-null default, or + * a column that we're changing the type of). Columns without such an entry + * are just copied from the old table during ATRewriteTable. Note that the + * expr is an expression over *old* table values, except when is_generated + * is true; then it is an expression over columns of the *new* tuple. + */ +typedef struct NewColumnValue +{ + AttrNumber attnum; /* which column */ + Expr *expr; /* expression to compute */ + ExprState *exprstate; /* execution state */ + bool is_generated; /* is it a GENERATED expression? */ +} NewColumnValue; + +/* Alter table target-type flags for ATSimplePermissions */ +#define ATT_TABLE 0x0001 +#define ATT_VIEW 0x0002 +#define ATT_MATVIEW 0x0004 +#define ATT_INDEX 0x0008 +#define ATT_COMPOSITE_TYPE 0x0010 +#define ATT_FOREIGN_TABLE 0x0020 +#define ATT_PARTITIONED_INDEX 0x0040 +#define ATT_SEQUENCE 0x0080 +#define ATT_PARTITIONED_TABLE 0x0100 + +/* Partial or complete FK creation in addFkConstraint() */ +typedef enum addFkConstraintSides +{ + addFkReferencedSide, + addFkReferencingSide, + addFkBothSides, +} addFkConstraintSides; + +extern void CheckAlterTableIsSafe(Relation rel); +extern void QueueFKConstraintValidation(List **wqueue, Relation conrel, Relation fkrel, + Oid pkrelid, HeapTuple contuple, LOCKMODE lockmode); +extern AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel); +extern void ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets); +extern ObjectAddress ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode, + bool recurse, bool recursing); +extern ObjectAddress addFkConstraint(addFkConstraintSides fkside, + char *constraintname, + Constraint *fkconstraint, Relation rel, + Relation pkrel, Oid indexOid, + Oid parentConstr, + int numfks, int16 *pkattnum, int16 *fkattnum, + Oid *pfeqoperators, Oid *ppeqoperators, + Oid *ffeqoperators, int numfkdelsetcols, + int16 *fkdelsetcols, bool is_internal, + bool with_period); +extern void addFkRecurseReferenced(Constraint *fkconstraint, + Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, + int numfks, int16 *pkattnum, int16 *fkattnum, + Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, + int numfkdelsetcols, int16 *fkdelsetcols, + bool old_check_ok, + Oid parentDelTrigger, Oid parentUpdTrigger, + bool with_period); +extern void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, + Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, + int numfks, int16 *pkattnum, int16 *fkattnum, + Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, + int numfkdelsetcols, int16 *fkdelsetcols, + bool old_check_ok, LOCKMODE lockmode, + Oid parentInsTrigger, Oid parentUpdTrigger, + bool with_period); +extern void DropForeignKeyConstraintTriggers(Relation trigrel, Oid conoid, + Oid confrelid, Oid conrelid); +extern void CreateInheritance(Relation child_rel, Relation parent_rel, bool ispartition); +extern void RemoveInheritance(Relation child_rel, Relation parent_rel, + bool expect_detached); + +#endif /* TABLECMDS_INTERNAL_H */ diff --git a/src/include/commands/tablecmds_partition.h b/src/include/commands/tablecmds_partition.h new file mode 100644 index 00000000000..27c3583abd8 --- /dev/null +++ b/src/include/commands/tablecmds_partition.h @@ -0,0 +1,59 @@ +/*------------------------------------------------------------------------- + * + * tablecmds_partition.h + * prototypes for tablecmds_partition.c. + * + * + * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/tablecmds_partition.h + * + *------------------------------------------------------------------------- + */ +#ifndef TABLECMDS_PARTITION_H +#define TABLECMDS_PARTITION_H + +/* to avoid including other headers */ +typedef struct AlteredTableInfo AlteredTableInfo; +typedef struct ParseState ParseState; +typedef struct AlterTableUtilityContext AlterTableUtilityContext; +typedef struct ForeignKeyCacheInfo ForeignKeyCacheInfo; + +extern void ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode); +extern bool ConstraintImpliedByRelConstraint(Relation scanrel, + List *testConstraint, List *provenConstraint); +extern void CloneForeignKeyConstraints(List **wqueue, Relation parentRel, + Relation partitionRel); +extern bool tryAttachPartitionForeignKey(List **wqueue, + ForeignKeyCacheInfo *fk, + Relation partition, + Oid parentConstrOid, int numfks, + AttrNumber *mapped_conkey, AttrNumber *confkey, + Oid *conpfeqop, + Oid parentInsTrigger, + Oid parentUpdTrigger, + Relation trigrel); +extern PartitionSpec *transformPartitionSpec(Relation rel, PartitionSpec *partspec); +extern void ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs, + List **partexprs, Oid *partopclass, Oid *partcollation, + PartitionStrategy strategy); +extern bool PartConstraintImpliedByRelConstraint(Relation scanrel, + List *partConstraint); +extern ObjectAddress ATExecAttachPartition(List **wqueue, Relation rel, + PartitionCmd *cmd, + AlterTableUtilityContext *context); +extern void CloneRowTriggersToPartition(Relation parent, Relation partition); +extern ObjectAddress ATExecDetachPartition(List **wqueue, AlteredTableInfo *tab, + Relation rel, RangeVar *name, + bool concurrent); +extern ObjectAddress ATExecDetachPartitionFinalize(Relation rel, RangeVar *name); +extern ObjectAddress ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx, + RangeVar *name); +extern void ATExecMergePartitions(List **wqueue, AlteredTableInfo *tab, Relation rel, + PartitionCmd *cmd, AlterTableUtilityContext *context); +extern void ATExecSplitPartition(List **wqueue, AlteredTableInfo *tab, + Relation rel, PartitionCmd *cmd, + AlterTableUtilityContext *context); + +#endif /* TABLECMDS_PARTITION_H */ -- 2.50.1 (Apple Git-155) --kKVivK7uYOweTyEF-- ^ permalink raw reply [nested|flat] 104+ messages in thread
end of thread, other threads:[~2026-01-29 22:09 UTC | newest] Thread overview: 104+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 4/8] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 4/8] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 4/8] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 4/8] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 4/8] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 4/8] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH v9 4/9] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 4/8] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 4/8] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 4/8] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 4/8] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 4/8] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 4/8] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 4/8] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 4/8] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH v7 4/9] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 4/8] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH v8 4/9] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 4/8] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 4/8] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/12] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 4/8] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 4/8] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 4/8] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/12] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 4/8] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 4/8] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 4/8] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 4/8] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2021-03-11 23:36 [PATCH 04/10] wal_compression_method: default to zlib.. Justin Pryzby <[email protected]> 2024-01-27 03:29 Re: Support run-time partition pruning for hash join vignesh C <[email protected]> 2024-01-30 02:33 ` Re: Support run-time partition pruning for hash join Richard Guo <[email protected]> 2026-01-29 22:09 [PATCH v2 1/1] move partitioning code out of tablecmds.c Nathan Bossart <[email protected]>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox