From a5b81b6f0006ea0b502780ce7f73d295a225842c Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Tue, 29 Dec 2020 23:35:26 +0300 Subject: [PATCH 001/240] Fix bugs in comparison functions for multirange_bsearch_match() Two functions multirange_range_overlaps_bsearch_comparison() and multirange_range_contains_bsearch_comparison() contain bugs of returning -1 instead of 1. This commit fixes these bugs and adds corresponding regression tests. --- src/backend/utils/adt/multirangetypes.c | 4 ++-- src/test/regress/expected/multirangetypes.out | 12 ++++++++++++ src/test/regress/sql/multirangetypes.sql | 2 ++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/backend/utils/adt/multirangetypes.c b/src/backend/utils/adt/multirangetypes.c index 06316ba6b6570..46f661fee49e4 100644 --- a/src/backend/utils/adt/multirangetypes.c +++ b/src/backend/utils/adt/multirangetypes.c @@ -1660,7 +1660,7 @@ multirange_range_contains_bsearch_comparison(TypeCacheEntry *typcache, if (range_cmp_bounds(typcache, keyUpper, lower) < 0) return -1; if (range_cmp_bounds(typcache, keyLower, upper) > 0) - return -1; + return 1; /* * At this point we found overlapping range. But we have to check if it @@ -1825,7 +1825,7 @@ multirange_range_overlaps_bsearch_comparison(TypeCacheEntry *typcache, if (range_cmp_bounds(typcache, keyUpper, lower) < 0) return -1; if (range_cmp_bounds(typcache, keyLower, upper) > 0) - return -1; + return 1; *match = true; return 0; diff --git a/src/test/regress/expected/multirangetypes.out b/src/test/regress/expected/multirangetypes.out index e81e565cab753..180aa1e8a535e 100644 --- a/src/test/regress/expected/multirangetypes.out +++ b/src/test/regress/expected/multirangetypes.out @@ -834,6 +834,12 @@ SELECT nummultirange(numrange(1,2), numrange(3.5,8)) && nummultirange(numrange(3 t (1 row) +select '{(10,20),(30,40),(50,60)}'::nummultirange && '(42,92)'::numrange; + ?column? +---------- + t +(1 row) + -- contains SELECT nummultirange() @> nummultirange(); ?column? @@ -967,6 +973,12 @@ SELECT '{[1,5), [6,9)}'::nummultirange @> '{[6,7)}'; t (1 row) +select '{(10,20),(30,40),(50,60)}'::nummultirange @> '(52,56)'::numrange; + ?column? +---------- + t +(1 row) + -- is contained by SELECT nummultirange() <@ nummultirange(); ?column? diff --git a/src/test/regress/sql/multirangetypes.sql b/src/test/regress/sql/multirangetypes.sql index 9be26f10d381f..c9f84cf81d467 100644 --- a/src/test/regress/sql/multirangetypes.sql +++ b/src/test/regress/sql/multirangetypes.sql @@ -162,6 +162,7 @@ SELECT nummultirange(numrange(1,2), numrange(7,8)) && nummultirange(numrange(3,4 SELECT nummultirange(numrange(3,4)) && nummultirange(numrange(1,2), numrange(3.5,8)); SELECT nummultirange(numrange(1,2), numrange(3.5,8)) && numrange(3,4); SELECT nummultirange(numrange(1,2), numrange(3.5,8)) && nummultirange(numrange(3,4)); +select '{(10,20),(30,40),(50,60)}'::nummultirange && '(42,92)'::numrange; -- contains SELECT nummultirange() @> nummultirange(); @@ -186,6 +187,7 @@ SELECT '{[-4,-2), [1,5)}'::nummultirange @> '{[1,5)}'; SELECT '{[1,5), [8,9)}'::nummultirange @> '{[1,5)}'; SELECT '{[1,5), [8,9)}'::nummultirange @> '{[6,7)}'; SELECT '{[1,5), [6,9)}'::nummultirange @> '{[6,7)}'; +select '{(10,20),(30,40),(50,60)}'::nummultirange @> '(52,56)'::numrange; -- is contained by SELECT nummultirange() <@ nummultirange(); From 4d7684cc754f312aee468abb83ca4f7da94b30a3 Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Tue, 29 Dec 2020 23:35:33 +0300 Subject: [PATCH 002/240] Implement operators for checking if the range contains a multirange We have operators for checking if the multirange contains a range but don't have the opposite. This commit improves completeness of the operator set by adding two new operators: @> (anyrange,anymultirange) and <@(anymultirange,anyrange). Catversion is bumped. --- doc/src/sgml/func.sgml | 14 + src/backend/utils/adt/multirangetypes.c | 60 +++++ .../utils/adt/multirangetypes_selfuncs.c | 6 +- src/include/catalog/catversion.h | 2 +- src/include/catalog/pg_operator.dat | 12 + src/include/catalog/pg_proc.dat | 6 + src/include/utils/multirangetypes.h | 4 +- src/test/regress/expected/multirangetypes.out | 240 ++++++++++++++++++ src/test/regress/sql/multirangetypes.sql | 40 +++ 9 files changed, 381 insertions(+), 3 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 93d17e4b558af..5021ac1ca96a4 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -18182,6 +18182,20 @@ SELECT NULLIF(value, '(none)') ... + + + anyrange @> anymultirange + boolean + + + Does the range contain the multirange? + + + '[2,4)'::int4range @> '{[2,3)}'::int4multirange + t + + + anymultirange <@ anymultirange diff --git a/src/backend/utils/adt/multirangetypes.c b/src/backend/utils/adt/multirangetypes.c index 46f661fee49e4..4b86be583ef71 100644 --- a/src/backend/utils/adt/multirangetypes.c +++ b/src/backend/utils/adt/multirangetypes.c @@ -1631,6 +1631,18 @@ multirange_contains_range(PG_FUNCTION_ARGS) PG_RETURN_BOOL(multirange_contains_range_internal(typcache, mr, r)); } +Datum +range_contains_multirange(PG_FUNCTION_ARGS) +{ + RangeType *r = PG_GETARG_RANGE_P(0); + MultirangeType *mr = PG_GETARG_MULTIRANGE_P(1); + TypeCacheEntry *typcache; + + typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr)); + + PG_RETURN_BOOL(range_contains_multirange_internal(typcache, r, mr)); +} + /* contained by? */ Datum range_contained_by_multirange(PG_FUNCTION_ARGS) @@ -1644,6 +1656,18 @@ range_contained_by_multirange(PG_FUNCTION_ARGS) PG_RETURN_BOOL(multirange_contains_range_internal(typcache, mr, r)); } +Datum +multirange_contained_by_range(PG_FUNCTION_ARGS) +{ + MultirangeType *mr = PG_GETARG_MULTIRANGE_P(0); + RangeType *r = PG_GETARG_RANGE_P(1); + TypeCacheEntry *typcache; + + typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr)); + + PG_RETURN_BOOL(range_contains_multirange_internal(typcache, r, mr)); +} + /* * Comparison function for checking if any range of multirange contains given * key range using binary search. @@ -1701,6 +1725,42 @@ multirange_contains_range_internal(TypeCacheEntry *typcache, MultirangeType *mr, multirange_range_contains_bsearch_comparison); } +/* + * Test whether range r contains a multirange mr. + */ +bool +range_contains_multirange_internal(TypeCacheEntry *typcache, RangeType *r, + MultirangeType *mr) +{ + TypeCacheEntry *rangetyp; + RangeBound lower1, + upper1, + lower2, + upper2, + tmp; + bool empty; + + rangetyp = typcache->rngtype; + + /* + * Every range contains an infinite number of empty multiranges, even an + * empty one. + */ + if (MultirangeIsEmpty(mr)) + return true; + + if (RangeIsEmpty(r)) + return false; + + /* Range contains multirange iff it contains its union range. */ + range_deserialize(rangetyp, r, &lower1, &upper1, &empty); + Assert(!empty); + multirange_get_bounds(rangetyp, mr, 0, &lower2, &tmp); + multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1, &tmp, &upper2); + + return range_bounds_contains(rangetyp, &lower1, &upper1, &lower2, &upper2); +} + /* multirange, multirange -> bool functions */ diff --git a/src/backend/utils/adt/multirangetypes_selfuncs.c b/src/backend/utils/adt/multirangetypes_selfuncs.c index 7259af0b85305..bb016b6e98770 100644 --- a/src/backend/utils/adt/multirangetypes_selfuncs.c +++ b/src/backend/utils/adt/multirangetypes_selfuncs.c @@ -86,6 +86,8 @@ default_multirange_selectivity(Oid operator) case OID_RANGE_OVERLAPS_MULTIRANGE_OP: return 0.01; + case OID_RANGE_CONTAINS_MULTIRANGE_OP: + case OID_RANGE_MULTIRANGE_CONTAINED_OP: case OID_MULTIRANGE_CONTAINS_RANGE_OP: case OID_MULTIRANGE_CONTAINS_MULTIRANGE_OP: case OID_MULTIRANGE_RANGE_CONTAINED_OP: @@ -224,7 +226,8 @@ multirangesel(PG_FUNCTION_ARGS) 1, &constrange); } } - else if (operator == OID_MULTIRANGE_CONTAINS_RANGE_OP || + else if (operator == OID_RANGE_MULTIRANGE_CONTAINED_OP || + operator == OID_MULTIRANGE_CONTAINS_RANGE_OP || operator == OID_MULTIRANGE_OVERLAPS_RANGE_OP || operator == OID_MULTIRANGE_OVERLAPS_LEFT_RANGE_OP || operator == OID_MULTIRANGE_OVERLAPS_RIGHT_RANGE_OP || @@ -248,6 +251,7 @@ multirangesel(PG_FUNCTION_ARGS) operator == OID_RANGE_OVERLAPS_RIGHT_MULTIRANGE_OP || operator == OID_RANGE_LEFT_MULTIRANGE_OP || operator == OID_RANGE_RIGHT_MULTIRANGE_OP || + operator == OID_RANGE_CONTAINS_MULTIRANGE_OP || operator == OID_MULTIRANGE_ELEM_CONTAINED_OP || operator == OID_MULTIRANGE_RANGE_CONTAINED_OP) { diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 40fd5d434758c..4fd88a477306c 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202012201 +#define CATALOG_VERSION_NO 202012291 #endif diff --git a/src/include/catalog/pg_operator.dat b/src/include/catalog/pg_operator.dat index bd0c3d0f81a8a..9c6bf6c9d115d 100644 --- a/src/include/catalog/pg_operator.dat +++ b/src/include/catalog/pg_operator.dat @@ -3360,6 +3360,18 @@ oprresult => 'bool', oprcom => '@>(anymultirange,anymultirange)', oprcode => 'multirange_contained_by_multirange', oprrest => 'multirangesel', oprjoin => 'contjoinsel' }, +{ oid => '4539', oid_symbol => 'OID_RANGE_CONTAINS_MULTIRANGE_OP', + descr => 'contains', + oprname => '@>', oprleft => 'anyrange', oprright => 'anymultirange', + oprresult => 'bool', oprcom => '<@(anymultirange,anyrange)', + oprcode => 'range_contains_multirange', oprrest => 'multirangesel', + oprjoin => 'contjoinsel' }, +{ oid => '4540', oid_symbol => 'OID_RANGE_MULTIRANGE_CONTAINED_OP', + descr => 'is contained by', + oprname => '<@', oprleft => 'anymultirange', oprright => 'anyrange', + oprresult => 'bool', oprcom => '@>(anyrange,anymultirange)', + oprcode => 'multirange_contained_by_range', oprrest => 'multirangesel', + oprjoin => 'contjoinsel' }, { oid => '2875', oid_symbol => 'OID_RANGE_OVERLAPS_LEFT_MULTIRANGE_OP', descr => 'overlaps or is left of', oprname => '&<', oprleft => 'anyrange', oprright => 'anymultirange', diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 22970f46cd7be..834ee86c791b4 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -10085,6 +10085,12 @@ { oid => '4253', proname => 'range_contained_by_multirange', prorettype => 'bool', proargtypes => 'anyrange anymultirange', prosrc => 'range_contained_by_multirange' }, +{ oid => '4541', + proname => 'range_contains_multirange', prorettype => 'bool', + proargtypes => 'anyrange anymultirange', prosrc => 'range_contains_multirange' }, +{ oid => '4542', + proname => 'multirange_contained_by_range', prorettype => 'bool', + proargtypes => 'anymultirange anyrange', prosrc => 'multirange_contained_by_range' }, { oid => '4254', proname => 'multirange_contained_by_multirange', prorettype => 'bool', proargtypes => 'anymultirange anymultirange', prosrc => 'multirange_contained_by_multirange' }, diff --git a/src/include/utils/multirangetypes.h b/src/include/utils/multirangetypes.h index 4cf7241570197..f2290aac27480 100644 --- a/src/include/utils/multirangetypes.h +++ b/src/include/utils/multirangetypes.h @@ -64,6 +64,8 @@ extern bool multirange_contains_elem_internal(TypeCacheEntry *typcache, Multiran Datum elem); extern bool multirange_contains_range_internal(TypeCacheEntry *typcache, MultirangeType *mr, RangeType *r); +extern bool range_contains_multirange_internal(TypeCacheEntry *typcache, RangeType *r, + MultirangeType *mr); extern bool multirange_contains_multirange_internal(TypeCacheEntry *typcache, MultirangeType *mr1, MultirangeType *mr2); @@ -77,7 +79,7 @@ extern bool range_before_multirange_internal(TypeCacheEntry *typcache, RangeType extern bool range_after_multirange_internal(TypeCacheEntry *typcache, RangeType *r, MultirangeType *mr); extern bool range_adjacent_multirange_internal(TypeCacheEntry *typcache, RangeType *r, - MultirangeType *mr); + MultirangeType *mr); extern bool multirange_before_multirange_internal(TypeCacheEntry *typcache, MultirangeType *mr1, MultirangeType *mr2); diff --git a/src/test/regress/expected/multirangetypes.out b/src/test/regress/expected/multirangetypes.out index 180aa1e8a535e..aa7232efc5779 100644 --- a/src/test/regress/expected/multirangetypes.out +++ b/src/test/regress/expected/multirangetypes.out @@ -979,6 +979,126 @@ select '{(10,20),(30,40),(50,60)}'::nummultirange @> '(52,56)'::numrange; t (1 row) +SELECT numrange(null,null) @> nummultirange(numrange(1,2)); + ?column? +---------- + t +(1 row) + +SELECT numrange(null,null) @> nummultirange(numrange(null,2)); + ?column? +---------- + t +(1 row) + +SELECT numrange(null,null) @> nummultirange(numrange(2,null)); + ?column? +---------- + t +(1 row) + +SELECT numrange(null,5) @> nummultirange(numrange(null,3)); + ?column? +---------- + t +(1 row) + +SELECT numrange(null,5) @> nummultirange(numrange(null,8)); + ?column? +---------- + f +(1 row) + +SELECT numrange(5,null) @> nummultirange(numrange(8,null)); + ?column? +---------- + t +(1 row) + +SELECT numrange(5,null) @> nummultirange(numrange(3,null)); + ?column? +---------- + f +(1 row) + +SELECT numrange(1,5) @> nummultirange(numrange(8,9)); + ?column? +---------- + f +(1 row) + +SELECT numrange(1,5) @> nummultirange(numrange(3,9)); + ?column? +---------- + f +(1 row) + +SELECT numrange(1,5) @> nummultirange(numrange(1,4)); + ?column? +---------- + t +(1 row) + +SELECT numrange(1,5) @> nummultirange(numrange(1,5)); + ?column? +---------- + t +(1 row) + +SELECT numrange(1,9) @> nummultirange(numrange(-4,-2), numrange(1,5)); + ?column? +---------- + f +(1 row) + +SELECT numrange(1,9) @> nummultirange(numrange(1,5), numrange(8,9)); + ?column? +---------- + t +(1 row) + +SELECT numrange(1,9) @> nummultirange(numrange(1,5), numrange(6,9)); + ?column? +---------- + t +(1 row) + +SELECT numrange(1,9) @> nummultirange(numrange(1,5), numrange(6,10)); + ?column? +---------- + f +(1 row) + +SELECT '{[1,9)}' @> '{[1,5)}'::nummultirange; + ?column? +---------- + t +(1 row) + +SELECT '{[1,9)}' @> '{[-4,-2), [1,5)}'::nummultirange; + ?column? +---------- + f +(1 row) + +SELECT '{[1,9)}' @> '{[1,5), [8,9)}'::nummultirange; + ?column? +---------- + t +(1 row) + +SELECT '{[1,9)}' @> '{[1,5), [6,9)}'::nummultirange; + ?column? +---------- + t +(1 row) + +SELECT '{[1,9)}' @> '{[1,5), [6,10)}'::nummultirange; + ?column? +---------- + f +(1 row) + -- is contained by SELECT nummultirange() <@ nummultirange(); ?column? @@ -1112,6 +1232,126 @@ SELECT '{[6,7)}' <@ '{[1,5), [6,9)}'::nummultirange; t (1 row) +SELECT nummultirange(numrange(1,2)) <@ numrange(null,null); + ?column? +---------- + t +(1 row) + +SELECT nummultirange(numrange(null,2)) <@ numrange(null,null); + ?column? +---------- + t +(1 row) + +SELECT nummultirange(numrange(2,null)) <@ numrange(null,null); + ?column? +---------- + t +(1 row) + +SELECT nummultirange(numrange(null,3)) <@ numrange(null,5); + ?column? +---------- + t +(1 row) + +SELECT nummultirange(numrange(null,8)) <@ numrange(null,5); + ?column? +---------- + f +(1 row) + +SELECT nummultirange(numrange(8,null)) <@ numrange(5,null); + ?column? +---------- + t +(1 row) + +SELECT nummultirange(numrange(3,null)) <@ numrange(5,null); + ?column? +---------- + f +(1 row) + +SELECT nummultirange(numrange(8,9)) <@ numrange(1,5); + ?column? +---------- + f +(1 row) + +SELECT nummultirange(numrange(3,9)) <@ numrange(1,5); + ?column? +---------- + f +(1 row) + +SELECT nummultirange(numrange(1,4)) <@ numrange(1,5); + ?column? +---------- + t +(1 row) + +SELECT nummultirange(numrange(1,5)) <@ numrange(1,5); + ?column? +---------- + t +(1 row) + +SELECT nummultirange(numrange(-4,-2), numrange(1,5)) <@ numrange(1,9); + ?column? +---------- + f +(1 row) + +SELECT nummultirange(numrange(1,5), numrange(8,9)) <@ numrange(1,9); + ?column? +---------- + t +(1 row) + +SELECT nummultirange(numrange(1,5), numrange(6,9)) <@ numrange(1,9); + ?column? +---------- + t +(1 row) + +SELECT nummultirange(numrange(1,5), numrange(6,10)) <@ numrange(1,9); + ?column? +---------- + f +(1 row) + +SELECT '{[1,5)}'::nummultirange <@ '{[1,9)}'; + ?column? +---------- + t +(1 row) + +SELECT '{[-4,-2), [1,5)}'::nummultirange <@ '{[1,9)}'; + ?column? +---------- + f +(1 row) + +SELECT '{[1,5), [8,9)}'::nummultirange <@ '{[1,9)}'; + ?column? +---------- + t +(1 row) + +SELECT '{[1,5), [6,9)}'::nummultirange <@ '{[1,9)}'; + ?column? +---------- + t +(1 row) + +SELECT '{[1,5), [6,10)}'::nummultirange <@ '{[1,9)}'; + ?column? +---------- + f +(1 row) + -- overleft SELECT 'empty'::numrange &< nummultirange(); ?column? diff --git a/src/test/regress/sql/multirangetypes.sql b/src/test/regress/sql/multirangetypes.sql index c9f84cf81d467..9d7af404c98c2 100644 --- a/src/test/regress/sql/multirangetypes.sql +++ b/src/test/regress/sql/multirangetypes.sql @@ -188,6 +188,26 @@ SELECT '{[1,5), [8,9)}'::nummultirange @> '{[1,5)}'; SELECT '{[1,5), [8,9)}'::nummultirange @> '{[6,7)}'; SELECT '{[1,5), [6,9)}'::nummultirange @> '{[6,7)}'; select '{(10,20),(30,40),(50,60)}'::nummultirange @> '(52,56)'::numrange; +SELECT numrange(null,null) @> nummultirange(numrange(1,2)); +SELECT numrange(null,null) @> nummultirange(numrange(null,2)); +SELECT numrange(null,null) @> nummultirange(numrange(2,null)); +SELECT numrange(null,5) @> nummultirange(numrange(null,3)); +SELECT numrange(null,5) @> nummultirange(numrange(null,8)); +SELECT numrange(5,null) @> nummultirange(numrange(8,null)); +SELECT numrange(5,null) @> nummultirange(numrange(3,null)); +SELECT numrange(1,5) @> nummultirange(numrange(8,9)); +SELECT numrange(1,5) @> nummultirange(numrange(3,9)); +SELECT numrange(1,5) @> nummultirange(numrange(1,4)); +SELECT numrange(1,5) @> nummultirange(numrange(1,5)); +SELECT numrange(1,9) @> nummultirange(numrange(-4,-2), numrange(1,5)); +SELECT numrange(1,9) @> nummultirange(numrange(1,5), numrange(8,9)); +SELECT numrange(1,9) @> nummultirange(numrange(1,5), numrange(6,9)); +SELECT numrange(1,9) @> nummultirange(numrange(1,5), numrange(6,10)); +SELECT '{[1,9)}' @> '{[1,5)}'::nummultirange; +SELECT '{[1,9)}' @> '{[-4,-2), [1,5)}'::nummultirange; +SELECT '{[1,9)}' @> '{[1,5), [8,9)}'::nummultirange; +SELECT '{[1,9)}' @> '{[1,5), [6,9)}'::nummultirange; +SELECT '{[1,9)}' @> '{[1,5), [6,10)}'::nummultirange; -- is contained by SELECT nummultirange() <@ nummultirange(); @@ -212,6 +232,26 @@ SELECT '{[1,5)}' <@ '{[-4,-2), [1,5)}'::nummultirange; SELECT '{[1,5)}' <@ '{[1,5), [8,9)}'::nummultirange; SELECT '{[6,7)}' <@ '{[1,5), [8,9)}'::nummultirange; SELECT '{[6,7)}' <@ '{[1,5), [6,9)}'::nummultirange; +SELECT nummultirange(numrange(1,2)) <@ numrange(null,null); +SELECT nummultirange(numrange(null,2)) <@ numrange(null,null); +SELECT nummultirange(numrange(2,null)) <@ numrange(null,null); +SELECT nummultirange(numrange(null,3)) <@ numrange(null,5); +SELECT nummultirange(numrange(null,8)) <@ numrange(null,5); +SELECT nummultirange(numrange(8,null)) <@ numrange(5,null); +SELECT nummultirange(numrange(3,null)) <@ numrange(5,null); +SELECT nummultirange(numrange(8,9)) <@ numrange(1,5); +SELECT nummultirange(numrange(3,9)) <@ numrange(1,5); +SELECT nummultirange(numrange(1,4)) <@ numrange(1,5); +SELECT nummultirange(numrange(1,5)) <@ numrange(1,5); +SELECT nummultirange(numrange(-4,-2), numrange(1,5)) <@ numrange(1,9); +SELECT nummultirange(numrange(1,5), numrange(8,9)) <@ numrange(1,9); +SELECT nummultirange(numrange(1,5), numrange(6,9)) <@ numrange(1,9); +SELECT nummultirange(numrange(1,5), numrange(6,10)) <@ numrange(1,9); +SELECT '{[1,5)}'::nummultirange <@ '{[1,9)}'; +SELECT '{[-4,-2), [1,5)}'::nummultirange <@ '{[1,9)}'; +SELECT '{[1,5), [8,9)}'::nummultirange <@ '{[1,9)}'; +SELECT '{[1,5), [6,9)}'::nummultirange <@ '{[1,9)}'; +SELECT '{[1,5), [6,10)}'::nummultirange <@ '{[1,9)}'; -- overleft SELECT 'empty'::numrange &< nummultirange(); From d1d61a8b23b604faf797695eeacaa5da4fe64762 Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Tue, 29 Dec 2020 23:35:38 +0300 Subject: [PATCH 003/240] Improve the signature of internal multirange functions There is a set of *_internal() functions exposed in include/utils/multirangetypes.h. This commit improves the signatures of these functions in two ways. * Add const qualifies where applicable. * Replace multirange typecache argument with range typecache argument. Multirange typecache was used solely to find the range typecache. At the same time, range typecache is easier for the caller to find. --- src/backend/utils/adt/multirangetypes.c | 206 +++++++++++++----------- src/include/utils/multirangetypes.h | 69 ++++---- 2 files changed, 153 insertions(+), 122 deletions(-) diff --git a/src/backend/utils/adt/multirangetypes.c b/src/backend/utils/adt/multirangetypes.c index 4b86be583ef71..a77299147e7fb 100644 --- a/src/backend/utils/adt/multirangetypes.c +++ b/src/backend/utils/adt/multirangetypes.c @@ -847,7 +847,7 @@ range_bounds_contains(TypeCacheEntry *typcache, * that would count as a mismatch. */ static bool -multirange_bsearch_match(TypeCacheEntry *typcache, MultirangeType *mr, +multirange_bsearch_match(TypeCacheEntry *typcache, const MultirangeType *mr, void *key, multirange_bsearch_comparison cmp_func) { uint32 l, @@ -1552,7 +1552,7 @@ multirange_contains_elem(PG_FUNCTION_ARGS) typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr)); - PG_RETURN_BOOL(multirange_contains_elem_internal(typcache, mr, val)); + PG_RETURN_BOOL(multirange_contains_elem_internal(typcache->rngtype, mr, val)); } /* contained by? */ @@ -1565,7 +1565,7 @@ elem_contained_by_multirange(PG_FUNCTION_ARGS) typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr)); - PG_RETURN_BOOL(multirange_contains_elem_internal(typcache, mr, val)); + PG_RETURN_BOOL(multirange_contains_elem_internal(typcache->rngtype, mr, val)); } /* @@ -1606,13 +1606,13 @@ multirange_elem_bsearch_comparison(TypeCacheEntry *typcache, * Test whether multirange mr contains a specific element value. */ bool -multirange_contains_elem_internal(TypeCacheEntry *typcache, - MultirangeType *mr, Datum val) +multirange_contains_elem_internal(TypeCacheEntry *rangetyp, + const MultirangeType *mr, Datum val) { if (MultirangeIsEmpty(mr)) return false; - return multirange_bsearch_match(typcache->rngtype, mr, &val, + return multirange_bsearch_match(rangetyp, mr, &val, multirange_elem_bsearch_comparison); } @@ -1628,7 +1628,7 @@ multirange_contains_range(PG_FUNCTION_ARGS) typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr)); - PG_RETURN_BOOL(multirange_contains_range_internal(typcache, mr, r)); + PG_RETURN_BOOL(multirange_contains_range_internal(typcache->rngtype, mr, r)); } Datum @@ -1640,7 +1640,7 @@ range_contains_multirange(PG_FUNCTION_ARGS) typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr)); - PG_RETURN_BOOL(range_contains_multirange_internal(typcache, r, mr)); + PG_RETURN_BOOL(range_contains_multirange_internal(typcache->rngtype, r, mr)); } /* contained by? */ @@ -1653,7 +1653,7 @@ range_contained_by_multirange(PG_FUNCTION_ARGS) typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr)); - PG_RETURN_BOOL(multirange_contains_range_internal(typcache, mr, r)); + PG_RETURN_BOOL(multirange_contains_range_internal(typcache->rngtype, mr, r)); } Datum @@ -1665,7 +1665,7 @@ multirange_contained_by_range(PG_FUNCTION_ARGS) typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr)); - PG_RETURN_BOOL(range_contains_multirange_internal(typcache, r, mr)); + PG_RETURN_BOOL(range_contains_multirange_internal(typcache->rngtype, r, mr)); } /* @@ -1700,14 +1700,13 @@ multirange_range_contains_bsearch_comparison(TypeCacheEntry *typcache, * Test whether multirange mr contains a specific range r. */ bool -multirange_contains_range_internal(TypeCacheEntry *typcache, MultirangeType *mr, RangeType *r) +multirange_contains_range_internal(TypeCacheEntry *rangetyp, + const MultirangeType *mr, + const RangeType *r) { - TypeCacheEntry *rangetyp; RangeBound bounds[2]; bool empty; - rangetyp = typcache->rngtype; - /* * Every multirange contains an infinite number of empty ranges, even an * empty one. @@ -1729,10 +1728,10 @@ multirange_contains_range_internal(TypeCacheEntry *typcache, MultirangeType *mr, * Test whether range r contains a multirange mr. */ bool -range_contains_multirange_internal(TypeCacheEntry *typcache, RangeType *r, - MultirangeType *mr) +range_contains_multirange_internal(TypeCacheEntry *rangetyp, + const RangeType *r, + const MultirangeType *mr) { - TypeCacheEntry *rangetyp; RangeBound lower1, upper1, lower2, @@ -1740,8 +1739,6 @@ range_contains_multirange_internal(TypeCacheEntry *typcache, RangeType *r, tmp; bool empty; - rangetyp = typcache->rngtype; - /* * Every range contains an infinite number of empty multiranges, even an * empty one. @@ -1766,9 +1763,10 @@ range_contains_multirange_internal(TypeCacheEntry *typcache, RangeType *r, /* equality (internal version) */ bool -multirange_eq_internal(TypeCacheEntry *typcache, MultirangeType *mr1, MultirangeType *mr2) +multirange_eq_internal(TypeCacheEntry *rangetyp, + const MultirangeType *mr1, + const MultirangeType *mr2) { - TypeCacheEntry *rangetyp = typcache->rngtype; int32 range_count_1; int32 range_count_2; int32 i; @@ -1810,14 +1808,16 @@ multirange_eq(PG_FUNCTION_ARGS) typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1)); - PG_RETURN_BOOL(multirange_eq_internal(typcache, mr1, mr2)); + PG_RETURN_BOOL(multirange_eq_internal(typcache->rngtype, mr1, mr2)); } /* inequality (internal version) */ bool -multirange_ne_internal(TypeCacheEntry *typcache, MultirangeType *mr1, MultirangeType *mr2) +multirange_ne_internal(TypeCacheEntry *rangetyp, + const MultirangeType *mr1, + const MultirangeType *mr2) { - return (!multirange_eq_internal(typcache, mr1, mr2)); + return (!multirange_eq_internal(rangetyp, mr1, mr2)); } /* inequality */ @@ -1830,7 +1830,7 @@ multirange_ne(PG_FUNCTION_ARGS) typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1)); - PG_RETURN_BOOL(multirange_ne_internal(typcache, mr1, mr2)); + PG_RETURN_BOOL(multirange_ne_internal(typcache->rngtype, mr1, mr2)); } /* overlaps? */ @@ -1843,7 +1843,7 @@ range_overlaps_multirange(PG_FUNCTION_ARGS) typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr)); - PG_RETURN_BOOL(range_overlaps_multirange_internal(typcache, r, mr)); + PG_RETURN_BOOL(range_overlaps_multirange_internal(typcache->rngtype, r, mr)); } Datum @@ -1855,7 +1855,7 @@ multirange_overlaps_range(PG_FUNCTION_ARGS) typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr)); - PG_RETURN_BOOL(range_overlaps_multirange_internal(typcache, r, mr)); + PG_RETURN_BOOL(range_overlaps_multirange_internal(typcache->rngtype, r, mr)); } Datum @@ -1867,7 +1867,7 @@ multirange_overlaps_multirange(PG_FUNCTION_ARGS) typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1)); - PG_RETURN_BOOL(multirange_overlaps_multirange_internal(typcache, mr1, mr2)); + PG_RETURN_BOOL(multirange_overlaps_multirange_internal(typcache->rngtype, mr1, mr2)); } /* @@ -1892,14 +1892,13 @@ multirange_range_overlaps_bsearch_comparison(TypeCacheEntry *typcache, } bool -range_overlaps_multirange_internal(TypeCacheEntry *typcache, RangeType *r, MultirangeType *mr) +range_overlaps_multirange_internal(TypeCacheEntry *rangetyp, + const RangeType *r, + const MultirangeType *mr) { - TypeCacheEntry *rangetyp; RangeBound bounds[2]; bool empty; - rangetyp = typcache->rngtype; - /* * Empties never overlap, even with empties. (This seems strange since * they *do* contain each other, but we want to follow how ranges work.) @@ -1915,10 +1914,10 @@ range_overlaps_multirange_internal(TypeCacheEntry *typcache, RangeType *r, Multi } bool -multirange_overlaps_multirange_internal(TypeCacheEntry *typcache, MultirangeType *mr1, - MultirangeType *mr2) +multirange_overlaps_multirange_internal(TypeCacheEntry *rangetyp, + const MultirangeType *mr1, + const MultirangeType *mr2) { - TypeCacheEntry *rangetyp; int32 range_count1; int32 range_count2; int32 i1; @@ -1935,8 +1934,6 @@ multirange_overlaps_multirange_internal(TypeCacheEntry *typcache, MultirangeType if (MultirangeIsEmpty(mr1) || MultirangeIsEmpty(mr2)) return false; - rangetyp = typcache->rngtype; - range_count1 = mr1->rangeCount; range_count2 = mr2->rangeCount; @@ -1974,12 +1971,11 @@ multirange_overlaps_multirange_internal(TypeCacheEntry *typcache, MultirangeType } /* does not extend to right of? */ -Datum -range_overleft_multirange(PG_FUNCTION_ARGS) +bool +range_overleft_multirange_internal(TypeCacheEntry *rangetyp, + const RangeType *r, + const MultirangeType *mr) { - RangeType *r = PG_GETARG_RANGE_P(0); - MultirangeType *mr = PG_GETARG_MULTIRANGE_P(1); - TypeCacheEntry *typcache; RangeBound lower1, upper1, lower2, @@ -1989,14 +1985,25 @@ range_overleft_multirange(PG_FUNCTION_ARGS) if (RangeIsEmpty(r) || MultirangeIsEmpty(mr)) PG_RETURN_BOOL(false); - typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr)); - range_deserialize(typcache->rngtype, r, &lower1, &upper1, &empty); + range_deserialize(rangetyp, r, &lower1, &upper1, &empty); Assert(!empty); - multirange_get_bounds(typcache->rngtype, mr, mr->rangeCount - 1, + multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1, &lower2, &upper2); - PG_RETURN_BOOL(range_cmp_bounds(typcache->rngtype, &upper1, &upper2) <= 0); + PG_RETURN_BOOL(range_cmp_bounds(rangetyp, &upper1, &upper2) <= 0); +} + +Datum +range_overleft_multirange(PG_FUNCTION_ARGS) +{ + RangeType *r = PG_GETARG_RANGE_P(0); + MultirangeType *mr = PG_GETARG_MULTIRANGE_P(1); + TypeCacheEntry *typcache; + + typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr)); + + PG_RETURN_BOOL(range_overleft_multirange_internal(typcache->rngtype, r, mr)); } Datum @@ -2049,12 +2056,11 @@ multirange_overleft_multirange(PG_FUNCTION_ARGS) } /* does not extend to left of? */ -Datum -range_overright_multirange(PG_FUNCTION_ARGS) +bool +range_overright_multirange_internal(TypeCacheEntry *rangetyp, + const RangeType *r, + const MultirangeType *mr) { - RangeType *r = PG_GETARG_RANGE_P(0); - MultirangeType *mr = PG_GETARG_MULTIRANGE_P(1); - TypeCacheEntry *typcache; RangeBound lower1, upper1, lower2, @@ -2064,13 +2070,23 @@ range_overright_multirange(PG_FUNCTION_ARGS) if (RangeIsEmpty(r) || MultirangeIsEmpty(mr)) PG_RETURN_BOOL(false); - typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr)); - - range_deserialize(typcache->rngtype, r, &lower1, &upper1, &empty); + range_deserialize(rangetyp, r, &lower1, &upper1, &empty); Assert(!empty); - multirange_get_bounds(typcache->rngtype, mr, 0, &lower2, &upper2); + multirange_get_bounds(rangetyp, mr, 0, &lower2, &upper2); - PG_RETURN_BOOL(range_cmp_bounds(typcache->rngtype, &lower1, &lower2) >= 0); + return (range_cmp_bounds(rangetyp, &lower1, &lower2) >= 0); +} + +Datum +range_overright_multirange(PG_FUNCTION_ARGS) +{ + RangeType *r = PG_GETARG_RANGE_P(0); + MultirangeType *mr = PG_GETARG_MULTIRANGE_P(1); + TypeCacheEntry *typcache; + + typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr)); + + PG_RETURN_BOOL(range_overright_multirange_internal(typcache->rngtype, r, mr)); } Datum @@ -2129,7 +2145,7 @@ multirange_contains_multirange(PG_FUNCTION_ARGS) typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1)); - PG_RETURN_BOOL(multirange_contains_multirange_internal(typcache, mr1, mr2)); + PG_RETURN_BOOL(multirange_contains_multirange_internal(typcache->rngtype, mr1, mr2)); } /* contained by? */ @@ -2142,17 +2158,17 @@ multirange_contained_by_multirange(PG_FUNCTION_ARGS) typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1)); - PG_RETURN_BOOL(multirange_contains_multirange_internal(typcache, mr2, mr1)); + PG_RETURN_BOOL(multirange_contains_multirange_internal(typcache->rngtype, mr2, mr1)); } /* * Test whether multirange mr1 contains every range from another multirange mr2. */ bool -multirange_contains_multirange_internal(TypeCacheEntry *typcache, - MultirangeType *mr1, MultirangeType *mr2) +multirange_contains_multirange_internal(TypeCacheEntry *rangetyp, + const MultirangeType *mr1, + const MultirangeType *mr2) { - TypeCacheEntry *rangetyp; int32 range_count1 = mr1->rangeCount; int32 range_count2 = mr2->rangeCount; int i1, @@ -2162,8 +2178,6 @@ multirange_contains_multirange_internal(TypeCacheEntry *typcache, lower2, upper2; - rangetyp = typcache->rngtype; - /* * We follow the same logic for empties as ranges: - an empty multirange * contains an empty range/multirange. - an empty multirange can't contain @@ -2221,7 +2235,7 @@ range_before_multirange(PG_FUNCTION_ARGS) typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr)); - PG_RETURN_BOOL(range_before_multirange_internal(typcache, r, mr)); + PG_RETURN_BOOL(range_before_multirange_internal(typcache->rngtype, r, mr)); } Datum @@ -2233,7 +2247,7 @@ multirange_before_range(PG_FUNCTION_ARGS) typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr)); - PG_RETURN_BOOL(range_after_multirange_internal(typcache, r, mr)); + PG_RETURN_BOOL(range_after_multirange_internal(typcache->rngtype, r, mr)); } Datum @@ -2245,7 +2259,7 @@ multirange_before_multirange(PG_FUNCTION_ARGS) typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1)); - PG_RETURN_BOOL(multirange_before_multirange_internal(typcache, mr1, mr2)); + PG_RETURN_BOOL(multirange_before_multirange_internal(typcache->rngtype, mr1, mr2)); } /* strictly right of? */ @@ -2258,7 +2272,7 @@ range_after_multirange(PG_FUNCTION_ARGS) typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr)); - PG_RETURN_BOOL(range_after_multirange_internal(typcache, r, mr)); + PG_RETURN_BOOL(range_after_multirange_internal(typcache->rngtype, r, mr)); } Datum @@ -2270,7 +2284,7 @@ multirange_after_range(PG_FUNCTION_ARGS) typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr)); - PG_RETURN_BOOL(range_before_multirange_internal(typcache, r, mr)); + PG_RETURN_BOOL(range_before_multirange_internal(typcache->rngtype, r, mr)); } Datum @@ -2282,13 +2296,14 @@ multirange_after_multirange(PG_FUNCTION_ARGS) typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1)); - PG_RETURN_BOOL(multirange_before_multirange_internal(typcache, mr2, mr1)); + PG_RETURN_BOOL(multirange_before_multirange_internal(typcache->rngtype, mr2, mr1)); } /* strictly left of? (internal version) */ bool -range_before_multirange_internal(TypeCacheEntry *typcache, RangeType *r, - MultirangeType *mr) +range_before_multirange_internal(TypeCacheEntry *rangetyp, + const RangeType *r, + const MultirangeType *mr) { RangeBound lower1, upper1, @@ -2299,19 +2314,18 @@ range_before_multirange_internal(TypeCacheEntry *typcache, RangeType *r, if (RangeIsEmpty(r) || MultirangeIsEmpty(mr)) return false; - range_deserialize(typcache->rngtype, r, &lower1, &upper1, &empty); + range_deserialize(rangetyp, r, &lower1, &upper1, &empty); Assert(!empty); - multirange_get_bounds(typcache->rngtype, mr, 0, - &lower2, &upper2); + multirange_get_bounds(rangetyp, mr, 0, &lower2, &upper2); - return (range_cmp_bounds(typcache->rngtype, &upper1, &lower2) < 0); + return (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0); } bool -multirange_before_multirange_internal(TypeCacheEntry *typcache, - MultirangeType *mr1, - MultirangeType *mr2) +multirange_before_multirange_internal(TypeCacheEntry *rangetyp, + const MultirangeType *mr1, + const MultirangeType *mr2) { RangeBound lower1, upper1, @@ -2321,18 +2335,19 @@ multirange_before_multirange_internal(TypeCacheEntry *typcache, if (MultirangeIsEmpty(mr1) || MultirangeIsEmpty(mr2)) return false; - multirange_get_bounds(typcache->rngtype, mr1, mr1->rangeCount - 1, + multirange_get_bounds(rangetyp, mr1, mr1->rangeCount - 1, &lower1, &upper1); - multirange_get_bounds(typcache->rngtype, mr2, 0, + multirange_get_bounds(rangetyp, mr2, 0, &lower2, &upper2); - return (range_cmp_bounds(typcache->rngtype, &upper1, &lower2) < 0); + return (range_cmp_bounds(rangetyp, &upper1, &lower2) < 0); } /* strictly right of? (internal version) */ bool -range_after_multirange_internal(TypeCacheEntry *typcache, RangeType *r, - MultirangeType *mr) +range_after_multirange_internal(TypeCacheEntry *rangetyp, + const RangeType *r, + const MultirangeType *mr) { RangeBound lower1, upper1, @@ -2344,19 +2359,20 @@ range_after_multirange_internal(TypeCacheEntry *typcache, RangeType *r, if (RangeIsEmpty(r) || MultirangeIsEmpty(mr)) return false; - range_deserialize(typcache->rngtype, r, &lower1, &upper1, &empty); + range_deserialize(rangetyp, r, &lower1, &upper1, &empty); Assert(!empty); range_count = mr->rangeCount; - multirange_get_bounds(typcache->rngtype, mr, range_count - 1, + multirange_get_bounds(rangetyp, mr, range_count - 1, &lower2, &upper2); - return (range_cmp_bounds(typcache->rngtype, &lower1, &upper2) > 0); + return (range_cmp_bounds(rangetyp, &lower1, &upper2) > 0); } bool -range_adjacent_multirange_internal(TypeCacheEntry *typcache, RangeType *r, - MultirangeType *mr) +range_adjacent_multirange_internal(TypeCacheEntry *rangetyp, + const RangeType *r, + const MultirangeType *mr) { RangeBound lower1, upper1, @@ -2368,21 +2384,21 @@ range_adjacent_multirange_internal(TypeCacheEntry *typcache, RangeType *r, if (RangeIsEmpty(r) || MultirangeIsEmpty(mr)) return false; - range_deserialize(typcache->rngtype, r, &lower1, &upper1, &empty); + range_deserialize(rangetyp, r, &lower1, &upper1, &empty); Assert(!empty); range_count = mr->rangeCount; - multirange_get_bounds(typcache->rngtype, mr, 0, + multirange_get_bounds(rangetyp, mr, 0, &lower2, &upper2); - if (bounds_adjacent(typcache->rngtype, upper1, lower2)) + if (bounds_adjacent(rangetyp, upper1, lower2)) return true; if (range_count > 1) - multirange_get_bounds(typcache->rngtype, mr, range_count - 1, + multirange_get_bounds(rangetyp, mr, range_count - 1, &lower2, &upper2); - if (bounds_adjacent(typcache->rngtype, upper2, lower1)) + if (bounds_adjacent(rangetyp, upper2, lower1)) return true; return false; @@ -2398,7 +2414,7 @@ range_adjacent_multirange(PG_FUNCTION_ARGS) typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr)); - PG_RETURN_BOOL(range_adjacent_multirange_internal(typcache, r, mr)); + PG_RETURN_BOOL(range_adjacent_multirange_internal(typcache->rngtype, r, mr)); } Datum @@ -2413,7 +2429,7 @@ multirange_adjacent_range(PG_FUNCTION_ARGS) typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr)); - PG_RETURN_BOOL(range_adjacent_multirange_internal(typcache, r, mr)); + PG_RETURN_BOOL(range_adjacent_multirange_internal(typcache->rngtype, r, mr)); } Datum diff --git a/src/include/utils/multirangetypes.h b/src/include/utils/multirangetypes.h index f2290aac27480..ff2e58744a908 100644 --- a/src/include/utils/multirangetypes.h +++ b/src/include/utils/multirangetypes.h @@ -14,8 +14,8 @@ #ifndef MULTIRANGETYPES_H #define MULTIRANGETYPES_H +#include "utils/rangetypes.h" #include "utils/typcache.h" -#include "utils/expandeddatum.h" /* @@ -56,33 +56,48 @@ typedef struct */ /* internal versions of the above */ -extern bool multirange_eq_internal(TypeCacheEntry *typcache, MultirangeType *mr1, - MultirangeType *mr2); -extern bool multirange_ne_internal(TypeCacheEntry *typcache, MultirangeType *mr1, - MultirangeType *mr2); -extern bool multirange_contains_elem_internal(TypeCacheEntry *typcache, MultirangeType *mr, +extern bool multirange_eq_internal(TypeCacheEntry *rangetyp, + const MultirangeType *mr1, + const MultirangeType *mr2); +extern bool multirange_ne_internal(TypeCacheEntry *rangetyp, + const MultirangeType *mr1, + const MultirangeType *mr2); +extern bool multirange_contains_elem_internal(TypeCacheEntry *rangetyp, + const MultirangeType *mr, Datum elem); -extern bool multirange_contains_range_internal(TypeCacheEntry *typcache, MultirangeType *mr, - RangeType *r); -extern bool range_contains_multirange_internal(TypeCacheEntry *typcache, RangeType *r, - MultirangeType *mr); -extern bool multirange_contains_multirange_internal(TypeCacheEntry *typcache, - MultirangeType *mr1, - MultirangeType *mr2); -extern bool range_overlaps_multirange_internal(TypeCacheEntry *typcache, RangeType *r, - MultirangeType *mr); -extern bool multirange_overlaps_multirange_internal(TypeCacheEntry *typcache, - MultirangeType *mr1, - MultirangeType *mr2); -extern bool range_before_multirange_internal(TypeCacheEntry *typcache, RangeType *r, - MultirangeType *mr); -extern bool range_after_multirange_internal(TypeCacheEntry *typcache, RangeType *r, - MultirangeType *mr); -extern bool range_adjacent_multirange_internal(TypeCacheEntry *typcache, RangeType *r, - MultirangeType *mr); -extern bool multirange_before_multirange_internal(TypeCacheEntry *typcache, - MultirangeType *mr1, - MultirangeType *mr2); +extern bool multirange_contains_range_internal(TypeCacheEntry *rangetyp, + const MultirangeType *mr, + const RangeType *r); +extern bool range_contains_multirange_internal(TypeCacheEntry *rangetyp, + const RangeType *r, + const MultirangeType *mr); +extern bool multirange_contains_multirange_internal(TypeCacheEntry *rangetyp, + const MultirangeType *mr1, + const MultirangeType *mr2); +extern bool range_overlaps_multirange_internal(TypeCacheEntry *rangetyp, + const RangeType *r, + const MultirangeType *mr); +extern bool multirange_overlaps_multirange_internal(TypeCacheEntry *rangetyp, + const MultirangeType *mr1, + const MultirangeType *mr2); +extern bool range_overleft_multirange_internal(TypeCacheEntry *rangetyp, + const RangeType *r, + const MultirangeType *mr); +extern bool range_overright_multirange_internal(TypeCacheEntry *rangetyp, + const RangeType *r, + const MultirangeType *mr); +extern bool range_before_multirange_internal(TypeCacheEntry *rangetyp, + const RangeType *r, + const MultirangeType *mr); +extern bool range_after_multirange_internal(TypeCacheEntry *rangetyp, + const RangeType *r, + const MultirangeType *mr); +extern bool range_adjacent_multirange_internal(TypeCacheEntry *rangetyp, + const RangeType *r, + const MultirangeType *mr); +extern bool multirange_before_multirange_internal(TypeCacheEntry *rangetyp, + const MultirangeType *mr1, + const MultirangeType *mr2); extern MultirangeType *multirange_minus_internal(Oid mltrngtypoid, TypeCacheEntry *rangetyp, int32 range_count1, From db6335b5b1d6654b0e3104f36817800d127c1c91 Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Tue, 29 Dec 2020 23:36:43 +0300 Subject: [PATCH 004/240] Add support of multirange matching to the existing range GiST indexes 6df7a9698b has introduced a set of operators between ranges and multiranges. Existing GiST indexes for ranges could easily support majority of them. This commit adds support for new operators to the existing range GiST indexes. New operators resides the same strategy numbers as existing ones. Appropriate check function is determined using the subtype. Catversion is bumped. --- doc/src/sgml/gist.sgml | 35 +- doc/src/sgml/rangetypes.sgml | 21 +- src/backend/utils/adt/multirangetypes.c | 21 + src/backend/utils/adt/rangetypes_gist.c | 393 +++++++++++++++--- src/include/catalog/catversion.h | 2 +- src/include/catalog/pg_amop.dat | 80 ++++ src/include/catalog/pg_amproc.dat | 18 + src/include/catalog/pg_opclass.dat | 2 + src/include/catalog/pg_opfamily.dat | 2 + src/include/catalog/pg_proc.dat | 8 + src/include/utils/multirangetypes.h | 2 + src/test/regress/expected/multirangetypes.out | 257 ++++++++++++ src/test/regress/expected/rangetypes.out | 162 ++++++++ src/test/regress/sql/multirangetypes.sql | 63 +++ src/test/regress/sql/rangetypes.sql | 27 ++ 15 files changed, 1024 insertions(+), 69 deletions(-) diff --git a/doc/src/sgml/gist.sgml b/doc/src/sgml/gist.sgml index d1b6cc9a01a31..dc1f192bddfdf 100644 --- a/doc/src/sgml/gist.sgml +++ b/doc/src/sgml/gist.sgml @@ -116,6 +116,29 @@ >= (inet,inet) && (inet,inet) + + multirange_ops + = (anymultirange,anymultirange) + + + && (anymultirange,anymultirange) + && (anymultirange,anyrange) + @> (anymultirange,anyelement) + @> (anymultirange,anymultirange) + @> (anymultirange,anyrange) + <@ (anymultirange,anymultirange) + <@ (anymultirange,anyrange) + << (anymultirange,anymultirange) + << (anymultirange,anyrange) + >> (anymultirange,anymultirange) + >> (anymultirange,anyrange) + &< (anymultirange,anymultirange) + &< (anymultirange,anyrange) + &> (anymultirange,anymultirange) + &> (anymultirange,anyrange) + -|- (anymultirange,anymultirange) + -|- (anymultirange,anyrange) + point_ops |>> (point,point) @@ -149,19 +172,27 @@ ~ (polygon,polygon) - range_ops + range_ops = (anyrange,anyrange) - + && (anyrange,anyrange) + && (anyrange,anymultirange) @> (anyrange,anyelement) @> (anyrange,anyrange) + @> (anyrange,anymultirange) <@ (anyrange,anyrange) + <@ (anyrange,anymultirange) << (anyrange,anyrange) + << (anyrange,anymultirange) >> (anyrange,anyrange) + >> (anyrange,anymultirange) &< (anyrange,anyrange) + &< (anyrange,anymultirange) &> (anyrange,anyrange) + &> (anyrange,anymultirange) -|- (anyrange,anyrange) + -|- (anyrange,anymultirange) tsquery_ops diff --git a/doc/src/sgml/rangetypes.sgml b/doc/src/sgml/rangetypes.sgml index 859079c69cad9..91e353d4fdb91 100644 --- a/doc/src/sgml/rangetypes.sgml +++ b/doc/src/sgml/rangetypes.sgml @@ -469,11 +469,13 @@ SELECT '[11:10, 23:00]'::timerange; GiST and SP-GiST indexes can be created for table columns of range types. + GiST indexes can be also created for table columns of multirange types. For instance, to create a GiST index: CREATE INDEX reservation_idx ON reservation USING GIST (during); - A GiST or SP-GiST index can accelerate queries involving these range operators: + A GiST or SP-GiST index on ranges can accelerate queries involving these + range operators: =, &&, <@, @@ -482,8 +484,21 @@ CREATE INDEX reservation_idx ON reservation USING GIST (during); >>, -|-, &<, and - &> - (see for more information). + &>. + A GiST index on multiranges can accelerate queries involving the same + set of multirange operators. + A GiST index on ranges and GiST index on multiranges can also accelerate + queries involving these cross-type range to multirange and multirange to + range operators correspondingly: + &&, + <@, + @>, + <<, + >>, + -|-, + &<, and + &>. + See for more information. diff --git a/src/backend/utils/adt/multirangetypes.c b/src/backend/utils/adt/multirangetypes.c index a77299147e7fb..2d4cee92bcced 100644 --- a/src/backend/utils/adt/multirangetypes.c +++ b/src/backend/utils/adt/multirangetypes.c @@ -768,6 +768,27 @@ multirange_get_bounds(TypeCacheEntry *rangetyp, upper->lower = false; } +/* + * Construct union range from the multirange. + */ +RangeType * +multirange_get_union_range(TypeCacheEntry *rangetyp, + const MultirangeType *mr) +{ + RangeBound lower, + upper, + tmp; + + if (MultirangeIsEmpty(mr)) + return make_empty_range(rangetyp); + + multirange_get_bounds(rangetyp, mr, 0, &lower, &tmp); + multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1, &tmp, &upper); + + return make_range(rangetyp, &lower, &upper, false); +} + + /* * multirange_deserialize: deconstruct a multirange value * diff --git a/src/backend/utils/adt/rangetypes_gist.c b/src/backend/utils/adt/rangetypes_gist.c index 75069c3ac2c8a..435b242c8abec 100644 --- a/src/backend/utils/adt/rangetypes_gist.c +++ b/src/backend/utils/adt/rangetypes_gist.c @@ -19,6 +19,7 @@ #include "utils/datum.h" #include "utils/float.h" #include "utils/fmgrprotos.h" +#include "utils/multirangetypes.h" #include "utils/rangetypes.h" /* @@ -135,12 +136,30 @@ typedef struct static RangeType *range_super_union(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2); -static bool range_gist_consistent_int(TypeCacheEntry *typcache, - StrategyNumber strategy, const RangeType *key, - Datum query); -static bool range_gist_consistent_leaf(TypeCacheEntry *typcache, - StrategyNumber strategy, const RangeType *key, - Datum query); +static bool range_gist_consistent_int_range(TypeCacheEntry *typcache, + StrategyNumber strategy, + const RangeType *key, + const RangeType *query); +static bool range_gist_consistent_int_multirange(TypeCacheEntry *typcache, + StrategyNumber strategy, + const RangeType *key, + const MultirangeType *query); +static bool range_gist_consistent_int_element(TypeCacheEntry *typcache, + StrategyNumber strategy, + const RangeType *key, + Datum query); +static bool range_gist_consistent_leaf_range(TypeCacheEntry *typcache, + StrategyNumber strategy, + const RangeType *key, + const RangeType *query); +static bool range_gist_consistent_leaf_multirange(TypeCacheEntry *typcache, + StrategyNumber strategy, + const RangeType *key, + const MultirangeType *query); +static bool range_gist_consistent_leaf_element(TypeCacheEntry *typcache, + StrategyNumber strategy, + const RangeType *key, + Datum query); static void range_gist_fallback_split(TypeCacheEntry *typcache, GistEntryVector *entryvec, GIST_SPLITVEC *v); @@ -174,8 +193,8 @@ range_gist_consistent(PG_FUNCTION_ARGS) GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); Datum query = PG_GETARG_DATUM(1); StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); - - /* Oid subtype = PG_GETARG_OID(3); */ + bool result; + Oid subtype = PG_GETARG_OID(3); bool *recheck = (bool *) PG_GETARG_POINTER(4); RangeType *key = DatumGetRangeTypeP(entry->key); TypeCacheEntry *typcache; @@ -185,12 +204,119 @@ range_gist_consistent(PG_FUNCTION_ARGS) typcache = range_get_typcache(fcinfo, RangeTypeGetOid(key)); + /* + * Perform consistent checking using function corresponding to key type + * (leaf or internal) and query subtype (range, multirange, or element). + * Note that invalid subtype means that query type matches key type + * (range). + */ if (GIST_LEAF(entry)) - PG_RETURN_BOOL(range_gist_consistent_leaf(typcache, strategy, - key, query)); + { + if (!OidIsValid(subtype) || subtype == ANYRANGEOID) + result = range_gist_consistent_leaf_range(typcache, strategy, key, + DatumGetRangeTypeP(query)); + else if (subtype == ANYMULTIRANGEOID) + result = range_gist_consistent_leaf_multirange(typcache, strategy, key, + DatumGetMultirangeTypeP(query)); + else + result = range_gist_consistent_leaf_element(typcache, strategy, + key, query); + } else - PG_RETURN_BOOL(range_gist_consistent_int(typcache, strategy, - key, query)); + { + if (!OidIsValid(subtype) || subtype == ANYRANGEOID) + result = range_gist_consistent_int_range(typcache, strategy, key, + DatumGetRangeTypeP(query)); + else if (subtype == ANYMULTIRANGEOID) + result = range_gist_consistent_int_multirange(typcache, strategy, key, + DatumGetMultirangeTypeP(query)); + else + result = range_gist_consistent_int_element(typcache, strategy, + key, query); + } + PG_RETURN_BOOL(result); +} + +/* + * GiST compress method for multiranges: multirange is approximated as union + * range with no gaps. + */ +Datum +multirange_gist_compress(PG_FUNCTION_ARGS) +{ + GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + + if (entry->leafkey) + { + MultirangeType *mr = DatumGetMultirangeTypeP(entry->key); + RangeType *r; + TypeCacheEntry *typcache; + GISTENTRY *retval = palloc(sizeof(GISTENTRY)); + + typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr)); + r = multirange_get_union_range(typcache->rngtype, mr); + + gistentryinit(*retval, RangeTypePGetDatum(r), + entry->rel, entry->page, entry->offset, false); + + PG_RETURN_POINTER(retval); + } + + PG_RETURN_POINTER(entry); +} + +/* GiST query consistency check for multiranges */ +Datum +multirange_gist_consistent(PG_FUNCTION_ARGS) +{ + GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + Datum query = PG_GETARG_DATUM(1); + StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); + bool result; + Oid subtype = PG_GETARG_OID(3); + bool *recheck = (bool *) PG_GETARG_POINTER(4); + RangeType *key = DatumGetRangeTypeP(entry->key); + TypeCacheEntry *typcache; + + /* + * All operators served by this function are inexact because multirange is + * approximated by union range with no gaps. + */ + *recheck = true; + + typcache = range_get_typcache(fcinfo, RangeTypeGetOid(key)); + + /* + * Perform consistent checking using function corresponding to key type + * (leaf or internal) and query subtype (range, multirange, or element). + * Note that invalid subtype means that query type matches key type + * (multirange). + */ + if (GIST_LEAF(entry)) + { + if (!OidIsValid(subtype) || subtype == ANYMULTIRANGEOID) + result = range_gist_consistent_leaf_multirange(typcache, strategy, key, + DatumGetMultirangeTypeP(query)); + else if (subtype == ANYRANGEOID) + result = range_gist_consistent_leaf_range(typcache, strategy, key, + DatumGetRangeTypeP(query)); + else + result = range_gist_consistent_leaf_element(typcache, strategy, + key, query); + } + else + { + if (!OidIsValid(subtype) || subtype == ANYMULTIRANGEOID) + result = range_gist_consistent_int_multirange(typcache, strategy, key, + DatumGetMultirangeTypeP(query)); + else if (subtype == ANYRANGEOID) + result = range_gist_consistent_int_range(typcache, strategy, key, + DatumGetRangeTypeP(query)); + else + result = range_gist_consistent_int_element(typcache, strategy, + key, query); + } + PG_RETURN_BOOL(result); } /* form union range */ @@ -758,49 +884,67 @@ range_super_union(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2) return result; } +static bool +multirange_union_range_equal(TypeCacheEntry *typcache, + const RangeType *r, + const MultirangeType *mr) +{ + RangeBound lower1, + upper1, + lower2, + upper2, + tmp; + bool empty; + + if (RangeIsEmpty(r) || MultirangeIsEmpty(mr)) + return (RangeIsEmpty(r) && MultirangeIsEmpty(mr)); + + range_deserialize(typcache, r, &lower1, &upper1, &empty); + Assert(!empty); + multirange_get_bounds(typcache, mr, 0, &lower2, &tmp); + multirange_get_bounds(typcache, mr, mr->rangeCount - 1, &tmp, &upper2); + + return (range_cmp_bounds(typcache, &lower1, &lower2) == 0 && + range_cmp_bounds(typcache, &upper1, &upper2) == 0); +} + /* - * GiST consistent test on an index internal page + * GiST consistent test on an index internal page with range query */ static bool -range_gist_consistent_int(TypeCacheEntry *typcache, StrategyNumber strategy, - const RangeType *key, Datum query) +range_gist_consistent_int_range(TypeCacheEntry *typcache, + StrategyNumber strategy, + const RangeType *key, + const RangeType *query) { switch (strategy) { case RANGESTRAT_BEFORE: - if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeTypeP(query))) + if (RangeIsEmpty(key) || RangeIsEmpty(query)) return false; - return (!range_overright_internal(typcache, key, - DatumGetRangeTypeP(query))); + return (!range_overright_internal(typcache, key, query)); case RANGESTRAT_OVERLEFT: - if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeTypeP(query))) + if (RangeIsEmpty(key) || RangeIsEmpty(query)) return false; - return (!range_after_internal(typcache, key, - DatumGetRangeTypeP(query))); + return (!range_after_internal(typcache, key, query)); case RANGESTRAT_OVERLAPS: - return range_overlaps_internal(typcache, key, - DatumGetRangeTypeP(query)); + return range_overlaps_internal(typcache, key, query); case RANGESTRAT_OVERRIGHT: - if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeTypeP(query))) + if (RangeIsEmpty(key) || RangeIsEmpty(query)) return false; - return (!range_before_internal(typcache, key, - DatumGetRangeTypeP(query))); + return (!range_before_internal(typcache, key, query)); case RANGESTRAT_AFTER: - if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeTypeP(query))) + if (RangeIsEmpty(key) || RangeIsEmpty(query)) return false; - return (!range_overleft_internal(typcache, key, - DatumGetRangeTypeP(query))); + return (!range_overleft_internal(typcache, key, query)); case RANGESTRAT_ADJACENT: - if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeTypeP(query))) + if (RangeIsEmpty(key) || RangeIsEmpty(query)) return false; - if (range_adjacent_internal(typcache, key, - DatumGetRangeTypeP(query))) + if (range_adjacent_internal(typcache, key, query)) return true; - return range_overlaps_internal(typcache, key, - DatumGetRangeTypeP(query)); + return range_overlaps_internal(typcache, key, query); case RANGESTRAT_CONTAINS: - return range_contains_internal(typcache, key, - DatumGetRangeTypeP(query)); + return range_contains_internal(typcache, key, query); case RANGESTRAT_CONTAINED_BY: /* @@ -810,20 +954,16 @@ range_gist_consistent_int(TypeCacheEntry *typcache, StrategyNumber strategy, */ if (RangeIsOrContainsEmpty(key)) return true; - return range_overlaps_internal(typcache, key, - DatumGetRangeTypeP(query)); - case RANGESTRAT_CONTAINS_ELEM: - return range_contains_elem_internal(typcache, key, query); + return range_overlaps_internal(typcache, key, query); case RANGESTRAT_EQ: /* * If query is empty, descend only if the key is or contains any * empty ranges. Otherwise, descend if key contains query. */ - if (RangeIsEmpty(DatumGetRangeTypeP(query))) + if (RangeIsEmpty(query)) return RangeIsOrContainsEmpty(key); - return range_contains_internal(typcache, key, - DatumGetRangeTypeP(query)); + return range_contains_internal(typcache, key, query); default: elog(ERROR, "unrecognized range strategy: %d", strategy); return false; /* keep compiler quiet */ @@ -831,42 +971,169 @@ range_gist_consistent_int(TypeCacheEntry *typcache, StrategyNumber strategy, } /* - * GiST consistent test on an index leaf page + * GiST consistent test on an index internal page with multirange query */ static bool -range_gist_consistent_leaf(TypeCacheEntry *typcache, StrategyNumber strategy, - const RangeType *key, Datum query) +range_gist_consistent_int_multirange(TypeCacheEntry *typcache, + StrategyNumber strategy, + const RangeType *key, + const MultirangeType *query) { switch (strategy) { case RANGESTRAT_BEFORE: - return range_before_internal(typcache, key, - DatumGetRangeTypeP(query)); + if (RangeIsEmpty(key) || MultirangeIsEmpty(query)) + return false; + return (!range_overright_multirange_internal(typcache, key, query)); case RANGESTRAT_OVERLEFT: - return range_overleft_internal(typcache, key, - DatumGetRangeTypeP(query)); + if (RangeIsEmpty(key) || MultirangeIsEmpty(query)) + return false; + return (!range_after_multirange_internal(typcache, key, query)); case RANGESTRAT_OVERLAPS: - return range_overlaps_internal(typcache, key, - DatumGetRangeTypeP(query)); + return range_overlaps_multirange_internal(typcache, key, query); case RANGESTRAT_OVERRIGHT: - return range_overright_internal(typcache, key, - DatumGetRangeTypeP(query)); + if (RangeIsEmpty(key) || MultirangeIsEmpty(query)) + return false; + return (!range_before_multirange_internal(typcache, key, query)); case RANGESTRAT_AFTER: - return range_after_internal(typcache, key, - DatumGetRangeTypeP(query)); + if (RangeIsEmpty(key) || MultirangeIsEmpty(query)) + return false; + return (!range_overleft_multirange_internal(typcache, key, query)); case RANGESTRAT_ADJACENT: - return range_adjacent_internal(typcache, key, - DatumGetRangeTypeP(query)); + if (RangeIsEmpty(key) || MultirangeIsEmpty(query)) + return false; + if (range_adjacent_multirange_internal(typcache, key, query)) + return true; + return range_overlaps_multirange_internal(typcache, key, query); case RANGESTRAT_CONTAINS: - return range_contains_internal(typcache, key, - DatumGetRangeTypeP(query)); + return range_contains_multirange_internal(typcache, key, query); case RANGESTRAT_CONTAINED_BY: - return range_contained_by_internal(typcache, key, - DatumGetRangeTypeP(query)); + + /* + * Empty ranges are contained by anything, so if key is or + * contains any empty ranges, we must descend into it. Otherwise, + * descend only if key overlaps the query. + */ + if (RangeIsOrContainsEmpty(key)) + return true; + return range_overlaps_multirange_internal(typcache, key, query); + case RANGESTRAT_EQ: + + /* + * If query is empty, descend only if the key is or contains any + * empty ranges. Otherwise, descend if key contains query. + */ + if (MultirangeIsEmpty(query)) + return RangeIsOrContainsEmpty(key); + return range_contains_multirange_internal(typcache, key, query); + default: + elog(ERROR, "unrecognized range strategy: %d", strategy); + return false; /* keep compiler quiet */ + } +} + +/* + * GiST consistent test on an index internal page with element query + */ +static bool +range_gist_consistent_int_element(TypeCacheEntry *typcache, + StrategyNumber strategy, + const RangeType *key, + Datum query) +{ + switch (strategy) + { case RANGESTRAT_CONTAINS_ELEM: return range_contains_elem_internal(typcache, key, query); + default: + elog(ERROR, "unrecognized range strategy: %d", strategy); + return false; /* keep compiler quiet */ + } +} + +/* + * GiST consistent test on an index leaf page with range query + */ +static bool +range_gist_consistent_leaf_range(TypeCacheEntry *typcache, + StrategyNumber strategy, + const RangeType *key, + const RangeType *query) +{ + switch (strategy) + { + case RANGESTRAT_BEFORE: + return range_before_internal(typcache, key, query); + case RANGESTRAT_OVERLEFT: + return range_overleft_internal(typcache, key, query); + case RANGESTRAT_OVERLAPS: + return range_overlaps_internal(typcache, key, query); + case RANGESTRAT_OVERRIGHT: + return range_overright_internal(typcache, key, query); + case RANGESTRAT_AFTER: + return range_after_internal(typcache, key, query); + case RANGESTRAT_ADJACENT: + return range_adjacent_internal(typcache, key, query); + case RANGESTRAT_CONTAINS: + return range_contains_internal(typcache, key, query); + case RANGESTRAT_CONTAINED_BY: + return range_contained_by_internal(typcache, key, query); + case RANGESTRAT_EQ: + return range_eq_internal(typcache, key, query); + default: + elog(ERROR, "unrecognized range strategy: %d", strategy); + return false; /* keep compiler quiet */ + } +} + +/* + * GiST consistent test on an index leaf page with multirange query + */ +static bool +range_gist_consistent_leaf_multirange(TypeCacheEntry *typcache, + StrategyNumber strategy, + const RangeType *key, + const MultirangeType *query) +{ + switch (strategy) + { + case RANGESTRAT_BEFORE: + return range_before_multirange_internal(typcache, key, query); + case RANGESTRAT_OVERLEFT: + return range_overleft_multirange_internal(typcache, key, query); + case RANGESTRAT_OVERLAPS: + return range_overlaps_multirange_internal(typcache, key, query); + case RANGESTRAT_OVERRIGHT: + return range_overright_multirange_internal(typcache, key, query); + case RANGESTRAT_AFTER: + return range_after_multirange_internal(typcache, key, query); + case RANGESTRAT_ADJACENT: + return range_adjacent_multirange_internal(typcache, key, query); + case RANGESTRAT_CONTAINS: + return range_contains_multirange_internal(typcache, key, query); + case RANGESTRAT_CONTAINED_BY: + return multirange_contains_range_internal(typcache, query, key); case RANGESTRAT_EQ: - return range_eq_internal(typcache, key, DatumGetRangeTypeP(query)); + return multirange_union_range_equal(typcache, key, query); + default: + elog(ERROR, "unrecognized range strategy: %d", strategy); + return false; /* keep compiler quiet */ + } +} + +/* + * GiST consistent test on an index leaf page with element query + */ +static bool +range_gist_consistent_leaf_element(TypeCacheEntry *typcache, + StrategyNumber strategy, + const RangeType *key, + Datum query) +{ + switch (strategy) + { + case RANGESTRAT_CONTAINS_ELEM: + return range_contains_elem_internal(typcache, key, query); default: elog(ERROR, "unrecognized range strategy: %d", strategy); return false; /* keep compiler quiet */ diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 4fd88a477306c..db4814e57afa5 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202012291 +#define CATALOG_VERSION_NO 202012293 #endif diff --git a/src/include/catalog/pg_amop.dat b/src/include/catalog/pg_amop.dat index 78d7d2c52329c..bbe1a6ddf8e64 100644 --- a/src/include/catalog/pg_amop.dat +++ b/src/include/catalog/pg_amop.dat @@ -1346,27 +1346,51 @@ { amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', amoprighttype => 'anyrange', amopstrategy => '1', amopopr => '<<(anyrange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anymultirange', amopstrategy => '1', + amopopr => '<<(anyrange,anymultirange)', amopmethod => 'gist' }, { amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', amoprighttype => 'anyrange', amopstrategy => '2', amopopr => '&<(anyrange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anymultirange', amopstrategy => '2', + amopopr => '&<(anyrange,anymultirange)', amopmethod => 'gist' }, { amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', amoprighttype => 'anyrange', amopstrategy => '3', amopopr => '&&(anyrange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anymultirange', amopstrategy => '3', + amopopr => '&&(anyrange,anymultirange)', amopmethod => 'gist' }, { amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', amoprighttype => 'anyrange', amopstrategy => '4', amopopr => '&>(anyrange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anymultirange', amopstrategy => '4', + amopopr => '&>(anyrange,anymultirange)', amopmethod => 'gist' }, { amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', amoprighttype => 'anyrange', amopstrategy => '5', amopopr => '>>(anyrange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anymultirange', amopstrategy => '5', + amopopr => '>>(anyrange,anymultirange)', amopmethod => 'gist' }, { amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', amoprighttype => 'anyrange', amopstrategy => '6', amopopr => '-|-(anyrange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anymultirange', amopstrategy => '6', + amopopr => '-|-(anyrange,anymultirange)', amopmethod => 'gist' }, { amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', amoprighttype => 'anyrange', amopstrategy => '7', amopopr => '@>(anyrange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anymultirange', amopstrategy => '7', + amopopr => '@>(anyrange,anymultirange)', amopmethod => 'gist' }, { amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', amoprighttype => 'anyrange', amopstrategy => '8', amopopr => '<@(anyrange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anymultirange', amopstrategy => '8', + amopopr => '<@(anyrange,anymultirange)', amopmethod => 'gist' }, { amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', amoprighttype => 'anyelement', amopstrategy => '16', amopopr => '@>(anyrange,anyelement)', amopmethod => 'gist' }, @@ -1374,6 +1398,62 @@ amoprighttype => 'anyrange', amopstrategy => '18', amopopr => '=(anyrange,anyrange)', amopmethod => 'gist' }, +# GiST multirange_ops +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anymultirange', amopstrategy => '1', + amopopr => '<<(anymultirange,anymultirange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anyrange', amopstrategy => '1', + amopopr => '<<(anymultirange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anymultirange', amopstrategy => '2', + amopopr => '&<(anymultirange,anymultirange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anyrange', amopstrategy => '2', + amopopr => '&<(anymultirange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anymultirange', amopstrategy => '3', + amopopr => '&&(anymultirange,anymultirange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anyrange', amopstrategy => '3', + amopopr => '&&(anymultirange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anymultirange', amopstrategy => '4', + amopopr => '&>(anymultirange,anymultirange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anyrange', amopstrategy => '4', + amopopr => '&>(anymultirange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anymultirange', amopstrategy => '5', + amopopr => '>>(anymultirange,anymultirange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anyrange', amopstrategy => '5', + amopopr => '>>(anymultirange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anymultirange', amopstrategy => '6', + amopopr => '-|-(anymultirange,anymultirange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anyrange', amopstrategy => '6', + amopopr => '-|-(anymultirange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anymultirange', amopstrategy => '7', + amopopr => '@>(anymultirange,anymultirange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anyrange', amopstrategy => '7', + amopopr => '@>(anymultirange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anymultirange', amopstrategy => '8', + amopopr => '<@(anymultirange,anymultirange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anyrange', amopstrategy => '8', + amopopr => '<@(anymultirange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anyelement', amopstrategy => '16', + amopopr => '@>(anymultirange,anyelement)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anymultirange', amopstrategy => '18', + amopopr => '=(anymultirange,anymultirange)', amopmethod => 'gist' }, + # btree multirange_ops { amopfamily => 'btree/multirange_ops', amoplefttype => 'anymultirange', amoprighttype => 'anymultirange', amopstrategy => '1', diff --git a/src/include/catalog/pg_amproc.dat b/src/include/catalog/pg_amproc.dat index 9d423d535cd59..68d72ec732a44 100644 --- a/src/include/catalog/pg_amproc.dat +++ b/src/include/catalog/pg_amproc.dat @@ -612,6 +612,24 @@ amprocrighttype => 'inet', amprocnum => '7', amproc => 'inet_gist_same' }, { amprocfamily => 'gist/network_ops', amproclefttype => 'inet', amprocrighttype => 'inet', amprocnum => '9', amproc => 'inet_gist_fetch' }, +{ amprocfamily => 'gist/multirange_ops', amproclefttype => 'anymultirange', + amprocrighttype => 'anymultirange', amprocnum => '1', + amproc => 'multirange_gist_consistent' }, +{ amprocfamily => 'gist/multirange_ops', amproclefttype => 'anymultirange', + amprocrighttype => 'anymultirange', amprocnum => '2', + amproc => 'range_gist_union' }, +{ amprocfamily => 'gist/multirange_ops', amproclefttype => 'anymultirange', + amprocrighttype => 'anymultirange', amprocnum => '3', + amproc => 'multirange_gist_compress' }, +{ amprocfamily => 'gist/multirange_ops', amproclefttype => 'anymultirange', + amprocrighttype => 'anymultirange', amprocnum => '5', + amproc => 'range_gist_penalty' }, +{ amprocfamily => 'gist/multirange_ops', amproclefttype => 'anymultirange', + amprocrighttype => 'anymultirange', amprocnum => '6', + amproc => 'range_gist_picksplit' }, +{ amprocfamily => 'gist/multirange_ops', amproclefttype => 'anymultirange', + amprocrighttype => 'anymultirange', amprocnum => '7', + amproc => 'range_gist_same' }, # gin { amprocfamily => 'gin/array_ops', amproclefttype => 'anyarray', diff --git a/src/include/catalog/pg_opclass.dat b/src/include/catalog/pg_opclass.dat index 4c5e475ff7b59..12cad6941866f 100644 --- a/src/include/catalog/pg_opclass.dat +++ b/src/include/catalog/pg_opclass.dat @@ -236,6 +236,8 @@ opcintype => 'anymultirange' }, { opcmethod => 'hash', opcname => 'multirange_ops', opcfamily => 'hash/multirange_ops', opcintype => 'anymultirange' }, +{ opcmethod => 'gist', opcname => 'multirange_ops', opcfamily => 'gist/multirange_ops', + opcintype => 'anymultirange', opckeytype => 'anyrange' }, { opcmethod => 'spgist', opcname => 'box_ops', opcfamily => 'spgist/box_ops', opcintype => 'box' }, { opcmethod => 'spgist', opcname => 'quad_point_ops', diff --git a/src/include/catalog/pg_opfamily.dat b/src/include/catalog/pg_opfamily.dat index fe42dfc0f8ffb..ac8338f34b120 100644 --- a/src/include/catalog/pg_opfamily.dat +++ b/src/include/catalog/pg_opfamily.dat @@ -236,5 +236,7 @@ opfmethod => 'btree', opfname => 'multirange_ops' }, { oid => '4225', opfmethod => 'hash', opfname => 'multirange_ops' }, +{ oid => '8021', + opfmethod => 'gist', opfname => 'multirange_ops' }, ] diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 834ee86c791b4..139f4a08bd5b7 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -9922,6 +9922,14 @@ { oid => '3881', descr => 'GiST support', proname => 'range_gist_same', prorettype => 'internal', proargtypes => 'anyrange anyrange internal', prosrc => 'range_gist_same' }, +{ oid => '8017', descr => 'GiST support', + proname => 'multirange_gist_consistent', prorettype => 'bool', + proargtypes => 'internal anymultirange int2 oid internal', + prosrc => 'multirange_gist_consistent' }, +{ oid => '8019', descr => 'GiST support', + proname => 'multirange_gist_compress', prorettype => 'internal', + proargtypes => 'internal', + prosrc => 'multirange_gist_compress' }, { oid => '3902', descr => 'hash a range', proname => 'hash_range', prorettype => 'int4', proargtypes => 'anyrange', prosrc => 'hash_range' }, diff --git a/src/include/utils/multirangetypes.h b/src/include/utils/multirangetypes.h index ff2e58744a908..1d877f08b56be 100644 --- a/src/include/utils/multirangetypes.h +++ b/src/include/utils/multirangetypes.h @@ -129,5 +129,7 @@ extern void multirange_get_bounds(TypeCacheEntry *rangetyp, RangeBound *lower, RangeBound *upper); extern RangeType *multirange_get_range(TypeCacheEntry *rangetyp, const MultirangeType *multirange, int i); +extern RangeType *multirange_get_union_range(TypeCacheEntry *rangetyp, + const MultirangeType *mr); #endif /* MULTIRANGETYPES_H */ diff --git a/src/test/regress/expected/multirangetypes.out b/src/test/regress/expected/multirangetypes.out index aa7232efc5779..86011a02a1e69 100644 --- a/src/test/regress/expected/multirangetypes.out +++ b/src/test/regress/expected/multirangetypes.out @@ -2219,6 +2219,263 @@ SELECT '{[1,4), [7,10)}'::nummultirange * '{[0,2), [3,8), [9,12)}'::nummultirang {[1,2),[3,4),[7,8),[9,10)} (1 row) +-- test GiST index +create table test_multirange_gist(mr int4multirange); +insert into test_multirange_gist select int4multirange(int4range(g, g+10),int4range(g+20, g+30),int4range(g+40, g+50)) from generate_series(1,2000) g; +insert into test_multirange_gist select '{}'::int4multirange from generate_series(1,500) g; +insert into test_multirange_gist select int4multirange(int4range(g, g+10000)) from generate_series(1,1000) g; +insert into test_multirange_gist select int4multirange(int4range(NULL, g*10, '(]'), int4range(g*10, g*20, '(]')) from generate_series(1,100) g; +insert into test_multirange_gist select int4multirange(int4range(g*10, g*20, '(]'), int4range(g*20, NULL, '(]')) from generate_series(1,100) g; +create index test_mulrirange_gist_idx on test_multirange_gist using gist (mr); +-- first, verify non-indexed results +SET enable_seqscan = t; +SET enable_indexscan = f; +SET enable_bitmapscan = f; +select count(*) from test_multirange_gist where mr @> 'empty'::int4range; + count +------- + 3700 +(1 row) + +select count(*) from test_multirange_gist where mr = int4multirange(int4range(10,20), int4range(30,40), int4range(50,60)); + count +------- + 1 +(1 row) + +select count(*) from test_multirange_gist where mr @> 10; + count +------- + 120 +(1 row) + +select count(*) from test_multirange_gist where mr @> int4range(10,20); + count +------- + 111 +(1 row) + +select count(*) from test_multirange_gist where mr && int4range(10,20); + count +------- + 139 +(1 row) + +select count(*) from test_multirange_gist where mr <@ int4range(10,50); + count +------- + 500 +(1 row) + +select count(*) from test_multirange_gist where mr << int4range(100,500); + count +------- + 54 +(1 row) + +select count(*) from test_multirange_gist where mr >> int4range(100,500); + count +------- + 2053 +(1 row) + +select count(*) from test_multirange_gist where mr &< int4range(100,500); + count +------- + 474 +(1 row) + +select count(*) from test_multirange_gist where mr &> int4range(100,500); + count +------- + 2893 +(1 row) + +select count(*) from test_multirange_gist where mr -|- int4range(100,500); + count +------- + 3 +(1 row) + +select count(*) from test_multirange_gist where mr @> '{}'::int4multirange; + count +------- + 3700 +(1 row) + +select count(*) from test_multirange_gist where mr @> int4multirange(int4range(10,20), int4range(30,40)); + count +------- + 110 +(1 row) + +select count(*) from test_multirange_gist where mr && '{(10,20),(30,40),(50,60)}'::int4multirange; + count +------- + 218 +(1 row) + +select count(*) from test_multirange_gist where mr <@ '{(10,30),(40,60),(70,90)}'::int4multirange; + count +------- + 500 +(1 row) + +select count(*) from test_multirange_gist where mr << int4multirange(int4range(100,200), int4range(400,500)); + count +------- + 54 +(1 row) + +select count(*) from test_multirange_gist where mr >> int4multirange(int4range(100,200), int4range(400,500)); + count +------- + 2053 +(1 row) + +select count(*) from test_multirange_gist where mr &< int4multirange(int4range(100,200), int4range(400,500)); + count +------- + 474 +(1 row) + +select count(*) from test_multirange_gist where mr &> int4multirange(int4range(100,200), int4range(400,500)); + count +------- + 2893 +(1 row) + +select count(*) from test_multirange_gist where mr -|- int4multirange(int4range(100,200), int4range(400,500)); + count +------- + 3 +(1 row) + +-- now check same queries using index +SET enable_seqscan = f; +SET enable_indexscan = t; +SET enable_bitmapscan = f; +select count(*) from test_multirange_gist where mr @> 'empty'::int4range; + count +------- + 3700 +(1 row) + +select count(*) from test_multirange_gist where mr = int4multirange(int4range(10,20), int4range(30,40), int4range(50,60)); + count +------- + 1 +(1 row) + +select count(*) from test_multirange_gist where mr @> 10; + count +------- + 120 +(1 row) + +select count(*) from test_multirange_gist where mr @> int4range(10,20); + count +------- + 111 +(1 row) + +select count(*) from test_multirange_gist where mr && int4range(10,20); + count +------- + 139 +(1 row) + +select count(*) from test_multirange_gist where mr <@ int4range(10,50); + count +------- + 500 +(1 row) + +select count(*) from test_multirange_gist where mr << int4range(100,500); + count +------- + 54 +(1 row) + +select count(*) from test_multirange_gist where mr >> int4range(100,500); + count +------- + 2053 +(1 row) + +select count(*) from test_multirange_gist where mr &< int4range(100,500); + count +------- + 474 +(1 row) + +select count(*) from test_multirange_gist where mr &> int4range(100,500); + count +------- + 2893 +(1 row) + +select count(*) from test_multirange_gist where mr -|- int4range(100,500); + count +------- + 3 +(1 row) + +select count(*) from test_multirange_gist where mr @> '{}'::int4multirange; + count +------- + 3700 +(1 row) + +select count(*) from test_multirange_gist where mr @> int4multirange(int4range(10,20), int4range(30,40)); + count +------- + 110 +(1 row) + +select count(*) from test_multirange_gist where mr && '{(10,20),(30,40),(50,60)}'::int4multirange; + count +------- + 218 +(1 row) + +select count(*) from test_multirange_gist where mr <@ '{(10,30),(40,60),(70,90)}'::int4multirange; + count +------- + 500 +(1 row) + +select count(*) from test_multirange_gist where mr << int4multirange(int4range(100,200), int4range(400,500)); + count +------- + 54 +(1 row) + +select count(*) from test_multirange_gist where mr >> int4multirange(int4range(100,200), int4range(400,500)); + count +------- + 2053 +(1 row) + +select count(*) from test_multirange_gist where mr &< int4multirange(int4range(100,200), int4range(400,500)); + count +------- + 474 +(1 row) + +select count(*) from test_multirange_gist where mr &> int4multirange(int4range(100,200), int4range(400,500)); + count +------- + 2893 +(1 row) + +select count(*) from test_multirange_gist where mr -|- int4multirange(int4range(100,200), int4range(400,500)); + count +------- + 3 +(1 row) + +drop table test_multirange_gist; -- -- range_agg function -- diff --git a/src/test/regress/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out index 6a1bbadc91af2..28dc995e5994f 100644 --- a/src/test/regress/expected/rangetypes.out +++ b/src/test/regress/expected/rangetypes.out @@ -862,6 +862,60 @@ select count(*) from test_range_gist where ir -|- int4range(100,500); 5 (1 row) +select count(*) from test_range_gist where ir @> '{}'::int4multirange; + count +------- + 6200 +(1 row) + +select count(*) from test_range_gist where ir @> int4multirange(int4range(10,20), int4range(30,40)); + count +------- + 107 +(1 row) + +select count(*) from test_range_gist where ir && '{(10,20),(30,40),(50,60)}'::int4multirange; + count +------- + 271 +(1 row) + +select count(*) from test_range_gist where ir <@ '{(10,30),(40,60),(70,90)}'::int4multirange; + count +------- + 1060 +(1 row) + +select count(*) from test_range_gist where ir << int4multirange(int4range(100,200), int4range(400,500)); + count +------- + 189 +(1 row) + +select count(*) from test_range_gist where ir >> int4multirange(int4range(100,200), int4range(400,500)); + count +------- + 3554 +(1 row) + +select count(*) from test_range_gist where ir &< int4multirange(int4range(100,200), int4range(400,500)); + count +------- + 1029 +(1 row) + +select count(*) from test_range_gist where ir &> int4multirange(int4range(100,200), int4range(400,500)); + count +------- + 4794 +(1 row) + +select count(*) from test_range_gist where ir -|- int4multirange(int4range(100,200), int4range(400,500)); + count +------- + 5 +(1 row) + -- now check same queries using index SET enable_seqscan = f; SET enable_indexscan = t; @@ -932,6 +986,60 @@ select count(*) from test_range_gist where ir -|- int4range(100,500); 5 (1 row) +select count(*) from test_range_gist where ir @> '{}'::int4multirange; + count +------- + 6200 +(1 row) + +select count(*) from test_range_gist where ir @> int4multirange(int4range(10,20), int4range(30,40)); + count +------- + 107 +(1 row) + +select count(*) from test_range_gist where ir && '{(10,20),(30,40),(50,60)}'::int4multirange; + count +------- + 271 +(1 row) + +select count(*) from test_range_gist where ir <@ '{(10,30),(40,60),(70,90)}'::int4multirange; + count +------- + 1060 +(1 row) + +select count(*) from test_range_gist where ir << int4multirange(int4range(100,200), int4range(400,500)); + count +------- + 189 +(1 row) + +select count(*) from test_range_gist where ir >> int4multirange(int4range(100,200), int4range(400,500)); + count +------- + 3554 +(1 row) + +select count(*) from test_range_gist where ir &< int4multirange(int4range(100,200), int4range(400,500)); + count +------- + 1029 +(1 row) + +select count(*) from test_range_gist where ir &> int4multirange(int4range(100,200), int4range(400,500)); + count +------- + 4794 +(1 row) + +select count(*) from test_range_gist where ir -|- int4multirange(int4range(100,200), int4range(400,500)); + count +------- + 5 +(1 row) + -- now check same queries using a bulk-loaded index drop index test_range_gist_idx; create index test_range_gist_idx on test_range_gist using gist (ir); @@ -1001,6 +1109,60 @@ select count(*) from test_range_gist where ir -|- int4range(100,500); 5 (1 row) +select count(*) from test_range_gist where ir @> '{}'::int4multirange; + count +------- + 6200 +(1 row) + +select count(*) from test_range_gist where ir @> int4multirange(int4range(10,20), int4range(30,40)); + count +------- + 107 +(1 row) + +select count(*) from test_range_gist where ir && '{(10,20),(30,40),(50,60)}'::int4multirange; + count +------- + 271 +(1 row) + +select count(*) from test_range_gist where ir <@ '{(10,30),(40,60),(70,90)}'::int4multirange; + count +------- + 1060 +(1 row) + +select count(*) from test_range_gist where ir << int4multirange(int4range(100,200), int4range(400,500)); + count +------- + 189 +(1 row) + +select count(*) from test_range_gist where ir >> int4multirange(int4range(100,200), int4range(400,500)); + count +------- + 3554 +(1 row) + +select count(*) from test_range_gist where ir &< int4multirange(int4range(100,200), int4range(400,500)); + count +------- + 1029 +(1 row) + +select count(*) from test_range_gist where ir &> int4multirange(int4range(100,200), int4range(400,500)); + count +------- + 4794 +(1 row) + +select count(*) from test_range_gist where ir -|- int4multirange(int4range(100,200), int4range(400,500)); + count +------- + 5 +(1 row) + -- test SP-GiST index that's been built incrementally create table test_range_spgist(ir int4range); create index test_range_spgist_idx on test_range_spgist using spgist (ir); diff --git a/src/test/regress/sql/multirangetypes.sql b/src/test/regress/sql/multirangetypes.sql index 9d7af404c98c2..2a2ee4dcdfd8f 100644 --- a/src/test/regress/sql/multirangetypes.sql +++ b/src/test/regress/sql/multirangetypes.sql @@ -414,6 +414,69 @@ SELECT '{[1,4), [7,10)}'::nummultirange * '{[-5,-4), [5,6), [9,12)}'::nummultira SELECT '{[1,4), [7,10)}'::nummultirange * '{[0,2), [3,8), [9,12)}'::nummultirange; SELECT '{[1,4), [7,10)}'::nummultirange * '{[0,2), [3,8), [9,12)}'::nummultirange; +-- test GiST index +create table test_multirange_gist(mr int4multirange); +insert into test_multirange_gist select int4multirange(int4range(g, g+10),int4range(g+20, g+30),int4range(g+40, g+50)) from generate_series(1,2000) g; +insert into test_multirange_gist select '{}'::int4multirange from generate_series(1,500) g; +insert into test_multirange_gist select int4multirange(int4range(g, g+10000)) from generate_series(1,1000) g; +insert into test_multirange_gist select int4multirange(int4range(NULL, g*10, '(]'), int4range(g*10, g*20, '(]')) from generate_series(1,100) g; +insert into test_multirange_gist select int4multirange(int4range(g*10, g*20, '(]'), int4range(g*20, NULL, '(]')) from generate_series(1,100) g; +create index test_mulrirange_gist_idx on test_multirange_gist using gist (mr); + +-- first, verify non-indexed results +SET enable_seqscan = t; +SET enable_indexscan = f; +SET enable_bitmapscan = f; + +select count(*) from test_multirange_gist where mr @> 'empty'::int4range; +select count(*) from test_multirange_gist where mr = int4multirange(int4range(10,20), int4range(30,40), int4range(50,60)); +select count(*) from test_multirange_gist where mr @> 10; +select count(*) from test_multirange_gist where mr @> int4range(10,20); +select count(*) from test_multirange_gist where mr && int4range(10,20); +select count(*) from test_multirange_gist where mr <@ int4range(10,50); +select count(*) from test_multirange_gist where mr << int4range(100,500); +select count(*) from test_multirange_gist where mr >> int4range(100,500); +select count(*) from test_multirange_gist where mr &< int4range(100,500); +select count(*) from test_multirange_gist where mr &> int4range(100,500); +select count(*) from test_multirange_gist where mr -|- int4range(100,500); +select count(*) from test_multirange_gist where mr @> '{}'::int4multirange; +select count(*) from test_multirange_gist where mr @> int4multirange(int4range(10,20), int4range(30,40)); +select count(*) from test_multirange_gist where mr && '{(10,20),(30,40),(50,60)}'::int4multirange; +select count(*) from test_multirange_gist where mr <@ '{(10,30),(40,60),(70,90)}'::int4multirange; +select count(*) from test_multirange_gist where mr << int4multirange(int4range(100,200), int4range(400,500)); +select count(*) from test_multirange_gist where mr >> int4multirange(int4range(100,200), int4range(400,500)); +select count(*) from test_multirange_gist where mr &< int4multirange(int4range(100,200), int4range(400,500)); +select count(*) from test_multirange_gist where mr &> int4multirange(int4range(100,200), int4range(400,500)); +select count(*) from test_multirange_gist where mr -|- int4multirange(int4range(100,200), int4range(400,500)); + +-- now check same queries using index +SET enable_seqscan = f; +SET enable_indexscan = t; +SET enable_bitmapscan = f; + +select count(*) from test_multirange_gist where mr @> 'empty'::int4range; +select count(*) from test_multirange_gist where mr = int4multirange(int4range(10,20), int4range(30,40), int4range(50,60)); +select count(*) from test_multirange_gist where mr @> 10; +select count(*) from test_multirange_gist where mr @> int4range(10,20); +select count(*) from test_multirange_gist where mr && int4range(10,20); +select count(*) from test_multirange_gist where mr <@ int4range(10,50); +select count(*) from test_multirange_gist where mr << int4range(100,500); +select count(*) from test_multirange_gist where mr >> int4range(100,500); +select count(*) from test_multirange_gist where mr &< int4range(100,500); +select count(*) from test_multirange_gist where mr &> int4range(100,500); +select count(*) from test_multirange_gist where mr -|- int4range(100,500); +select count(*) from test_multirange_gist where mr @> '{}'::int4multirange; +select count(*) from test_multirange_gist where mr @> int4multirange(int4range(10,20), int4range(30,40)); +select count(*) from test_multirange_gist where mr && '{(10,20),(30,40),(50,60)}'::int4multirange; +select count(*) from test_multirange_gist where mr <@ '{(10,30),(40,60),(70,90)}'::int4multirange; +select count(*) from test_multirange_gist where mr << int4multirange(int4range(100,200), int4range(400,500)); +select count(*) from test_multirange_gist where mr >> int4multirange(int4range(100,200), int4range(400,500)); +select count(*) from test_multirange_gist where mr &< int4multirange(int4range(100,200), int4range(400,500)); +select count(*) from test_multirange_gist where mr &> int4multirange(int4range(100,200), int4range(400,500)); +select count(*) from test_multirange_gist where mr -|- int4multirange(int4range(100,200), int4range(400,500)); + +drop table test_multirange_gist; + -- -- range_agg function -- diff --git a/src/test/regress/sql/rangetypes.sql b/src/test/regress/sql/rangetypes.sql index b69efede3ae49..51eddabf60f4e 100644 --- a/src/test/regress/sql/rangetypes.sql +++ b/src/test/regress/sql/rangetypes.sql @@ -232,6 +232,15 @@ select count(*) from test_range_gist where ir >> int4range(100,500); select count(*) from test_range_gist where ir &< int4range(100,500); select count(*) from test_range_gist where ir &> int4range(100,500); select count(*) from test_range_gist where ir -|- int4range(100,500); +select count(*) from test_range_gist where ir @> '{}'::int4multirange; +select count(*) from test_range_gist where ir @> int4multirange(int4range(10,20), int4range(30,40)); +select count(*) from test_range_gist where ir && '{(10,20),(30,40),(50,60)}'::int4multirange; +select count(*) from test_range_gist where ir <@ '{(10,30),(40,60),(70,90)}'::int4multirange; +select count(*) from test_range_gist where ir << int4multirange(int4range(100,200), int4range(400,500)); +select count(*) from test_range_gist where ir >> int4multirange(int4range(100,200), int4range(400,500)); +select count(*) from test_range_gist where ir &< int4multirange(int4range(100,200), int4range(400,500)); +select count(*) from test_range_gist where ir &> int4multirange(int4range(100,200), int4range(400,500)); +select count(*) from test_range_gist where ir -|- int4multirange(int4range(100,200), int4range(400,500)); -- now check same queries using index SET enable_seqscan = f; @@ -249,6 +258,15 @@ select count(*) from test_range_gist where ir >> int4range(100,500); select count(*) from test_range_gist where ir &< int4range(100,500); select count(*) from test_range_gist where ir &> int4range(100,500); select count(*) from test_range_gist where ir -|- int4range(100,500); +select count(*) from test_range_gist where ir @> '{}'::int4multirange; +select count(*) from test_range_gist where ir @> int4multirange(int4range(10,20), int4range(30,40)); +select count(*) from test_range_gist where ir && '{(10,20),(30,40),(50,60)}'::int4multirange; +select count(*) from test_range_gist where ir <@ '{(10,30),(40,60),(70,90)}'::int4multirange; +select count(*) from test_range_gist where ir << int4multirange(int4range(100,200), int4range(400,500)); +select count(*) from test_range_gist where ir >> int4multirange(int4range(100,200), int4range(400,500)); +select count(*) from test_range_gist where ir &< int4multirange(int4range(100,200), int4range(400,500)); +select count(*) from test_range_gist where ir &> int4multirange(int4range(100,200), int4range(400,500)); +select count(*) from test_range_gist where ir -|- int4multirange(int4range(100,200), int4range(400,500)); -- now check same queries using a bulk-loaded index drop index test_range_gist_idx; @@ -265,6 +283,15 @@ select count(*) from test_range_gist where ir >> int4range(100,500); select count(*) from test_range_gist where ir &< int4range(100,500); select count(*) from test_range_gist where ir &> int4range(100,500); select count(*) from test_range_gist where ir -|- int4range(100,500); +select count(*) from test_range_gist where ir @> '{}'::int4multirange; +select count(*) from test_range_gist where ir @> int4multirange(int4range(10,20), int4range(30,40)); +select count(*) from test_range_gist where ir && '{(10,20),(30,40),(50,60)}'::int4multirange; +select count(*) from test_range_gist where ir <@ '{(10,30),(40,60),(70,90)}'::int4multirange; +select count(*) from test_range_gist where ir << int4multirange(int4range(100,200), int4range(400,500)); +select count(*) from test_range_gist where ir >> int4multirange(int4range(100,200), int4range(400,500)); +select count(*) from test_range_gist where ir &< int4multirange(int4range(100,200), int4range(400,500)); +select count(*) from test_range_gist where ir &> int4multirange(int4range(100,200), int4range(400,500)); +select count(*) from test_range_gist where ir -|- int4multirange(int4range(100,200), int4range(400,500)); -- test SP-GiST index that's been built incrementally create table test_range_spgist(ir int4range); From 1f9158ba48122fa232db955a2ee324eec1848ba9 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 29 Dec 2020 18:02:38 -0500 Subject: [PATCH 005/240] Suppress log spam from multiple reports of SIGQUIT shutdown. When the postmaster sends SIGQUIT to its children, there's no real need for all the children to log that fact; the postmaster already made a log entry about it, so adding perhaps dozens or hundreds of child-process log entries adds nothing of value. So, let's introduce a new ereport level to specify "WARNING, but never send to log" and use that for these messages. Such a change wouldn't have been desirable before commit 7e784d1dc, because if someone manually SIGQUIT's a backend, we *do* want to log that. But now we can tell the difference between a signal that was issued by the postmaster and one that was not with reasonable certainty. While we're here, also clear error_context_stack before ereport'ing, to prevent error callbacks from being invoked in the signal-handler context. This should reduce the odds of getting hung up while trying to notify the client. Per a suggestion from Andres Freund. Discussion: https://postgr.es/m/20201225230331.hru3u6obyy6j53tk@alap3.anarazel.de --- src/backend/tcop/postgres.c | 16 ++++++++++++++-- src/backend/utils/error/elog.c | 10 +++++++++- src/include/utils/elog.h | 12 ++++++------ 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index d35c5020ea634..317d1aa57309f 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -2789,6 +2789,18 @@ quickdie(SIGNAL_ARGS) * wrong, so there's not much to lose. Assuming the postmaster is still * running, it will SIGKILL us soon if we get stuck for some reason. * + * One thing we can do to make this a tad safer is to clear the error + * context stack, so that context callbacks are not called. That's a lot + * less code that could be reached here, and the context info is unlikely + * to be very relevant to a SIGQUIT report anyway. + */ + error_context_stack = NULL; + + /* + * When responding to a postmaster-issued signal, we send the message only + * to the client; sending to the server log just creates log spam, plus + * it's more code that we need to hope will work in a signal handler. + * * Ideally these should be ereport(FATAL), but then we'd not get control * back to force the correct type of process exit. */ @@ -2802,7 +2814,7 @@ quickdie(SIGNAL_ARGS) break; case PMQUIT_FOR_CRASH: /* A crash-and-restart cycle is in progress */ - ereport(WARNING, + ereport(WARNING_CLIENT_ONLY, (errcode(ERRCODE_CRASH_SHUTDOWN), errmsg("terminating connection because of crash of another server process"), errdetail("The postmaster has commanded this server process to roll back" @@ -2814,7 +2826,7 @@ quickdie(SIGNAL_ARGS) break; case PMQUIT_FOR_STOP: /* Immediate-mode stop */ - ereport(WARNING, + ereport(WARNING_CLIENT_ONLY, (errcode(ERRCODE_ADMIN_SHUTDOWN), errmsg("terminating connection due to immediate shutdown command"))); break; diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index 3558e660c73b2..9a69038b80c7c 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -202,6 +202,11 @@ is_log_level_output(int elevel, int log_min_level) if (log_min_level == LOG || log_min_level <= ERROR) return true; } + else if (elevel == WARNING_CLIENT_ONLY) + { + /* never sent to log, regardless of log_min_level */ + return false; + } else if (log_min_level == LOG) { /* elevel != LOG */ @@ -453,7 +458,7 @@ errstart(int elevel, const char *domain) /* Select default errcode based on elevel */ if (elevel >= ERROR) edata->sqlerrcode = ERRCODE_INTERNAL_ERROR; - else if (elevel == WARNING) + else if (elevel >= WARNING) edata->sqlerrcode = ERRCODE_WARNING; else edata->sqlerrcode = ERRCODE_SUCCESSFUL_COMPLETION; @@ -2152,6 +2157,7 @@ write_eventlog(int level, const char *line, int len) eventlevel = EVENTLOG_INFORMATION_TYPE; break; case WARNING: + case WARNING_CLIENT_ONLY: eventlevel = EVENTLOG_WARNING_TYPE; break; case ERROR: @@ -3109,6 +3115,7 @@ send_message_to_server_log(ErrorData *edata) break; case NOTICE: case WARNING: + case WARNING_CLIENT_ONLY: syslog_level = LOG_NOTICE; break; case ERROR: @@ -3484,6 +3491,7 @@ error_severity(int elevel) prefix = gettext_noop("NOTICE"); break; case WARNING: + case WARNING_CLIENT_ONLY: prefix = gettext_noop("WARNING"); break; case ERROR: diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h index e8f04a1691649..d2bdfa0be3a97 100644 --- a/src/include/utils/elog.h +++ b/src/include/utils/elog.h @@ -40,19 +40,19 @@ #define WARNING 19 /* Warnings. NOTICE is for expected messages * like implicit sequence creation by SERIAL. * WARNING is for unexpected messages. */ -#define ERROR 20 /* user error - abort transaction; return to +#define WARNING_CLIENT_ONLY 20 /* Warnings to be sent to client as usual, but + * never to the server log. */ +#define ERROR 21 /* user error - abort transaction; return to * known state */ /* Save ERROR value in PGERROR so it can be restored when Win32 includes * modify it. We have to use a constant rather than ERROR because macros * are expanded only when referenced outside macros. */ #ifdef WIN32 -#define PGERROR 20 +#define PGERROR 21 #endif -#define FATAL 21 /* fatal error - abort process */ -#define PANIC 22 /* take down the other backends with me */ - - /* #define DEBUG DEBUG1 */ /* Backward compatibility with pre-7.3 */ +#define FATAL 22 /* fatal error - abort process */ +#define PANIC 23 /* take down the other backends with me */ /* macros for representing SQLSTATE strings compactly */ From f20dc2c8dd50a5c738d535205d5d44bff82d3f75 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 29 Dec 2020 20:44:03 -0500 Subject: [PATCH 006/240] Doc: fix up PDF build warnings from over-width table columns. Addition of multirange info to tables 8.27 and 65.1 made them start throwing "exceed the available area" warnings in PDF docs builds. For 8.27, twiddling the existing column width hints was enough to fix this. For 65.1, I twiddled the widths a little, but to really fix it I had to insert a space after each comma in the table, to allow a line break to occur there. (This seemed easier to read and maintain than the alternative of inserting &zwsp; entities.) Per buildfarm. --- doc/src/sgml/datatype.sgml | 4 +- doc/src/sgml/gist.sgml | 211 +++++++++++++++++++------------------ 2 files changed, 109 insertions(+), 106 deletions(-) diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml index 58d168c763e96..7c341c8e3fa6d 100644 --- a/doc/src/sgml/datatype.sgml +++ b/doc/src/sgml/datatype.sgml @@ -4995,8 +4995,8 @@ SELECT * FROM pg_attribute Pseudo-Types - - + + Name diff --git a/doc/src/sgml/gist.sgml b/doc/src/sgml/gist.sgml index dc1f192bddfdf..f22efd1f6e898 100644 --- a/doc/src/sgml/gist.sgml +++ b/doc/src/sgml/gist.sgml @@ -54,6 +54,9 @@
Built-in <acronym>GiST</acronym> Operator Classes + + + Name @@ -64,145 +67,145 @@ box_ops - << (box,box) - <-> (box,point) + << (box, box) + <-> (box, point) - &< (box,box) - && (box,box) - &> (box,box) - >> (box,box) - ~= (box,box) - @> (box,box) - <@ (box,box) - &<| (box,box) - <<| (box,box) - |>> (box,box) - |&> (box,box) - ~ (box,box) - @ (box,box) + &< (box, box) + && (box, box) + &> (box, box) + >> (box, box) + ~= (box, box) + @> (box, box) + <@ (box, box) + &<| (box, box) + <<| (box, box) + |>> (box, box) + |&> (box, box) + ~ (box, box) + @ (box, box) circle_ops - << (circle,circle) - <-> (circle,point) + << (circle, circle) + <-> (circle, point) - &< (circle,circle) - &> (circle,circle) - >> (circle,circle) - <@ (circle,circle) - @> (circle,circle) - ~= (circle,circle) - && (circle,circle) - |>> (circle,circle) - <<| (circle,circle) - &<| (circle,circle) - |&> (circle,circle) - @ (circle,circle) - ~ (circle,circle) + &< (circle, circle) + &> (circle, circle) + >> (circle, circle) + <@ (circle, circle) + @> (circle, circle) + ~= (circle, circle) + && (circle, circle) + |>> (circle, circle) + <<| (circle, circle) + &<| (circle, circle) + |&> (circle, circle) + @ (circle, circle) + ~ (circle, circle) inet_ops - << (inet,inet) + << (inet, inet) - <<= (inet,inet) - >> (inet,inet) - >>= (inet,inet) - = (inet,inet) - <> (inet,inet) - < (inet,inet) - <= (inet,inet) - > (inet,inet) - >= (inet,inet) - && (inet,inet) + <<= (inet, inet) + >> (inet, inet) + >>= (inet, inet) + = (inet, inet) + <> (inet, inet) + < (inet, inet) + <= (inet, inet) + > (inet, inet) + >= (inet, inet) + && (inet, inet) multirange_ops - = (anymultirange,anymultirange) + = (anymultirange, anymultirange) - && (anymultirange,anymultirange) - && (anymultirange,anyrange) - @> (anymultirange,anyelement) - @> (anymultirange,anymultirange) - @> (anymultirange,anyrange) - <@ (anymultirange,anymultirange) - <@ (anymultirange,anyrange) - << (anymultirange,anymultirange) - << (anymultirange,anyrange) - >> (anymultirange,anymultirange) - >> (anymultirange,anyrange) - &< (anymultirange,anymultirange) - &< (anymultirange,anyrange) - &> (anymultirange,anymultirange) - &> (anymultirange,anyrange) - -|- (anymultirange,anymultirange) - -|- (anymultirange,anyrange) + && (anymultirange, anymultirange) + && (anymultirange, anyrange) + @> (anymultirange, anyelement) + @> (anymultirange, anymultirange) + @> (anymultirange, anyrange) + <@ (anymultirange, anymultirange) + <@ (anymultirange, anyrange) + << (anymultirange, anymultirange) + << (anymultirange, anyrange) + >> (anymultirange, anymultirange) + >> (anymultirange, anyrange) + &< (anymultirange, anymultirange) + &< (anymultirange, anyrange) + &> (anymultirange, anymultirange) + &> (anymultirange, anyrange) + -|- (anymultirange, anymultirange) + -|- (anymultirange, anyrange) point_ops - |>> (point,point) - <-> (point,point) + |>> (point, point) + <-> (point, point) - << (point,point) - >> (point,point) - <<| (point,point) - ~= (point,point) - <@ (point,box) - <@ (point,polygon) - <@ (point,circle) + << (point, point) + >> (point, point) + <<| (point, point) + ~= (point, point) + <@ (point, box) + <@ (point, polygon) + <@ (point, circle) poly_ops - << (polygon,polygon) - <-> (polygon,point) + << (polygon, polygon) + <-> (polygon, point) - &< (polygon,polygon) - &> (polygon,polygon) - >> (polygon,polygon) - <@ (polygon,polygon) - @> (polygon,polygon) - ~= (polygon,polygon) - && (polygon,polygon) - <<| (polygon,polygon) - &<| (polygon,polygon) - |&> (polygon,polygon) - |>> (polygon,polygon) - @ (polygon,polygon) - ~ (polygon,polygon) + &< (polygon, polygon) + &> (polygon, polygon) + >> (polygon, polygon) + <@ (polygon, polygon) + @> (polygon, polygon) + ~= (polygon, polygon) + && (polygon, polygon) + <<| (polygon, polygon) + &<| (polygon, polygon) + |&> (polygon, polygon) + |>> (polygon, polygon) + @ (polygon, polygon) + ~ (polygon, polygon) range_ops - = (anyrange,anyrange) + = (anyrange, anyrange) - && (anyrange,anyrange) - && (anyrange,anymultirange) - @> (anyrange,anyelement) - @> (anyrange,anyrange) - @> (anyrange,anymultirange) - <@ (anyrange,anyrange) - <@ (anyrange,anymultirange) - << (anyrange,anyrange) - << (anyrange,anymultirange) - >> (anyrange,anyrange) - >> (anyrange,anymultirange) - &< (anyrange,anyrange) - &< (anyrange,anymultirange) - &> (anyrange,anyrange) - &> (anyrange,anymultirange) - -|- (anyrange,anyrange) - -|- (anyrange,anymultirange) + && (anyrange, anyrange) + && (anyrange, anymultirange) + @> (anyrange, anyelement) + @> (anyrange, anyrange) + @> (anyrange, anymultirange) + <@ (anyrange, anyrange) + <@ (anyrange, anymultirange) + << (anyrange, anyrange) + << (anyrange, anymultirange) + >> (anyrange, anyrange) + >> (anyrange, anymultirange) + &< (anyrange, anyrange) + &< (anyrange, anymultirange) + &> (anyrange, anyrange) + &> (anyrange, anymultirange) + -|- (anyrange, anyrange) + -|- (anyrange, anymultirange) tsquery_ops - <@ (tsquery,tsquery) + <@ (tsquery, tsquery) - @> (tsquery,tsquery) + @> (tsquery, tsquery) tsvector_ops - @@ (tsvector,tsquery) + @@ (tsvector, tsquery) From 107a2d4204ff4bf4ce05e3525f0d94fc0bd497ff Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Wed, 30 Dec 2020 12:38:16 +0900 Subject: [PATCH 007/240] Remove references to libpq_srcdir in adminpack and old_snapshot Those two modules included references to libpq's source path, without using anything from libpq. Some copy-pastos done when each module was created are likely at the origin of those useless references (aecf5ee for old_snapshot, fe59e56 for adminpack). Reviewed-by: Tom Lane, David Rowley Discussion: https://postgr.es/m/X+LQpfLyk7jgzUki@paquier.xyz --- contrib/adminpack/Makefile | 1 - contrib/old_snapshot/Makefile | 1 - 2 files changed, 2 deletions(-) diff --git a/contrib/adminpack/Makefile b/contrib/adminpack/Makefile index 630fea7726c7b..851504f4aefba 100644 --- a/contrib/adminpack/Makefile +++ b/contrib/adminpack/Makefile @@ -4,7 +4,6 @@ MODULE_big = adminpack OBJS = \ $(WIN32RES) \ adminpack.o -PG_CPPFLAGS = -I$(libpq_srcdir) EXTENSION = adminpack DATA = adminpack--1.0.sql adminpack--1.0--1.1.sql adminpack--1.1--2.0.sql\ diff --git a/contrib/old_snapshot/Makefile b/contrib/old_snapshot/Makefile index 77c85df3225d6..adb557532fc1c 100644 --- a/contrib/old_snapshot/Makefile +++ b/contrib/old_snapshot/Makefile @@ -4,7 +4,6 @@ MODULE_big = old_snapshot OBJS = \ $(WIN32RES) \ time_mapping.o -PG_CPPFLAGS = -I$(libpq_srcdir) EXTENSION = old_snapshot DATA = old_snapshot--1.0.sql From 52202bb396b1e96c43bfd767d6e434b1c6fd2ae1 Mon Sep 17 00:00:00 2001 From: Noah Misch Date: Wed, 30 Dec 2020 01:43:43 -0800 Subject: [PATCH 008/240] In pg_upgrade cross-version test, handle lack of oldstyle_length(). This suffices for testing v12 -> v13; some other version pairs need more changes. Back-patch to v10, which removed the function. --- src/bin/pg_upgrade/test.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bin/pg_upgrade/test.sh b/src/bin/pg_upgrade/test.sh index 04aa7fd9f513c..a2da1abe3f167 100644 --- a/src/bin/pg_upgrade/test.sh +++ b/src/bin/pg_upgrade/test.sh @@ -167,17 +167,17 @@ createdb "regression$dbname3" || createdb_status=$? if "$MAKE" -C "$oldsrc" installcheck-parallel; then oldpgversion=`psql -X -A -t -d regression -c "SHOW server_version_num"` - # before dumping, get rid of objects not existing in later versions + # before dumping, get rid of objects not feasible in later versions if [ "$newsrc" != "$oldsrc" ]; then fix_sql="" case $oldpgversion in 804??) - fix_sql="DROP FUNCTION public.myfunc(integer); DROP FUNCTION public.oldstyle_length(integer, text);" - ;; - *) - fix_sql="DROP FUNCTION public.oldstyle_length(integer, text);" + fix_sql="DROP FUNCTION public.myfunc(integer);" ;; esac + fix_sql="$fix_sql + DROP FUNCTION IF EXISTS + public.oldstyle_length(integer, text); -- last in 9.6"; psql -X -d regression -c "$fix_sql;" || psql_fix_sql_status=$? fi From fa744697c79189a661f802d9a979d959b4454df0 Mon Sep 17 00:00:00 2001 From: Noah Misch Date: Wed, 30 Dec 2020 01:43:43 -0800 Subject: [PATCH 009/240] In pg_upgrade cross-version test, handle postfix operators. Commit 1ed6b895634ce0dc5fd4bd040e87252b32182cba eliminated support for them, so drop them from regression databases before upgrading. This is necessary but not sufficient for testing v13 -> v14 upgrades. Discussion: https://postgr.es/m/449144.1600439950@sss.pgh.pa.us --- src/bin/pg_upgrade/test.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/bin/pg_upgrade/test.sh b/src/bin/pg_upgrade/test.sh index a2da1abe3f167..8b13ec8692d04 100644 --- a/src/bin/pg_upgrade/test.sh +++ b/src/bin/pg_upgrade/test.sh @@ -177,7 +177,12 @@ if "$MAKE" -C "$oldsrc" installcheck-parallel; then esac fix_sql="$fix_sql DROP FUNCTION IF EXISTS - public.oldstyle_length(integer, text); -- last in 9.6"; + public.oldstyle_length(integer, text); -- last in 9.6 + DROP OPERATOR IF EXISTS -- last in v13 + public.#@# (pg_catalog.int8, NONE), + public.#%# (pg_catalog.int8, NONE), + public.!=- (pg_catalog.int8, NONE), + public.#@%# (pg_catalog.int8, NONE);" psql -X -d regression -c "$fix_sql;" || psql_fix_sql_status=$? fi From 0aa8a01d04c8fe200b7a106878eebc3d0af9105c Mon Sep 17 00:00:00 2001 From: Amit Kapila Date: Wed, 30 Dec 2020 16:17:26 +0530 Subject: [PATCH 010/240] Extend the output plugin API to allow decoding of prepared xacts. This adds six methods to the output plugin API, adding support for streaming changes of two-phase transactions at prepare time. * begin_prepare * filter_prepare * prepare * commit_prepared * rollback_prepared * stream_prepare Most of this is a simple extension of the existing methods, with the semantic difference that the transaction is not yet committed and maybe aborted later. Until now two-phase transactions were translated into regular transactions on the subscriber, and the GID was not forwarded to it. None of the two-phase commands were communicated to the subscriber. This patch provides the infrastructure for logical decoding plugins to be informed of two-phase commands Like PREPARE TRANSACTION, COMMIT PREPARED and ROLLBACK PREPARED commands with the corresponding GID. This also extends the 'test_decoding' plugin, implementing these new methods. This commit simply adds these new APIs and the upcoming patch to "allow the decoding at prepare time in ReorderBuffer" will use these APIs. Author: Ajin Cherian and Amit Kapila based on previous work by Nikhil Sontakke and Stas Kelvich Reviewed-by: Amit Kapila, Peter Smith, Sawada Masahiko, and Dilip Kumar Discussion: https://postgr.es/m/02DA5F5E-CECE-4D9C-8B4B-418077E2C010@postgrespro.ru https://postgr.es/m/CAMGcDxeqEpWj3fTXwqhSwBdXd2RS9jzwWscO-XbeCfso6ts3+Q@mail.gmail.com --- contrib/test_decoding/test_decoding.c | 167 ++++++++++++ doc/src/sgml/logicaldecoding.sgml | 172 ++++++++++++- src/backend/replication/logical/logical.c | 297 ++++++++++++++++++++++ src/include/replication/logical.h | 6 + src/include/replication/output_plugin.h | 56 ++++ src/include/replication/reorderbuffer.h | 41 +++ src/tools/pgindent/typedefs.list | 12 + 7 files changed, 744 insertions(+), 7 deletions(-) diff --git a/contrib/test_decoding/test_decoding.c b/contrib/test_decoding/test_decoding.c index e12278beb5817..05763553a40ee 100644 --- a/contrib/test_decoding/test_decoding.c +++ b/contrib/test_decoding/test_decoding.c @@ -76,6 +76,20 @@ static void pg_decode_message(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, XLogRecPtr message_lsn, bool transactional, const char *prefix, Size sz, const char *message); +static bool pg_decode_filter_prepare(LogicalDecodingContext *ctx, + const char *gid); +static void pg_decode_begin_prepare_txn(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn); +static void pg_decode_prepare_txn(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr prepare_lsn); +static void pg_decode_commit_prepared_txn(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr commit_lsn); +static void pg_decode_rollback_prepared_txn(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr prepare_end_lsn, + TimestampTz prepare_time); static void pg_decode_stream_start(LogicalDecodingContext *ctx, ReorderBufferTXN *txn); static void pg_output_stream_start(LogicalDecodingContext *ctx, @@ -87,6 +101,9 @@ static void pg_decode_stream_stop(LogicalDecodingContext *ctx, static void pg_decode_stream_abort(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, XLogRecPtr abort_lsn); +static void pg_decode_stream_prepare(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr prepare_lsn); static void pg_decode_stream_commit(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, XLogRecPtr commit_lsn); @@ -123,9 +140,15 @@ _PG_output_plugin_init(OutputPluginCallbacks *cb) cb->filter_by_origin_cb = pg_decode_filter; cb->shutdown_cb = pg_decode_shutdown; cb->message_cb = pg_decode_message; + cb->filter_prepare_cb = pg_decode_filter_prepare; + cb->begin_prepare_cb = pg_decode_begin_prepare_txn; + cb->prepare_cb = pg_decode_prepare_txn; + cb->commit_prepared_cb = pg_decode_commit_prepared_txn; + cb->rollback_prepared_cb = pg_decode_rollback_prepared_txn; cb->stream_start_cb = pg_decode_stream_start; cb->stream_stop_cb = pg_decode_stream_stop; cb->stream_abort_cb = pg_decode_stream_abort; + cb->stream_prepare_cb = pg_decode_stream_prepare; cb->stream_commit_cb = pg_decode_stream_commit; cb->stream_change_cb = pg_decode_stream_change; cb->stream_message_cb = pg_decode_stream_message; @@ -141,6 +164,7 @@ pg_decode_startup(LogicalDecodingContext *ctx, OutputPluginOptions *opt, ListCell *option; TestDecodingData *data; bool enable_streaming = false; + bool enable_twophase = false; data = palloc0(sizeof(TestDecodingData)); data->context = AllocSetContextCreate(ctx->context, @@ -241,6 +265,16 @@ pg_decode_startup(LogicalDecodingContext *ctx, OutputPluginOptions *opt, errmsg("could not parse value \"%s\" for parameter \"%s\"", strVal(elem->arg), elem->defname))); } + else if (strcmp(elem->defname, "two-phase-commit") == 0) + { + if (elem->arg == NULL) + continue; + else if (!parse_bool(strVal(elem->arg), &enable_twophase)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("could not parse value \"%s\" for parameter \"%s\"", + strVal(elem->arg), elem->defname))); + } else { ereport(ERROR, @@ -252,6 +286,7 @@ pg_decode_startup(LogicalDecodingContext *ctx, OutputPluginOptions *opt, } ctx->streaming &= enable_streaming; + ctx->twophase &= enable_twophase; } /* cleanup this plugin's resources */ @@ -320,6 +355,111 @@ pg_decode_commit_txn(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, OutputPluginWrite(ctx, true); } +/* BEGIN PREPARE callback */ +static void +pg_decode_begin_prepare_txn(LogicalDecodingContext *ctx, ReorderBufferTXN *txn) +{ + TestDecodingData *data = ctx->output_plugin_private; + TestDecodingTxnData *txndata = + MemoryContextAllocZero(ctx->context, sizeof(TestDecodingTxnData)); + + txndata->xact_wrote_changes = false; + txn->output_plugin_private = txndata; + + if (data->skip_empty_xacts) + return; + + pg_output_begin(ctx, data, txn, true); +} + +/* PREPARE callback */ +static void +pg_decode_prepare_txn(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, + XLogRecPtr prepare_lsn) +{ + TestDecodingData *data = ctx->output_plugin_private; + TestDecodingTxnData *txndata = txn->output_plugin_private; + + if (data->skip_empty_xacts && !txndata->xact_wrote_changes) + return; + + OutputPluginPrepareWrite(ctx, true); + + appendStringInfo(ctx->out, "PREPARE TRANSACTION %s", + quote_literal_cstr(txn->gid)); + + if (data->include_xids) + appendStringInfo(ctx->out, ", txid %u", txn->xid); + + if (data->include_timestamp) + appendStringInfo(ctx->out, " (at %s)", + timestamptz_to_str(txn->commit_time)); + + OutputPluginWrite(ctx, true); +} + +/* COMMIT PREPARED callback */ +static void +pg_decode_commit_prepared_txn(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, + XLogRecPtr commit_lsn) +{ + TestDecodingData *data = ctx->output_plugin_private; + + OutputPluginPrepareWrite(ctx, true); + + appendStringInfo(ctx->out, "COMMIT PREPARED %s", + quote_literal_cstr(txn->gid)); + + if (data->include_xids) + appendStringInfo(ctx->out, ", txid %u", txn->xid); + + if (data->include_timestamp) + appendStringInfo(ctx->out, " (at %s)", + timestamptz_to_str(txn->commit_time)); + + OutputPluginWrite(ctx, true); +} + +/* ROLLBACK PREPARED callback */ +static void +pg_decode_rollback_prepared_txn(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr prepare_end_lsn, + TimestampTz prepare_time) +{ + TestDecodingData *data = ctx->output_plugin_private; + + OutputPluginPrepareWrite(ctx, true); + + appendStringInfo(ctx->out, "ROLLBACK PREPARED %s", + quote_literal_cstr(txn->gid)); + + if (data->include_xids) + appendStringInfo(ctx->out, ", txid %u", txn->xid); + + if (data->include_timestamp) + appendStringInfo(ctx->out, " (at %s)", + timestamptz_to_str(txn->commit_time)); + + OutputPluginWrite(ctx, true); +} + +/* + * Filter out two-phase transactions. + * + * Each plugin can implement its own filtering logic. Here we demonstrate a + * simple logic by checking the GID. If the GID contains the "_nodecode" + * substring, then we filter it out. + */ +static bool +pg_decode_filter_prepare(LogicalDecodingContext *ctx, const char *gid) +{ + if (strstr(gid, "_nodecode") != NULL) + return true; + + return false; +} + static bool pg_decode_filter(LogicalDecodingContext *ctx, RepOriginId origin_id) @@ -701,6 +841,33 @@ pg_decode_stream_abort(LogicalDecodingContext *ctx, OutputPluginWrite(ctx, true); } +static void +pg_decode_stream_prepare(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr prepare_lsn) +{ + TestDecodingData *data = ctx->output_plugin_private; + TestDecodingTxnData *txndata = txn->output_plugin_private; + + if (data->skip_empty_xacts && !txndata->xact_wrote_changes) + return; + + OutputPluginPrepareWrite(ctx, true); + + if (data->include_xids) + appendStringInfo(ctx->out, "preparing streamed transaction TXN %s, txid %u", + quote_literal_cstr(txn->gid), txn->xid); + else + appendStringInfo(ctx->out, "preparing streamed transaction %s", + quote_literal_cstr(txn->gid)); + + if (data->include_timestamp) + appendStringInfo(ctx->out, " (at %s)", + timestamptz_to_str(txn->commit_time)); + + OutputPluginWrite(ctx, true); +} + static void pg_decode_stream_commit(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, diff --git a/doc/src/sgml/logicaldecoding.sgml b/doc/src/sgml/logicaldecoding.sgml index ca78a81e9c545..d63f90ff282b8 100644 --- a/doc/src/sgml/logicaldecoding.sgml +++ b/doc/src/sgml/logicaldecoding.sgml @@ -389,9 +389,15 @@ typedef struct OutputPluginCallbacks LogicalDecodeMessageCB message_cb; LogicalDecodeFilterByOriginCB filter_by_origin_cb; LogicalDecodeShutdownCB shutdown_cb; + LogicalDecodeFilterPrepareCB filter_prepare_cb; + LogicalDecodeBeginPrepareCB begin_prepare_cb; + LogicalDecodePrepareCB prepare_cb; + LogicalDecodeCommitPreparedCB commit_prepared_cb; + LogicalDecodeRollbackPreparedCB rollback_prepared_cb; LogicalDecodeStreamStartCB stream_start_cb; LogicalDecodeStreamStopCB stream_stop_cb; LogicalDecodeStreamAbortCB stream_abort_cb; + LogicalDecodeStreamPrepareCB stream_prepare_cb; LogicalDecodeStreamCommitCB stream_commit_cb; LogicalDecodeStreamChangeCB stream_change_cb; LogicalDecodeStreamMessageCB stream_message_cb; @@ -413,10 +419,20 @@ typedef void (*LogicalOutputPluginInit) (struct OutputPluginCallbacks *cb); An output plugin may also define functions to support streaming of large, in-progress transactions. The stream_start_cb, stream_stop_cb, stream_abort_cb, - stream_commit_cb and stream_change_cb + stream_commit_cb, stream_change_cb, + and stream_prepare_cb are required, while stream_message_cb and stream_truncate_cb are optional. + + + An output plugin may also define functions to support two-phase commits, + which allows actions to be decoded on the PREPARE TRANSACTION. + The begin_prepare_cb, prepare_cb, + stream_prepare_cb, + commit_prepared_cb and rollback_prepared_cb + callbacks are required, while filter_prepare_cb is optional. + @@ -477,7 +493,15 @@ CREATE TABLE another_catalog_table(data text) WITH (user_catalog_table = true); never get decoded. Successful savepoints are folded into the transaction containing them in the order they were - executed within that transaction. + executed within that transaction. A transaction that is prepared for + a two-phase commit using PREPARE TRANSACTION will + also be decoded if the output plugin callbacks needed for decoding + them are provided. It is possible that the current transaction which + is being decoded is aborted concurrently via a ROLLBACK PREPARED + command. In that case, the logical decoding of this transaction will + be aborted too. We will skip all the changes of such a transaction once + the abort is detected and abort the transaction when we read WAL for + ROLLBACK PREPARED. @@ -587,7 +611,13 @@ typedef void (*LogicalDecodeCommitCB) (struct LogicalDecodingContext *ctx, an INSERT, UPDATE, or DELETE. Even if the original command modified several rows at once the callback will be called individually for each - row. + row. The change_cb callback may access system or + user catalog tables to aid in the process of outputting the row + modification details. In case of decoding a prepared (but yet + uncommitted) transaction or decoding of an uncommitted transaction, this + change callback might also error out due to simultaneous rollback of + this very same transaction. In that case, the logical decoding of this + aborted transaction is stopped gracefully. typedef void (*LogicalDecodeChangeCB) (struct LogicalDecodingContext *ctx, ReorderBufferTXN *txn, @@ -685,7 +715,13 @@ typedef void (*LogicalDecodeMessageCB) (struct LogicalDecodingContext *ctx, non-transactional and the XID was not assigned yet in the transaction which logged the message. The lsn has WAL location of the message. The transactional says - if the message was sent as transactional or not. + if the message was sent as transactional or not. Similar to the change + callback, in case of decoding a prepared (but yet uncommitted) + transaction or decoding of an uncommitted transaction, this message + callback might also error out due to simultaneous rollback of + this very same transaction. In that case, the logical decoding of this + aborted transaction is stopped gracefully. + The prefix is arbitrary null-terminated prefix which can be used for identifying interesting messages for the current plugin. And finally the message parameter holds @@ -698,6 +734,111 @@ typedef void (*LogicalDecodeMessageCB) (struct LogicalDecodingContext *ctx, + + Prepare Filter Callback + + + The optional filter_prepare_cb callback + is called to determine whether data that is part of the current + two-phase commit transaction should be considered for decode + at this prepare stage or as a regular one-phase transaction at + COMMIT PREPARED time later. To signal that + decoding should be skipped, return true; + false otherwise. When the callback is not + defined, false is assumed (i.e. nothing is + filtered). + +typedef bool (*LogicalDecodeFilterPrepareCB) (struct LogicalDecodingContext *ctx, + const char *gid); + + The ctx parameter has the same contents as for the + other callbacks. The gid is the identifier that later + identifies this transaction for COMMIT PREPARED or + ROLLBACK PREPARED. + + + The callback has to provide the same static answer for a given + gid every time it is called. + + + + + Transaction Begin Prepare Callback + + + The required begin_prepare_cb callback is called + whenever the start of a prepared transaction has been decoded. The + gid field, which is part of the + txn parameter can be used in this callback to + check if the plugin has already received this prepare in which case it + can skip the remaining changes of the transaction. This can only happen + if the user restarts the decoding after receiving the prepare for a + transaction but before receiving the commit prepared say because of some + error. + + typedef void (*LogicalDecodeBeginPrepareCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn); + + + + + + Transaction Prepare Callback + + + The required prepare_cb callback is called whenever + a transaction which is prepared for two-phase commit has been + decoded. The change_cb callback for all modified + rows will have been called before this, if there have been any modified + rows. The gid field, which is part of the + txn parameter can be used in this callback. + + typedef void (*LogicalDecodePrepareCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr prepare_lsn); + + + + + + Transaction Commit Prepared Callback + + + The required commit_prepared_cb callback is called + whenever a transaction commit prepared has been decoded. The + gid field, which is part of the + txn parameter can be used in this callback. + + typedef void (*LogicalDecodeCommitPreparedCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr commit_lsn); + + + + + + Transaction Rollback Prepared Callback + + + The required rollback_prepared_cb callback is called + whenever a transaction rollback prepared has been decoded. The + gid field, which is part of the + txn parameter can be used in this callback. The + parameters prepare_end_lsn and + prepare_time can be used to check if the plugin + has received this prepare transaction in which case it can apply the + rollback, otherwise, it can skip the rollback operation. The + gid alone is not sufficient because the downstream + node can have prepared transaction with same identifier. + + typedef void (*LogicalDecodeRollbackPreparedCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr preapre_end_lsn, + TimestampTz prepare_time); + + + + Stream Start Callback @@ -735,6 +876,19 @@ typedef void (*LogicalDecodeStreamAbortCB) (struct LogicalDecodingContext *ctx, + + Stream Prepare Callback + + The stream_prepare_cb callback is called to prepare + a previously streamed transaction as part of a two-phase commit. + +typedef void (*LogicalDecodeStreamPrepareCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr prepare_lsn); + + + + Stream Commit Callback @@ -913,9 +1067,13 @@ OutputPluginWrite(ctx, true); When streaming an in-progress transaction, the changes (and messages) are streamed in blocks demarcated by stream_start_cb and stream_stop_cb callbacks. Once all the decoded - changes are transmitted, the transaction is committed using the - stream_commit_cb callback (or possibly aborted using - the stream_abort_cb callback). + changes are transmitted, the transaction can be committed using the + the stream_commit_cb callback + (or possibly aborted using the stream_abort_cb callback). + If two-phase commits are supported, the transaction can be prepared using the + stream_prepare_cb callback, commit prepared using the + commit_prepared_cb callback or aborted using the + rollback_prepared_cb. diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c index f1f4df7d70f28..6e3de92a67c54 100644 --- a/src/backend/replication/logical/logical.c +++ b/src/backend/replication/logical/logical.c @@ -59,6 +59,13 @@ static void shutdown_cb_wrapper(LogicalDecodingContext *ctx); static void begin_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn); static void commit_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, XLogRecPtr commit_lsn); +static void begin_prepare_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn); +static void prepare_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, + XLogRecPtr prepare_lsn); +static void commit_prepared_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, + XLogRecPtr commit_lsn); +static void rollback_prepared_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, + XLogRecPtr prepare_end_lsn, TimestampTz prepare_time); static void change_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, Relation relation, ReorderBufferChange *change); static void truncate_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, @@ -74,6 +81,8 @@ static void stream_stop_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, XLogRecPtr last_lsn); static void stream_abort_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, XLogRecPtr abort_lsn); +static void stream_prepare_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, + XLogRecPtr prepare_lsn); static void stream_commit_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, XLogRecPtr commit_lsn); static void stream_change_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, @@ -237,11 +246,37 @@ StartupDecodingContext(List *output_plugin_options, ctx->reorder->stream_start = stream_start_cb_wrapper; ctx->reorder->stream_stop = stream_stop_cb_wrapper; ctx->reorder->stream_abort = stream_abort_cb_wrapper; + ctx->reorder->stream_prepare = stream_prepare_cb_wrapper; ctx->reorder->stream_commit = stream_commit_cb_wrapper; ctx->reorder->stream_change = stream_change_cb_wrapper; ctx->reorder->stream_message = stream_message_cb_wrapper; ctx->reorder->stream_truncate = stream_truncate_cb_wrapper; + + /* + * To support two-phase logical decoding, we require + * begin_prepare/prepare/commit-prepare/abort-prepare callbacks. The + * filter_prepare callback is optional. We however enable two-phase + * logical decoding when at least one of the methods is enabled so that we + * can easily identify missing methods. + * + * We decide it here, but only check it later in the wrappers. + */ + ctx->twophase = (ctx->callbacks.begin_prepare_cb != NULL) || + (ctx->callbacks.prepare_cb != NULL) || + (ctx->callbacks.commit_prepared_cb != NULL) || + (ctx->callbacks.rollback_prepared_cb != NULL) || + (ctx->callbacks.stream_prepare_cb != NULL) || + (ctx->callbacks.filter_prepare_cb != NULL); + + /* + * Callback to support decoding at prepare time. + */ + ctx->reorder->begin_prepare = begin_prepare_cb_wrapper; + ctx->reorder->prepare = prepare_cb_wrapper; + ctx->reorder->commit_prepared = commit_prepared_cb_wrapper; + ctx->reorder->rollback_prepared = rollback_prepared_cb_wrapper; + ctx->out = makeStringInfo(); ctx->prepare_write = prepare_write; ctx->write = do_write; @@ -782,6 +817,186 @@ commit_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, error_context_stack = errcallback.previous; } +/* + * The functionality of begin_prepare is quite similar to begin with the + * exception that this will have gid (global transaction id) information which + * can be used by plugin. Now, we thought about extending the existing begin + * but that would break the replication protocol and additionally this looks + * cleaner. + */ +static void +begin_prepare_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn) +{ + LogicalDecodingContext *ctx = cache->private_data; + LogicalErrorCallbackState state; + ErrorContextCallback errcallback; + + Assert(!ctx->fast_forward); + + /* We're only supposed to call this when two-phase commits are supported */ + Assert(ctx->twophase); + + /* Push callback + info on the error context stack */ + state.ctx = ctx; + state.callback_name = "begin_prepare"; + state.report_location = txn->first_lsn; + errcallback.callback = output_plugin_error_callback; + errcallback.arg = (void *) &state; + errcallback.previous = error_context_stack; + error_context_stack = &errcallback; + + /* set output state */ + ctx->accept_writes = true; + ctx->write_xid = txn->xid; + ctx->write_location = txn->first_lsn; + + /* + * If the plugin supports two-phase commits then begin prepare callback is + * mandatory + */ + if (ctx->callbacks.begin_prepare_cb == NULL) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("logical replication at prepare time requires begin_prepare_cb callback"))); + + /* do the actual work: call callback */ + ctx->callbacks.begin_prepare_cb(ctx, txn); + + /* Pop the error context stack */ + error_context_stack = errcallback.previous; +} + +static void +prepare_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, + XLogRecPtr prepare_lsn) +{ + LogicalDecodingContext *ctx = cache->private_data; + LogicalErrorCallbackState state; + ErrorContextCallback errcallback; + + Assert(!ctx->fast_forward); + + /* We're only supposed to call this when two-phase commits are supported */ + Assert(ctx->twophase); + + /* Push callback + info on the error context stack */ + state.ctx = ctx; + state.callback_name = "prepare"; + state.report_location = txn->final_lsn; /* beginning of prepare record */ + errcallback.callback = output_plugin_error_callback; + errcallback.arg = (void *) &state; + errcallback.previous = error_context_stack; + error_context_stack = &errcallback; + + /* set output state */ + ctx->accept_writes = true; + ctx->write_xid = txn->xid; + ctx->write_location = txn->end_lsn; /* points to the end of the record */ + + /* + * If the plugin supports two-phase commits then prepare callback is + * mandatory + */ + if (ctx->callbacks.prepare_cb == NULL) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("logical replication at prepare time requires prepare_cb callback"))); + + /* do the actual work: call callback */ + ctx->callbacks.prepare_cb(ctx, txn, prepare_lsn); + + /* Pop the error context stack */ + error_context_stack = errcallback.previous; +} + +static void +commit_prepared_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, + XLogRecPtr commit_lsn) +{ + LogicalDecodingContext *ctx = cache->private_data; + LogicalErrorCallbackState state; + ErrorContextCallback errcallback; + + Assert(!ctx->fast_forward); + + /* We're only supposed to call this when two-phase commits are supported */ + Assert(ctx->twophase); + + /* Push callback + info on the error context stack */ + state.ctx = ctx; + state.callback_name = "commit_prepared"; + state.report_location = txn->final_lsn; /* beginning of commit record */ + errcallback.callback = output_plugin_error_callback; + errcallback.arg = (void *) &state; + errcallback.previous = error_context_stack; + error_context_stack = &errcallback; + + /* set output state */ + ctx->accept_writes = true; + ctx->write_xid = txn->xid; + ctx->write_location = txn->end_lsn; /* points to the end of the record */ + + /* + * If the plugin support two-phase commits then commit prepared callback + * is mandatory + */ + if (ctx->callbacks.commit_prepared_cb == NULL) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("logical replication at prepare time requires commit_prepared_cb callback"))); + + /* do the actual work: call callback */ + ctx->callbacks.commit_prepared_cb(ctx, txn, commit_lsn); + + /* Pop the error context stack */ + error_context_stack = errcallback.previous; +} + +static void +rollback_prepared_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, + XLogRecPtr prepare_end_lsn, + TimestampTz prepare_time) +{ + LogicalDecodingContext *ctx = cache->private_data; + LogicalErrorCallbackState state; + ErrorContextCallback errcallback; + + Assert(!ctx->fast_forward); + + /* We're only supposed to call this when two-phase commits are supported */ + Assert(ctx->twophase); + + /* Push callback + info on the error context stack */ + state.ctx = ctx; + state.callback_name = "rollback_prepared"; + state.report_location = txn->final_lsn; /* beginning of commit record */ + errcallback.callback = output_plugin_error_callback; + errcallback.arg = (void *) &state; + errcallback.previous = error_context_stack; + error_context_stack = &errcallback; + + /* set output state */ + ctx->accept_writes = true; + ctx->write_xid = txn->xid; + ctx->write_location = txn->end_lsn; /* points to the end of the record */ + + /* + * If the plugin support two-phase commits then rollback prepared callback + * is mandatory + */ + if (ctx->callbacks.rollback_prepared_cb == NULL) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("logical replication at prepare time requires rollback_prepared_cb callback"))); + + /* do the actual work: call callback */ + ctx->callbacks.rollback_prepared_cb(ctx, txn, prepare_end_lsn, + prepare_time); + + /* Pop the error context stack */ + error_context_stack = errcallback.previous; +} + static void change_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, Relation relation, ReorderBufferChange *change) @@ -859,6 +1074,45 @@ truncate_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, error_context_stack = errcallback.previous; } +bool +filter_prepare_cb_wrapper(LogicalDecodingContext *ctx, const char *gid) +{ + LogicalErrorCallbackState state; + ErrorContextCallback errcallback; + bool ret; + + Assert(!ctx->fast_forward); + + /* + * Skip if decoding of two-phase transactions at PREPARE time is not + * enabled. In that case, all two-phase transactions are considered + * filtered out and will be applied as regular transactions at COMMIT + * PREPARED. + */ + if (!ctx->twophase) + return true; + + /* Push callback + info on the error context stack */ + state.ctx = ctx; + state.callback_name = "filter_prepare"; + state.report_location = InvalidXLogRecPtr; + errcallback.callback = output_plugin_error_callback; + errcallback.arg = (void *) &state; + errcallback.previous = error_context_stack; + error_context_stack = &errcallback; + + /* set output state */ + ctx->accept_writes = false; + + /* do the actual work: call callback */ + ret = ctx->callbacks.filter_prepare_cb(ctx, gid); + + /* Pop the error context stack */ + error_context_stack = errcallback.previous; + + return ret; +} + bool filter_by_origin_cb_wrapper(LogicalDecodingContext *ctx, RepOriginId origin_id) { @@ -1056,6 +1310,49 @@ stream_abort_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, error_context_stack = errcallback.previous; } +static void +stream_prepare_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, + XLogRecPtr prepare_lsn) +{ + LogicalDecodingContext *ctx = cache->private_data; + LogicalErrorCallbackState state; + ErrorContextCallback errcallback; + + Assert(!ctx->fast_forward); + + /* + * We're only supposed to call this when streaming and two-phase commits + * are supported. + */ + Assert(ctx->streaming); + Assert(ctx->twophase); + + /* Push callback + info on the error context stack */ + state.ctx = ctx; + state.callback_name = "stream_prepare"; + state.report_location = txn->final_lsn; + errcallback.callback = output_plugin_error_callback; + errcallback.arg = (void *) &state; + errcallback.previous = error_context_stack; + error_context_stack = &errcallback; + + /* set output state */ + ctx->accept_writes = true; + ctx->write_xid = txn->xid; + ctx->write_location = txn->end_lsn; + + /* in streaming mode with two-phase commits, stream_prepare_cb is required */ + if (ctx->callbacks.stream_prepare_cb == NULL) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("logical streaming at prepare time requires a stream_prepare_cb callback"))); + + ctx->callbacks.stream_prepare_cb(ctx, txn, prepare_lsn); + + /* Pop the error context stack */ + error_context_stack = errcallback.previous; +} + static void stream_commit_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, XLogRecPtr commit_lsn) diff --git a/src/include/replication/logical.h b/src/include/replication/logical.h index 40bab7ee02df4..28c9c1f474eb3 100644 --- a/src/include/replication/logical.h +++ b/src/include/replication/logical.h @@ -84,6 +84,11 @@ typedef struct LogicalDecodingContext */ bool streaming; + /* + * Does the output plugin support two-phase decoding, and is it enabled? + */ + bool twophase; + /* * State for writing output. */ @@ -120,6 +125,7 @@ extern void LogicalIncreaseRestartDecodingForSlot(XLogRecPtr current_lsn, XLogRecPtr restart_lsn); extern void LogicalConfirmReceivedLocation(XLogRecPtr lsn); +extern bool filter_prepare_cb_wrapper(LogicalDecodingContext *ctx, const char *gid); extern bool filter_by_origin_cb_wrapper(LogicalDecodingContext *ctx, RepOriginId origin_id); extern void ResetLogicalStreamingState(void); extern void UpdateDecodingStats(LogicalDecodingContext *ctx); diff --git a/src/include/replication/output_plugin.h b/src/include/replication/output_plugin.h index b78c796450a18..89e1dc3517d66 100644 --- a/src/include/replication/output_plugin.h +++ b/src/include/replication/output_plugin.h @@ -99,6 +99,45 @@ typedef bool (*LogicalDecodeFilterByOriginCB) (struct LogicalDecodingContext *ct */ typedef void (*LogicalDecodeShutdownCB) (struct LogicalDecodingContext *ctx); +/* + * Called before decoding of PREPARE record to decide whether this + * transaction should be decoded with separate calls to prepare and + * commit_prepared/rollback_prepared callbacks or wait till COMMIT PREPARED + * and sent as usual transaction. + */ +typedef bool (*LogicalDecodeFilterPrepareCB) (struct LogicalDecodingContext *ctx, + const char *gid); + +/* + * Callback called for every BEGIN of a prepared trnsaction. + */ +typedef void (*LogicalDecodeBeginPrepareCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn); + +/* + * Called for PREPARE record unless it was filtered by filter_prepare() + * callback. + */ +typedef void (*LogicalDecodePrepareCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr prepare_lsn); + +/* + * Called for COMMIT PREPARED. + */ +typedef void (*LogicalDecodeCommitPreparedCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr commit_lsn); + +/* + * Called for ROLLBACK PREPARED. + */ +typedef void (*LogicalDecodeRollbackPreparedCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr prepare_end_lsn, + TimestampTz prepare_time); + + /* * Called when starting to stream a block of changes from in-progress * transaction (may be called repeatedly, if it's streamed in multiple @@ -123,6 +162,14 @@ typedef void (*LogicalDecodeStreamAbortCB) (struct LogicalDecodingContext *ctx, ReorderBufferTXN *txn, XLogRecPtr abort_lsn); +/* + * Called to prepare changes streamed to remote node from in-progress + * transaction. This is called as part of a two-phase commit. + */ +typedef void (*LogicalDecodeStreamPrepareCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr prepare_lsn); + /* * Called to apply changes streamed to remote node from in-progress * transaction. @@ -173,10 +220,19 @@ typedef struct OutputPluginCallbacks LogicalDecodeMessageCB message_cb; LogicalDecodeFilterByOriginCB filter_by_origin_cb; LogicalDecodeShutdownCB shutdown_cb; + + /* streaming of changes at prepare time */ + LogicalDecodeFilterPrepareCB filter_prepare_cb; + LogicalDecodeBeginPrepareCB begin_prepare_cb; + LogicalDecodePrepareCB prepare_cb; + LogicalDecodeCommitPreparedCB commit_prepared_cb; + LogicalDecodeRollbackPreparedCB rollback_prepared_cb; + /* streaming of changes */ LogicalDecodeStreamStartCB stream_start_cb; LogicalDecodeStreamStopCB stream_stop_cb; LogicalDecodeStreamAbortCB stream_abort_cb; + LogicalDecodeStreamPrepareCB stream_prepare_cb; LogicalDecodeStreamCommitCB stream_commit_cb; LogicalDecodeStreamChangeCB stream_change_cb; LogicalDecodeStreamMessageCB stream_message_cb; diff --git a/src/include/replication/reorderbuffer.h b/src/include/replication/reorderbuffer.h index bd9dd7ec6764f..1e60afe70f4a0 100644 --- a/src/include/replication/reorderbuffer.h +++ b/src/include/replication/reorderbuffer.h @@ -244,6 +244,12 @@ typedef struct ReorderBufferTXN /* Xid of top-level transaction, if known */ TransactionId toplevel_xid; + /* + * Global transaction id required for identification of prepared + * transactions. + */ + char *gid; + /* * LSN of the first data carrying, WAL record with knowledge about this * xid. This is allowed to *not* be first record adorned with this xid, if @@ -418,6 +424,26 @@ typedef void (*ReorderBufferMessageCB) (ReorderBuffer *rb, const char *prefix, Size sz, const char *message); +/* begin prepare callback signature */ +typedef void (*ReorderBufferBeginPrepareCB) (ReorderBuffer *rb, + ReorderBufferTXN *txn); + +/* prepare callback signature */ +typedef void (*ReorderBufferPrepareCB) (ReorderBuffer *rb, + ReorderBufferTXN *txn, + XLogRecPtr prepare_lsn); + +/* commit prepared callback signature */ +typedef void (*ReorderBufferCommitPreparedCB) (ReorderBuffer *rb, + ReorderBufferTXN *txn, + XLogRecPtr commit_lsn); + +/* rollback prepared callback signature */ +typedef void (*ReorderBufferRollbackPreparedCB) (ReorderBuffer *rb, + ReorderBufferTXN *txn, + XLogRecPtr prepare_end_lsn, + TimestampTz prepare_time); + /* start streaming transaction callback signature */ typedef void (*ReorderBufferStreamStartCB) ( ReorderBuffer *rb, @@ -436,6 +462,12 @@ typedef void (*ReorderBufferStreamAbortCB) ( ReorderBufferTXN *txn, XLogRecPtr abort_lsn); +/* prepare streamed transaction callback signature */ +typedef void (*ReorderBufferStreamPrepareCB) ( + ReorderBuffer *rb, + ReorderBufferTXN *txn, + XLogRecPtr prepare_lsn); + /* commit streamed transaction callback signature */ typedef void (*ReorderBufferStreamCommitCB) ( ReorderBuffer *rb, @@ -504,12 +536,21 @@ struct ReorderBuffer ReorderBufferCommitCB commit; ReorderBufferMessageCB message; + /* + * Callbacks to be called when streaming a transaction at prepare time. + */ + ReorderBufferBeginCB begin_prepare; + ReorderBufferPrepareCB prepare; + ReorderBufferCommitPreparedCB commit_prepared; + ReorderBufferRollbackPreparedCB rollback_prepared; + /* * Callbacks to be called when streaming a transaction. */ ReorderBufferStreamStartCB stream_start; ReorderBufferStreamStopCB stream_stop; ReorderBufferStreamAbortCB stream_abort; + ReorderBufferStreamPrepareCB stream_prepare; ReorderBufferStreamCommitCB stream_commit; ReorderBufferStreamChangeCB stream_change; ReorderBufferStreamMessageCB stream_message; diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index bca37c536eef1..9cd047ba25ea6 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -1315,9 +1315,21 @@ LogStmtLevel LogicalDecodeBeginCB LogicalDecodeChangeCB LogicalDecodeCommitCB +LogicalDecodeFilterPrepareCB +LogicalDecodeBeginPrepareCB +LogicalDecodePrepareCB +LogicalDecodeCommitPreparedCB +LogicalDecodeRollbackPreparedCB LogicalDecodeFilterByOriginCB LogicalDecodeMessageCB LogicalDecodeShutdownCB +LogicalDecodeStreamStartCB +LogicalDecodeStreamStopCB +LogicalDecodeStreamAbortCB +LogicalDecodeStreamPrepareCB +LogicalDecodeStreamCommitCB +LogicalDecodeStreamChangeCB +LogicalDecodeStreamMessageCB LogicalDecodeStartupCB LogicalDecodeTruncateCB LogicalDecodingContext From e665769e6d1e84b6650f53ed297058fc11152f7f Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Wed, 30 Dec 2020 21:23:24 +0900 Subject: [PATCH 011/240] Sanitize IF NOT EXISTS in EXPLAIN for CTAS and matviews IF NOT EXISTS was ignored when specified in an EXPLAIN query for CREATE MATERIALIZED VIEW or CREATE TABLE AS. Hence, if this clause was specified, the caller would get a failure if the relation already exists instead of a success with a NOTICE message. This commit makes the behavior of IF NOT EXISTS in EXPLAIN consistent with the non-EXPLAIN'd DDL queries, preventing a failure with IF NOT EXISTS if the relation to-be-created already exists. The skip is done before the SELECT query used for the relation is planned or executed, and a "dummy" plan is generated instead depending on the format used by EXPLAIN. Author: Bharath Rupireddy Reviewed-by: Zhijie Hou, Michael Paquier Discussion: https://postgr.es/m/CALj2ACVa3oJ9O_wcGd+FtHWZds04dEKcakxphGz5POVgD4wC7Q@mail.gmail.com --- src/backend/commands/createas.c | 53 ++++++++++++++++------- src/backend/commands/explain.c | 16 +++++++ src/include/commands/createas.h | 2 + src/test/regress/expected/matview.out | 38 ++++++++++++++++ src/test/regress/expected/select_into.out | 42 ++++++++++++++++++ src/test/regress/sql/matview.sql | 23 ++++++++++ src/test/regress/sql/select_into.sql | 21 +++++++++ 7 files changed, 180 insertions(+), 15 deletions(-) diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c index 6bf6c5a3106ff..009896bcee78c 100644 --- a/src/backend/commands/createas.c +++ b/src/backend/commands/createas.c @@ -239,21 +239,9 @@ ExecCreateTableAs(ParseState *pstate, CreateTableAsStmt *stmt, PlannedStmt *plan; QueryDesc *queryDesc; - if (stmt->if_not_exists) - { - Oid nspid; - - nspid = RangeVarGetCreationNamespace(stmt->into->rel); - - if (get_relname_relid(stmt->into->rel->relname, nspid)) - { - ereport(NOTICE, - (errcode(ERRCODE_DUPLICATE_TABLE), - errmsg("relation \"%s\" already exists, skipping", - stmt->into->rel->relname))); - return InvalidObjectAddress; - } - } + /* Check if the relation exists or not */ + if (CreateTableAsRelExists(stmt)) + return InvalidObjectAddress; /* * Create the tuple receiver object and insert info it will need @@ -400,6 +388,41 @@ GetIntoRelEFlags(IntoClause *intoClause) return flags; } +/* + * CreateTableAsRelExists --- check existence of relation for CreateTableAsStmt + * + * Utility wrapper checking if the relation pending for creation in this + * CreateTableAsStmt query already exists or not. Returns true if the + * relation exists, otherwise false. + */ +bool +CreateTableAsRelExists(CreateTableAsStmt *ctas) +{ + Oid nspid; + IntoClause *into = ctas->into; + + nspid = RangeVarGetCreationNamespace(into->rel); + + if (get_relname_relid(into->rel->relname, nspid)) + { + if (!ctas->if_not_exists) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_TABLE), + errmsg("relation \"%s\" already exists", + into->rel->relname))); + + /* The relation exists and IF NOT EXISTS has been specified */ + ereport(NOTICE, + (errcode(ERRCODE_DUPLICATE_TABLE), + errmsg("relation \"%s\" already exists, skipping", + into->rel->relname))); + return true; + } + + /* Relation does not exist, it can be created */ + return false; +} + /* * CreateIntoRelDestReceiver -- create a suitable DestReceiver object * diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 43f9b01e833b1..d797b5f53e039 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -435,6 +435,22 @@ ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es, CreateTableAsStmt *ctas = (CreateTableAsStmt *) utilityStmt; List *rewritten; + /* + * Check if the relation exists or not. This is done at this stage to + * avoid query planning or execution. + */ + if (CreateTableAsRelExists(ctas)) + { + if (ctas->objtype == OBJECT_TABLE) + ExplainDummyGroup("CREATE TABLE AS", NULL, es); + else if (ctas->objtype == OBJECT_MATVIEW) + ExplainDummyGroup("CREATE MATERIALIZED VIEW", NULL, es); + else + elog(ERROR, "unexpected object type: %d", + (int) ctas->objtype); + return; + } + rewritten = QueryRewrite(castNode(Query, copyObject(ctas->query))); Assert(list_length(rewritten) == 1); ExplainOneQuery(linitial_node(Query, rewritten), diff --git a/src/include/commands/createas.h b/src/include/commands/createas.h index 7629230254248..d8cfb625228fc 100644 --- a/src/include/commands/createas.h +++ b/src/include/commands/createas.h @@ -29,4 +29,6 @@ extern int GetIntoRelEFlags(IntoClause *intoClause); extern DestReceiver *CreateIntoRelDestReceiver(IntoClause *intoClause); +extern bool CreateTableAsRelExists(CreateTableAsStmt *ctas); + #endif /* CREATEAS_H */ diff --git a/src/test/regress/expected/matview.out b/src/test/regress/expected/matview.out index 2c0760404d3bb..4b3a2e0cb7306 100644 --- a/src/test/regress/expected/matview.out +++ b/src/test/regress/expected/matview.out @@ -630,3 +630,41 @@ drop cascades to materialized view matview_schema.mv_withdata2 drop cascades to materialized view matview_schema.mv_nodata1 drop cascades to materialized view matview_schema.mv_nodata2 DROP USER regress_matview_user; +-- CREATE MATERIALIZED VIEW ... IF NOT EXISTS +CREATE MATERIALIZED VIEW matview_ine_tab AS SELECT 1; +CREATE MATERIALIZED VIEW matview_ine_tab AS SELECT 1 / 0; -- error +ERROR: relation "matview_ine_tab" already exists +CREATE MATERIALIZED VIEW IF NOT EXISTS matview_ine_tab AS + SELECT 1 / 0; -- ok +NOTICE: relation "matview_ine_tab" already exists, skipping +CREATE MATERIALIZED VIEW matview_ine_tab AS + SELECT 1 / 0 WITH NO DATA; -- error +ERROR: relation "matview_ine_tab" already exists +CREATE MATERIALIZED VIEW IF NOT EXISTS matview_ine_tab AS + SELECT 1 / 0 WITH NO DATA; -- ok +NOTICE: relation "matview_ine_tab" already exists, skipping +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE MATERIALIZED VIEW matview_ine_tab AS + SELECT 1 / 0; -- error +ERROR: relation "matview_ine_tab" already exists +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE MATERIALIZED VIEW IF NOT EXISTS matview_ine_tab AS + SELECT 1 / 0; -- ok +NOTICE: relation "matview_ine_tab" already exists, skipping + QUERY PLAN +------------ +(0 rows) + +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE MATERIALIZED VIEW matview_ine_tab AS + SELECT 1 / 0 WITH NO DATA; -- error +ERROR: relation "matview_ine_tab" already exists +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE MATERIALIZED VIEW IF NOT EXISTS matview_ine_tab AS + SELECT 1 / 0 WITH NO DATA; -- ok +NOTICE: relation "matview_ine_tab" already exists, skipping + QUERY PLAN +------------ +(0 rows) + +DROP MATERIALIZED VIEW matview_ine_tab; diff --git a/src/test/regress/expected/select_into.out b/src/test/regress/expected/select_into.out index bf5c6bea045ee..43b8209d22954 100644 --- a/src/test/regress/expected/select_into.out +++ b/src/test/regress/expected/select_into.out @@ -178,3 +178,45 @@ INSERT INTO b SELECT 1 INTO f; ERROR: SELECT ... INTO is not allowed here LINE 1: INSERT INTO b SELECT 1 INTO f; ^ +-- Test CREATE TABLE AS ... IF NOT EXISTS +CREATE TABLE ctas_ine_tbl AS SELECT 1; +CREATE TABLE ctas_ine_tbl AS SELECT 1 / 0; -- error +ERROR: relation "ctas_ine_tbl" already exists +CREATE TABLE IF NOT EXISTS ctas_ine_tbl AS SELECT 1 / 0; -- ok +NOTICE: relation "ctas_ine_tbl" already exists, skipping +CREATE TABLE ctas_ine_tbl AS SELECT 1 / 0 WITH NO DATA; -- error +ERROR: relation "ctas_ine_tbl" already exists +CREATE TABLE IF NOT EXISTS ctas_ine_tbl AS SELECT 1 / 0 WITH NO DATA; -- ok +NOTICE: relation "ctas_ine_tbl" already exists, skipping +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE TABLE ctas_ine_tbl AS SELECT 1 / 0; -- error +ERROR: relation "ctas_ine_tbl" already exists +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE TABLE IF NOT EXISTS ctas_ine_tbl AS SELECT 1 / 0; -- ok +NOTICE: relation "ctas_ine_tbl" already exists, skipping + QUERY PLAN +------------ +(0 rows) + +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE TABLE ctas_ine_tbl AS SELECT 1 / 0 WITH NO DATA; -- error +ERROR: relation "ctas_ine_tbl" already exists +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE TABLE IF NOT EXISTS ctas_ine_tbl AS SELECT 1 / 0 WITH NO DATA; -- ok +NOTICE: relation "ctas_ine_tbl" already exists, skipping + QUERY PLAN +------------ +(0 rows) + +PREPARE ctas_ine_query AS SELECT 1 / 0; +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE TABLE ctas_ine_tbl AS EXECUTE ctas_ine_query; -- error +ERROR: relation "ctas_ine_tbl" already exists +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE TABLE IF NOT EXISTS ctas_ine_tbl AS EXECUTE ctas_ine_query; -- ok +NOTICE: relation "ctas_ine_tbl" already exists, skipping + QUERY PLAN +------------ +(0 rows) + +DROP TABLE ctas_ine_tbl; diff --git a/src/test/regress/sql/matview.sql b/src/test/regress/sql/matview.sql index 70c4954d89a30..4a4bd0d6b6199 100644 --- a/src/test/regress/sql/matview.sql +++ b/src/test/regress/sql/matview.sql @@ -264,3 +264,26 @@ ALTER DEFAULT PRIVILEGES FOR ROLE regress_matview_user DROP SCHEMA matview_schema CASCADE; DROP USER regress_matview_user; + +-- CREATE MATERIALIZED VIEW ... IF NOT EXISTS +CREATE MATERIALIZED VIEW matview_ine_tab AS SELECT 1; +CREATE MATERIALIZED VIEW matview_ine_tab AS SELECT 1 / 0; -- error +CREATE MATERIALIZED VIEW IF NOT EXISTS matview_ine_tab AS + SELECT 1 / 0; -- ok +CREATE MATERIALIZED VIEW matview_ine_tab AS + SELECT 1 / 0 WITH NO DATA; -- error +CREATE MATERIALIZED VIEW IF NOT EXISTS matview_ine_tab AS + SELECT 1 / 0 WITH NO DATA; -- ok +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE MATERIALIZED VIEW matview_ine_tab AS + SELECT 1 / 0; -- error +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE MATERIALIZED VIEW IF NOT EXISTS matview_ine_tab AS + SELECT 1 / 0; -- ok +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE MATERIALIZED VIEW matview_ine_tab AS + SELECT 1 / 0 WITH NO DATA; -- error +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE MATERIALIZED VIEW IF NOT EXISTS matview_ine_tab AS + SELECT 1 / 0 WITH NO DATA; -- ok +DROP MATERIALIZED VIEW matview_ine_tab; diff --git a/src/test/regress/sql/select_into.sql b/src/test/regress/sql/select_into.sql index 6c170ef9688a1..7e903c339a809 100644 --- a/src/test/regress/sql/select_into.sql +++ b/src/test/regress/sql/select_into.sql @@ -115,3 +115,24 @@ COPY (SELECT 1 INTO frak UNION SELECT 2) TO 'blob'; SELECT * FROM (SELECT 1 INTO f) bar; CREATE VIEW foo AS SELECT 1 INTO b; INSERT INTO b SELECT 1 INTO f; + +-- Test CREATE TABLE AS ... IF NOT EXISTS +CREATE TABLE ctas_ine_tbl AS SELECT 1; +CREATE TABLE ctas_ine_tbl AS SELECT 1 / 0; -- error +CREATE TABLE IF NOT EXISTS ctas_ine_tbl AS SELECT 1 / 0; -- ok +CREATE TABLE ctas_ine_tbl AS SELECT 1 / 0 WITH NO DATA; -- error +CREATE TABLE IF NOT EXISTS ctas_ine_tbl AS SELECT 1 / 0 WITH NO DATA; -- ok +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE TABLE ctas_ine_tbl AS SELECT 1 / 0; -- error +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE TABLE IF NOT EXISTS ctas_ine_tbl AS SELECT 1 / 0; -- ok +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE TABLE ctas_ine_tbl AS SELECT 1 / 0 WITH NO DATA; -- error +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE TABLE IF NOT EXISTS ctas_ine_tbl AS SELECT 1 / 0 WITH NO DATA; -- ok +PREPARE ctas_ine_query AS SELECT 1 / 0; +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE TABLE ctas_ine_tbl AS EXECUTE ctas_ine_query; -- error +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE TABLE IF NOT EXISTS ctas_ine_tbl AS EXECUTE ctas_ine_query; -- ok +DROP TABLE ctas_ine_tbl; From 860fe27ee1e2a4a1c36c2f874c37656533cccce9 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 30 Dec 2020 11:38:42 -0500 Subject: [PATCH 012/240] Fix up usage of krb_server_keyfile GUC parameter. secure_open_gssapi() installed the krb_server_keyfile setting as KRB5_KTNAME unconditionally, so long as it's not empty. However, pg_GSS_recvauth() only installed it if KRB5_KTNAME wasn't set already, leading to a troubling inconsistency: in theory, clients could see different sets of server principal names depending on whether they use GSSAPI encryption. Always using krb_server_keyfile seems like the right thing, so make both places do that. Also fix up secure_open_gssapi()'s lack of a check for setenv() failure --- it's unlikely, surely, but security-critical actions are no place to be sloppy. Also improve the associated documentation. This patch does nothing about secure_open_gssapi()'s use of setenv(), and indeed causes pg_GSS_recvauth() to use it too. That's nominally against project portability rules, but since this code is only built with --with-gssapi, I do not feel a need to do something about this in the back branches. A fix will be forthcoming for HEAD though. Back-patch to v12 where GSSAPI encryption was introduced. The dubious behavior in pg_GSS_recvauth() goes back further, but it didn't have anything to be inconsistent with, so let it be. Discussion: https://postgr.es/m/2187460.1609263156@sss.pgh.pa.us --- doc/src/sgml/client-auth.sgml | 6 +--- doc/src/sgml/config.sgml | 12 +++++-- src/backend/libpq/auth.c | 31 ++++++------------- src/backend/libpq/be-secure-gssapi.c | 12 +++++-- src/backend/utils/misc/postgresql.conf.sample | 2 +- 5 files changed, 31 insertions(+), 32 deletions(-) diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml index 9a5c9318cee42..c4b9971a206cc 100644 --- a/doc/src/sgml/client-auth.sgml +++ b/doc/src/sgml/client-auth.sgml @@ -1265,11 +1265,7 @@ omicron bryanh guest1 The location of the server's keytab file is specified by the configuration - parameter. The default is - FILE:/usr/local/pgsql/etc/krb5.keytab - (where the directory part is whatever was specified - as sysconfdir at build time). + linkend="guc-krb-server-keyfile"/> configuration parameter. For security reasons, it is recommended to use a separate keytab just for the PostgreSQL server rather than allowing the server to read the system keytab file. diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 048bd6aa08a6b..67de4150b8e48 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -1057,10 +1057,16 @@ include_dir 'conf.d' - Sets the location of the Kerberos server key file. See - - for details. This parameter can only be set in the + Sets the location of the server's Kerberos key file. The default is + FILE:/usr/local/pgsql/etc/krb5.keytab + (where the directory part is whatever was specified + as sysconfdir at build time; use + pg_config --sysconfdir to determine that). + If this parameter is set to an empty string, it is ignored and a + system-dependent default is used. + This parameter can only be set in the postgresql.conf file or on the server command line. + See for more information. diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 515ae95fe109a..e51ede5a2228f 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -1054,29 +1054,18 @@ pg_GSS_recvauth(Port *port) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("GSSAPI is not supported in protocol version 2"))); - if (pg_krb_server_keyfile && strlen(pg_krb_server_keyfile) > 0) + /* + * Use the configured keytab, if there is one. Unfortunately, Heimdal + * doesn't support the cred store extensions, so use the env var. + */ + if (pg_krb_server_keyfile != NULL && pg_krb_server_keyfile[0] != '\0') { - /* - * Set default Kerberos keytab file for the Krb5 mechanism. - * - * setenv("KRB5_KTNAME", pg_krb_server_keyfile, 0); except setenv() - * not always available. - */ - if (getenv("KRB5_KTNAME") == NULL) + if (setenv("KRB5_KTNAME", pg_krb_server_keyfile, 1) != 0) { - size_t kt_len = strlen(pg_krb_server_keyfile) + 14; - char *kt_path = malloc(kt_len); - - if (!kt_path || - snprintf(kt_path, kt_len, "KRB5_KTNAME=%s", - pg_krb_server_keyfile) != kt_len - 2 || - putenv(kt_path) != 0) - { - ereport(LOG, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"))); - return STATUS_ERROR; - } + /* The only likely failure cause is OOM, so use that errcode */ + ereport(FATAL, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("could not set environment: %m"))); } } diff --git a/src/backend/libpq/be-secure-gssapi.c b/src/backend/libpq/be-secure-gssapi.c index 1747fccb143e2..547c7d6a177bd 100644 --- a/src/backend/libpq/be-secure-gssapi.c +++ b/src/backend/libpq/be-secure-gssapi.c @@ -525,8 +525,16 @@ secure_open_gssapi(Port *port) * Use the configured keytab, if there is one. Unfortunately, Heimdal * doesn't support the cred store extensions, so use the env var. */ - if (pg_krb_server_keyfile != NULL && strlen(pg_krb_server_keyfile) > 0) - setenv("KRB5_KTNAME", pg_krb_server_keyfile, 1); + if (pg_krb_server_keyfile != NULL && pg_krb_server_keyfile[0] != '\0') + { + if (setenv("KRB5_KTNAME", pg_krb_server_keyfile, 1) != 0) + { + /* The only likely failure cause is OOM, so use that errcode */ + ereport(FATAL, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("could not set environment: %m"))); + } + } while (true) { diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index b7fb2ec1feb6b..5298e18ecd558 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -92,7 +92,7 @@ #db_user_namespace = off # GSSAPI using Kerberos -#krb_server_keyfile = '' +#krb_server_keyfile = 'FILE:${sysconfdir}/krb5.keytab' #krb_caseins_users = off # - SSL - From 62097a4cc8c725fa86d3170396a8f30609acd0d3 Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Wed, 30 Dec 2020 20:19:15 +0300 Subject: [PATCH 013/240] Fix selectivity estimation @> (anymultirange, anyrange) operator Attempt to get selectivity estimation for @> (anymultirange, anyrange) operator caused an error in buildfarm, because this operator was missed in switch() of calc_hist_selectivity(). Fix that and also make regression tests reliably check that selectivity estimation for (multi)ranges doesn't fall. Previously, whether we test selectivity estimation for (multi)ranges depended on whether autovacuum managed to gather concurrently to the test. Reported-by: Michael Paquier Discussion: https://postgr.es/m/X%2BwmgjRItuvHNBeV%40paquier.xyz --- src/backend/utils/adt/multirangetypes_selfuncs.c | 1 + src/test/regress/expected/multirangetypes.out | 5 +++++ src/test/regress/expected/rangetypes.out | 5 +++++ src/test/regress/sql/multirangetypes.sql | 6 ++++++ src/test/regress/sql/rangetypes.sql | 6 ++++++ 5 files changed, 23 insertions(+) diff --git a/src/backend/utils/adt/multirangetypes_selfuncs.c b/src/backend/utils/adt/multirangetypes_selfuncs.c index bb016b6e98770..14283e4503a2b 100644 --- a/src/backend/utils/adt/multirangetypes_selfuncs.c +++ b/src/backend/utils/adt/multirangetypes_selfuncs.c @@ -649,6 +649,7 @@ calc_hist_selectivity(TypeCacheEntry *typcache, VariableStatData *vardata, case OID_MULTIRANGE_RANGE_CONTAINED_OP: case OID_MULTIRANGE_MULTIRANGE_CONTAINED_OP: + case OID_RANGE_MULTIRANGE_CONTAINED_OP: if (const_lower.infinite) { /* diff --git a/src/test/regress/expected/multirangetypes.out b/src/test/regress/expected/multirangetypes.out index 86011a02a1e69..04953a5990324 100644 --- a/src/test/regress/expected/multirangetypes.out +++ b/src/test/regress/expected/multirangetypes.out @@ -2227,6 +2227,11 @@ insert into test_multirange_gist select int4multirange(int4range(g, g+10000)) fr insert into test_multirange_gist select int4multirange(int4range(NULL, g*10, '(]'), int4range(g*10, g*20, '(]')) from generate_series(1,100) g; insert into test_multirange_gist select int4multirange(int4range(g*10, g*20, '(]'), int4range(g*20, NULL, '(]')) from generate_series(1,100) g; create index test_mulrirange_gist_idx on test_multirange_gist using gist (mr); +-- test statistics and selectivity estimation as well +-- +-- We don't check the accuracy of selectivity estimation, but at least check +-- it doesn't fall. +analyze test_multirange_gist; -- first, verify non-indexed results SET enable_seqscan = t; SET enable_indexscan = f; diff --git a/src/test/regress/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out index 28dc995e5994f..05b882fde93f3 100644 --- a/src/test/regress/expected/rangetypes.out +++ b/src/test/regress/expected/rangetypes.out @@ -792,6 +792,11 @@ insert into test_range_gist select 'empty'::int4range from generate_series(1,500 insert into test_range_gist select int4range(NULL,g*10,'(]') from generate_series(1,100) g; insert into test_range_gist select int4range(g*10,NULL,'(]') from generate_series(1,100) g; insert into test_range_gist select int4range(g, g+10) from generate_series(1,2000) g; +-- test statistics and selectivity estimation as well +-- +-- We don't check the accuracy of selectivity estimation, but at least check +-- it doesn't fall. +analyze test_range_gist; -- first, verify non-indexed results SET enable_seqscan = t; SET enable_indexscan = f; diff --git a/src/test/regress/sql/multirangetypes.sql b/src/test/regress/sql/multirangetypes.sql index 2a2ee4dcdfd8f..692f2416d9b8d 100644 --- a/src/test/regress/sql/multirangetypes.sql +++ b/src/test/regress/sql/multirangetypes.sql @@ -423,6 +423,12 @@ insert into test_multirange_gist select int4multirange(int4range(NULL, g*10, '(] insert into test_multirange_gist select int4multirange(int4range(g*10, g*20, '(]'), int4range(g*20, NULL, '(]')) from generate_series(1,100) g; create index test_mulrirange_gist_idx on test_multirange_gist using gist (mr); +-- test statistics and selectivity estimation as well +-- +-- We don't check the accuracy of selectivity estimation, but at least check +-- it doesn't fall. +analyze test_multirange_gist; + -- first, verify non-indexed results SET enable_seqscan = t; SET enable_indexscan = f; diff --git a/src/test/regress/sql/rangetypes.sql b/src/test/regress/sql/rangetypes.sql index 51eddabf60f4e..e1b8917c0c538 100644 --- a/src/test/regress/sql/rangetypes.sql +++ b/src/test/regress/sql/rangetypes.sql @@ -216,6 +216,12 @@ insert into test_range_gist select int4range(NULL,g*10,'(]') from generate_serie insert into test_range_gist select int4range(g*10,NULL,'(]') from generate_series(1,100) g; insert into test_range_gist select int4range(g, g+10) from generate_series(1,2000) g; +-- test statistics and selectivity estimation as well +-- +-- We don't check the accuracy of selectivity estimation, but at least check +-- it doesn't fall. +analyze test_range_gist; + -- first, verify non-indexed results SET enable_seqscan = t; SET enable_indexscan = f; From 7ca37fb0406bc2cbbd864a2ffdbdb4479e338c0c Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 30 Dec 2020 12:55:59 -0500 Subject: [PATCH 014/240] Use setenv() in preference to putenv(). Since at least 2001 we've used putenv() and avoided setenv(), on the grounds that the latter was unportable and not in POSIX. However, POSIX added it that same year, and by now the situation has reversed: setenv() is probably more portable than putenv(), since POSIX now treats the latter as not being a core function. And setenv() has cleaner semantics too. So, let's reverse that old policy. This commit adds a simple src/port/ implementation of setenv() for any stragglers (we have one in the buildfarm, but I'd not be surprised if that code is never used in the field). More importantly, extend win32env.c to also support setenv(). Then, replace usages of putenv() with setenv(), and get rid of some ad-hoc implementations of setenv() wannabees. Also, adjust our src/port/ implementation of unsetenv() to follow the POSIX spec that it returns an error indicator, rather than returning void as per the ancient BSD convention. I don't feel a need to make all the call sites check for errors, but the portability stub ought to match real-world practice. Discussion: https://postgr.es/m/2065122.1609212051@sss.pgh.pa.us --- configure | 19 +++++++- configure.ac | 4 +- contrib/dblink/input/paths.source | 6 +-- contrib/dblink/output/paths.source | 6 +-- src/backend/utils/adt/pg_locale.c | 31 ++----------- src/bin/initdb/initdb.c | 10 ++-- src/bin/pg_ctl/pg_ctl.c | 12 ++--- src/bin/pg_upgrade/controldata.c | 54 ++++++++++++++-------- src/bin/pg_upgrade/option.c | 6 +-- src/bin/pg_upgrade/pg_upgrade.h | 1 - src/bin/pg_upgrade/util.c | 36 --------------- src/bin/psql/command.c | 11 +---- src/common/exec.c | 22 ++------- src/common/restricted_token.c | 2 +- src/include/pg_config.h.in | 3 ++ src/include/port.h | 6 ++- src/include/port/win32_port.h | 10 ++-- src/interfaces/ecpg/test/pg_regress_ecpg.c | 6 +-- src/port/setenv.c | 48 +++++++++++++++++++ src/port/unsetenv.c | 18 ++++++-- src/port/win32env.c | 50 +++++++++++++++++--- src/test/isolation/isolation_main.c | 6 +-- src/test/regress/pg_regress.c | 45 +++++++----------- src/test/regress/pg_regress_main.c | 6 +-- src/test/regress/regress.c | 14 ++---- src/tools/msvc/Solution.pm | 1 + 26 files changed, 234 insertions(+), 199 deletions(-) create mode 100644 src/port/setenv.c diff --git a/configure b/configure index 11a4284e5bd75..07529825d1897 100755 --- a/configure +++ b/configure @@ -15959,12 +15959,29 @@ case $host_os in # Windows uses a specialised env handler mingw*) +$as_echo "#define HAVE_SETENV 1" >>confdefs.h + + $as_echo "#define HAVE_UNSETENV 1" >>confdefs.h + ac_cv_func_setenv=yes ac_cv_func_unsetenv=yes ;; *) - ac_fn_c_check_func "$LINENO" "unsetenv" "ac_cv_func_unsetenv" + ac_fn_c_check_func "$LINENO" "setenv" "ac_cv_func_setenv" +if test "x$ac_cv_func_setenv" = xyes; then : + $as_echo "#define HAVE_SETENV 1" >>confdefs.h + +else + case " $LIBOBJS " in + *" setenv.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS setenv.$ac_objext" + ;; +esac + +fi + +ac_fn_c_check_func "$LINENO" "unsetenv" "ac_cv_func_unsetenv" if test "x$ac_cv_func_unsetenv" = xyes; then : $as_echo "#define HAVE_UNSETENV 1" >>confdefs.h diff --git a/configure.ac b/configure.ac index fc523c6aeb413..7f855783f4ef5 100644 --- a/configure.ac +++ b/configure.ac @@ -1757,11 +1757,13 @@ fi case $host_os in # Windows uses a specialised env handler mingw*) + AC_DEFINE(HAVE_SETENV, 1, [Define to 1 because replacement version used.]) AC_DEFINE(HAVE_UNSETENV, 1, [Define to 1 because replacement version used.]) + ac_cv_func_setenv=yes ac_cv_func_unsetenv=yes ;; *) - AC_REPLACE_FUNCS([unsetenv]) + AC_REPLACE_FUNCS([setenv unsetenv]) ;; esac diff --git a/contrib/dblink/input/paths.source b/contrib/dblink/input/paths.source index aab3a3b2bfb42..881a65314f34e 100644 --- a/contrib/dblink/input/paths.source +++ b/contrib/dblink/input/paths.source @@ -1,8 +1,8 @@ -- Initialization that requires path substitution. -CREATE FUNCTION putenv(text) +CREATE FUNCTION setenv(text, text) RETURNS void - AS '@libdir@/regress@DLSUFFIX@', 'regress_putenv' + AS '@libdir@/regress@DLSUFFIX@', 'regress_setenv' LANGUAGE C STRICT; CREATE FUNCTION wait_pid(int) @@ -11,4 +11,4 @@ CREATE FUNCTION wait_pid(int) LANGUAGE C STRICT; CREATE FUNCTION set_pgservicefile(text) RETURNS void LANGUAGE SQL - AS $$SELECT putenv('PGSERVICEFILE=@abs_srcdir@/' || $1)$$; + AS $$SELECT setenv('PGSERVICEFILE', '@abs_srcdir@/' || $1)$$; diff --git a/contrib/dblink/output/paths.source b/contrib/dblink/output/paths.source index e1097f0996fea..8ed95e1f78259 100644 --- a/contrib/dblink/output/paths.source +++ b/contrib/dblink/output/paths.source @@ -1,11 +1,11 @@ -- Initialization that requires path substitution. -CREATE FUNCTION putenv(text) +CREATE FUNCTION setenv(text, text) RETURNS void - AS '@libdir@/regress@DLSUFFIX@', 'regress_putenv' + AS '@libdir@/regress@DLSUFFIX@', 'regress_setenv' LANGUAGE C STRICT; CREATE FUNCTION wait_pid(int) RETURNS void AS '@libdir@/regress@DLSUFFIX@' LANGUAGE C STRICT; CREATE FUNCTION set_pgservicefile(text) RETURNS void LANGUAGE SQL - AS $$SELECT putenv('PGSERVICEFILE=@abs_srcdir@/' || $1)$$; + AS $$SELECT setenv('PGSERVICEFILE', '@abs_srcdir@/' || $1)$$; diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c index c39d67645c693..088c1444c3b20 100644 --- a/src/backend/utils/adt/pg_locale.c +++ b/src/backend/utils/adt/pg_locale.c @@ -105,20 +105,6 @@ char *localized_full_months[12 + 1]; static bool CurrentLocaleConvValid = false; static bool CurrentLCTimeValid = false; -/* Environment variable storage area */ - -#define LC_ENV_BUFSIZE (NAMEDATALEN + 20) - -static char lc_collate_envbuf[LC_ENV_BUFSIZE]; -static char lc_ctype_envbuf[LC_ENV_BUFSIZE]; - -#ifdef LC_MESSAGES -static char lc_messages_envbuf[LC_ENV_BUFSIZE]; -#endif -static char lc_monetary_envbuf[LC_ENV_BUFSIZE]; -static char lc_numeric_envbuf[LC_ENV_BUFSIZE]; -static char lc_time_envbuf[LC_ENV_BUFSIZE]; - /* Cache for collation-related knowledge */ typedef struct @@ -163,7 +149,6 @@ pg_perm_setlocale(int category, const char *locale) { char *result; const char *envvar; - char *envbuf; #ifndef WIN32 result = setlocale(category, locale); @@ -199,7 +184,7 @@ pg_perm_setlocale(int category, const char *locale) */ if (category == LC_CTYPE) { - static char save_lc_ctype[LC_ENV_BUFSIZE]; + static char save_lc_ctype[NAMEDATALEN + 20]; /* copy setlocale() return value before callee invokes it again */ strlcpy(save_lc_ctype, result, sizeof(save_lc_ctype)); @@ -216,16 +201,13 @@ pg_perm_setlocale(int category, const char *locale) { case LC_COLLATE: envvar = "LC_COLLATE"; - envbuf = lc_collate_envbuf; break; case LC_CTYPE: envvar = "LC_CTYPE"; - envbuf = lc_ctype_envbuf; break; #ifdef LC_MESSAGES case LC_MESSAGES: envvar = "LC_MESSAGES"; - envbuf = lc_messages_envbuf; #ifdef WIN32 result = IsoLocaleName(locale); if (result == NULL) @@ -236,26 +218,19 @@ pg_perm_setlocale(int category, const char *locale) #endif /* LC_MESSAGES */ case LC_MONETARY: envvar = "LC_MONETARY"; - envbuf = lc_monetary_envbuf; break; case LC_NUMERIC: envvar = "LC_NUMERIC"; - envbuf = lc_numeric_envbuf; break; case LC_TIME: envvar = "LC_TIME"; - envbuf = lc_time_envbuf; break; default: elog(FATAL, "unrecognized LC category: %d", category); - envvar = NULL; /* keep compiler quiet */ - envbuf = NULL; - return NULL; + return NULL; /* keep compiler quiet */ } - snprintf(envbuf, LC_ENV_BUFSIZE - 1, "%s=%s", envvar, result); - - if (putenv(envbuf)) + if (setenv(envvar, result, 1) != 0) return NULL; return result; diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index f994c4216bcdc..0865f73ee0b76 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -2355,8 +2355,7 @@ check_need_password(const char *authmethodlocal, const char *authmethodhost) void setup_pgdata(void) { - char *pgdata_get_env, - *pgdata_set_env; + char *pgdata_get_env; if (!pg_data) { @@ -2386,8 +2385,11 @@ setup_pgdata(void) * need quotes otherwise on Windows because paths there are most likely to * have embedded spaces. */ - pgdata_set_env = psprintf("PGDATA=%s", pg_data); - putenv(pgdata_set_env); + if (setenv("PGDATA", pg_data, 1) != 0) + { + pg_log_error("could not set environment"); + exit(1); + } } diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c index fc07f1aba6e77..fcdc0213e488c 100644 --- a/src/bin/pg_ctl/pg_ctl.c +++ b/src/bin/pg_ctl/pg_ctl.c @@ -889,11 +889,10 @@ do_start(void) */ #ifndef WIN32 { - static char env_var[32]; + char env_var[32]; - snprintf(env_var, sizeof(env_var), "PG_GRANDPARENT_PID=%d", - (int) getppid()); - putenv(env_var); + snprintf(env_var, sizeof(env_var), "%d", (int) getppid()); + setenv("PG_GRANDPARENT_PID", env_var, 1); } #endif @@ -2340,12 +2339,10 @@ main(int argc, char **argv) case 'D': { char *pgdata_D; - char *env_var; pgdata_D = pg_strdup(optarg); canonicalize_path(pgdata_D); - env_var = psprintf("PGDATA=%s", pgdata_D); - putenv(env_var); + setenv("PGDATA", pgdata_D, 1); /* * We could pass PGDATA just in an environment @@ -2353,6 +2350,7 @@ main(int argc, char **argv) * 'ps' display */ pgdata_opt = psprintf("-D \"%s\" ", pgdata_D); + free(pgdata_D); break; } case 'e': diff --git a/src/bin/pg_upgrade/controldata.c b/src/bin/pg_upgrade/controldata.c index 39bcaa8fe1a2b..7eb56e7a293f5 100644 --- a/src/bin/pg_upgrade/controldata.c +++ b/src/bin/pg_upgrade/controldata.c @@ -97,20 +97,20 @@ get_control_data(ClusterInfo *cluster, bool live_check) if (getenv("LC_MESSAGES")) lc_messages = pg_strdup(getenv("LC_MESSAGES")); - pg_putenv("LC_COLLATE", NULL); - pg_putenv("LC_CTYPE", NULL); - pg_putenv("LC_MONETARY", NULL); - pg_putenv("LC_NUMERIC", NULL); - pg_putenv("LC_TIME", NULL); + unsetenv("LC_COLLATE"); + unsetenv("LC_CTYPE"); + unsetenv("LC_MONETARY"); + unsetenv("LC_NUMERIC"); + unsetenv("LC_TIME"); #ifndef WIN32 - pg_putenv("LANG", NULL); + unsetenv("LANG"); #else /* On Windows the default locale may not be English, so force it */ - pg_putenv("LANG", "en"); + setenv("LANG", "en", 1); #endif - pg_putenv("LANGUAGE", NULL); - pg_putenv("LC_ALL", NULL); - pg_putenv("LC_MESSAGES", "C"); + unsetenv("LANGUAGE"); + unsetenv("LC_ALL"); + setenv("LC_MESSAGES", "C", 1); /* * Check for clean shutdown @@ -490,17 +490,31 @@ get_control_data(ClusterInfo *cluster, bool live_check) pclose(output); /* - * Restore environment variables + * Restore environment variables. Note all but LANG and LC_MESSAGES were + * unset above. */ - pg_putenv("LC_COLLATE", lc_collate); - pg_putenv("LC_CTYPE", lc_ctype); - pg_putenv("LC_MONETARY", lc_monetary); - pg_putenv("LC_NUMERIC", lc_numeric); - pg_putenv("LC_TIME", lc_time); - pg_putenv("LANG", lang); - pg_putenv("LANGUAGE", language); - pg_putenv("LC_ALL", lc_all); - pg_putenv("LC_MESSAGES", lc_messages); + if (lc_collate) + setenv("LC_COLLATE", lc_collate, 1); + if (lc_ctype) + setenv("LC_CTYPE", lc_ctype, 1); + if (lc_monetary) + setenv("LC_MONETARY", lc_monetary, 1); + if (lc_numeric) + setenv("LC_NUMERIC", lc_numeric, 1); + if (lc_time) + setenv("LC_TIME", lc_time, 1); + if (lang) + setenv("LANG", lang, 1); + else + unsetenv("LANG"); + if (language) + setenv("LANGUAGE", language, 1); + if (lc_all) + setenv("LC_ALL", lc_all, 1); + if (lc_messages) + setenv("LC_MESSAGES", lc_messages, 1); + else + unsetenv("LC_MESSAGES"); pg_free(lc_collate); pg_free(lc_ctype); diff --git a/src/bin/pg_upgrade/option.c b/src/bin/pg_upgrade/option.c index 548d648e8c4e6..5b566c14ef4ea 100644 --- a/src/bin/pg_upgrade/option.c +++ b/src/bin/pg_upgrade/option.c @@ -193,7 +193,7 @@ parseCommandLine(int argc, char *argv[]) * Push the user name into the environment so pre-9.1 * pg_ctl/libpq uses it. */ - pg_putenv("PGUSER", os_info.user); + setenv("PGUSER", os_info.user, 1); break; case 'v': @@ -245,11 +245,11 @@ parseCommandLine(int argc, char *argv[]) char *pgoptions = psprintf("%s %s", FIX_DEFAULT_READ_ONLY, getenv("PGOPTIONS")); - pg_putenv("PGOPTIONS", pgoptions); + setenv("PGOPTIONS", pgoptions, 1); pfree(pgoptions); } else - pg_putenv("PGOPTIONS", FIX_DEFAULT_READ_ONLY); + setenv("PGOPTIONS", FIX_DEFAULT_READ_ONLY, 1); /* Get values from env if not already set */ check_required_directory(&old_cluster.bindir, "PGBINOLD", false, diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h index ee70243c2e946..1842556274ffa 100644 --- a/src/bin/pg_upgrade/pg_upgrade.h +++ b/src/bin/pg_upgrade/pg_upgrade.h @@ -436,7 +436,6 @@ void end_progress_output(void); void prep_status(const char *fmt,...) pg_attribute_printf(1, 2); void check_ok(void); unsigned int str2uint(const char *str); -void pg_putenv(const char *var, const char *val); /* version.c */ diff --git a/src/bin/pg_upgrade/util.c b/src/bin/pg_upgrade/util.c index a16c794261b59..9c9ba29124e31 100644 --- a/src/bin/pg_upgrade/util.c +++ b/src/bin/pg_upgrade/util.c @@ -241,39 +241,3 @@ str2uint(const char *str) { return strtoul(str, NULL, 10); } - - -/* - * pg_putenv() - * - * This is like putenv(), but takes two arguments. - * It also does unsetenv() if val is NULL. - */ -void -pg_putenv(const char *var, const char *val) -{ - if (val) - { -#ifndef WIN32 - char *envstr; - - envstr = psprintf("%s=%s", var, val); - putenv(envstr); - - /* - * Do not free envstr because it becomes part of the environment on - * some operating systems. See port/unsetenv.c::unsetenv. - */ -#else - SetEnvironmentVariableA(var, val); -#endif - } - else - { -#ifndef WIN32 - unsetenv(var); -#else - SetEnvironmentVariableA(var, ""); -#endif - } -} diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 38b588882d154..c545341cddd01 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -2296,17 +2296,8 @@ exec_command_setenv(PsqlScanState scan_state, bool active_branch, else { /* Set variable to the value of the next argument */ - char *newval; - - newval = psprintf("%s=%s", envvar, envval); - putenv(newval); + setenv(envvar, envval, 1); success = true; - - /* - * Do not free newval here, it will screw up the environment if - * you do. See putenv man page for details. That means we leak a - * bit of memory here, but not enough to worry about. - */ } free(envvar); free(envval); diff --git a/src/common/exec.c b/src/common/exec.c index 78bb486f999a2..773afd080c05a 100644 --- a/src/common/exec.c +++ b/src/common/exec.c @@ -435,9 +435,6 @@ set_pglocale_pgservice(const char *argv0, const char *app) { char path[MAXPGPATH]; char my_exec_path[MAXPGPATH]; - char env_path[MAXPGPATH + sizeof("PGSYSCONFDIR=")]; /* longer than - * PGLOCALEDIR */ - char *dup_path; /* don't set LC_ALL in the backend */ if (strcmp(app, PG_TEXTDOMAIN("postgres")) != 0) @@ -462,28 +459,15 @@ set_pglocale_pgservice(const char *argv0, const char *app) get_locale_path(my_exec_path, path); bindtextdomain(app, path); textdomain(app); - - if (getenv("PGLOCALEDIR") == NULL) - { - /* set for libpq to use */ - snprintf(env_path, sizeof(env_path), "PGLOCALEDIR=%s", path); - canonicalize_path(env_path + 12); - dup_path = strdup(env_path); - if (dup_path) - putenv(dup_path); - } + /* set for libpq to use, but don't override existing setting */ + setenv("PGLOCALEDIR", path, 0); #endif if (getenv("PGSYSCONFDIR") == NULL) { get_etc_path(my_exec_path, path); - /* set for libpq to use */ - snprintf(env_path, sizeof(env_path), "PGSYSCONFDIR=%s", path); - canonicalize_path(env_path + 13); - dup_path = strdup(env_path); - if (dup_path) - putenv(dup_path); + setenv("PGSYSCONFDIR", path, 0); } } diff --git a/src/common/restricted_token.c b/src/common/restricted_token.c index dcc88a75c59d8..9058c5ad252ea 100644 --- a/src/common/restricted_token.c +++ b/src/common/restricted_token.c @@ -171,7 +171,7 @@ get_restricted_token(void) cmdline = pg_strdup(GetCommandLine()); - putenv("PG_RESTRICT_EXEC=1"); + setenv("PG_RESTRICT_EXEC", "1", 1); if ((restrictedToken = CreateRestrictedProcess(cmdline, &pi)) == 0) { diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index de8f838e536d2..ddaa9e8e18215 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -473,6 +473,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SECURITY_PAM_APPL_H +/* Define to 1 if you have the `setenv' function. */ +#undef HAVE_SETENV + /* Define to 1 if you have the `setproctitle' function. */ #undef HAVE_SETPROCTITLE diff --git a/src/include/port.h b/src/include/port.h index 5dfb00b07cc4f..c631185c8bbb2 100644 --- a/src/include/port.h +++ b/src/include/port.h @@ -447,8 +447,12 @@ extern size_t strnlen(const char *str, size_t maxlen); extern long random(void); #endif +#ifndef HAVE_SETENV +extern int setenv(const char *name, const char *value, int overwrite); +#endif + #ifndef HAVE_UNSETENV -extern void unsetenv(const char *name); +extern int unsetenv(const char *name); #endif #ifndef HAVE_SRANDOM diff --git a/src/include/port/win32_port.h b/src/include/port/win32_port.h index 59c7f35e3dfab..2ffe056a0fefd 100644 --- a/src/include/port/win32_port.h +++ b/src/include/port/win32_port.h @@ -490,7 +490,12 @@ extern void _dosmaperr(unsigned long); /* in port/win32env.c */ extern int pgwin32_putenv(const char *); -extern void pgwin32_unsetenv(const char *); +extern int pgwin32_setenv(const char *name, const char *value, int overwrite); +extern int pgwin32_unsetenv(const char *name); + +#define putenv(x) pgwin32_putenv(x) +#define setenv(x,y,z) pgwin32_setenv(x,y,z) +#define unsetenv(x) pgwin32_unsetenv(x) /* in port/win32security.c */ extern int pgwin32_is_service(void); @@ -499,9 +504,6 @@ extern int pgwin32_is_admin(void); /* Windows security token manipulation (in src/common/exec.c) */ extern BOOL AddUserToTokenDacl(HANDLE hToken); -#define putenv(x) pgwin32_putenv(x) -#define unsetenv(x) pgwin32_unsetenv(x) - /* Things that exist in MinGW headers, but need to be added to MSVC */ #ifdef _MSC_VER diff --git a/src/interfaces/ecpg/test/pg_regress_ecpg.c b/src/interfaces/ecpg/test/pg_regress_ecpg.c index 6e1d25b1f4a3c..49b2d8141f5e2 100644 --- a/src/interfaces/ecpg/test/pg_regress_ecpg.c +++ b/src/interfaces/ecpg/test/pg_regress_ecpg.c @@ -147,8 +147,9 @@ ecpg_start_test(const char *testname, outfile_stdout, outfile_stderr); - appnameenv = psprintf("PGAPPNAME=ecpg/%s", testname_dash.data); - putenv(appnameenv); + appnameenv = psprintf("ecpg/%s", testname_dash.data); + setenv("PGAPPNAME", appnameenv, 1); + free(appnameenv); pid = spawn_process(cmd); @@ -160,7 +161,6 @@ ecpg_start_test(const char *testname, } unsetenv("PGAPPNAME"); - free(appnameenv); free(testname_dash.data); diff --git a/src/port/setenv.c b/src/port/setenv.c new file mode 100644 index 0000000000000..d8a5647fb02fc --- /dev/null +++ b/src/port/setenv.c @@ -0,0 +1,48 @@ +/*------------------------------------------------------------------------- + * + * setenv.c + * setenv() emulation for machines without it + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/port/setenv.c + * + *------------------------------------------------------------------------- + */ + +#include "c.h" + + +int +setenv(const char *name, const char *value, int overwrite) +{ + char *envstr; + + /* Error conditions, per POSIX */ + if (name == NULL || name[0] == '\0' || strchr(name, '=') != NULL || + value == NULL) + { + errno = EINVAL; + return -1; + } + + /* No work if variable exists and we're not to replace it */ + if (overwrite == 0 && getenv(name) != NULL) + return 0; + + /* + * Add or replace the value using putenv(). This will leak memory if the + * same variable is repeatedly redefined, but there's little we can do + * about that when sitting atop putenv(). + */ + envstr = (char *) malloc(strlen(name) + strlen(value) + 2); + if (!envstr) /* not much we can do if no memory */ + return -1; + + sprintf(envstr, "%s=%s", name, value); + + return putenv(envstr); +} diff --git a/src/port/unsetenv.c b/src/port/unsetenv.c index f2028c2f8346f..a5f19f8db39ab 100644 --- a/src/port/unsetenv.c +++ b/src/port/unsetenv.c @@ -16,13 +16,20 @@ #include "c.h" -void +int unsetenv(const char *name) { char *envstr; + /* Error conditions, per POSIX */ + if (name == NULL || name[0] == '\0' || strchr(name, '=') != NULL) + { + errno = EINVAL; + return -1; + } + if (getenv(name) == NULL) - return; /* no work */ + return 0; /* no work */ /* * The technique embodied here works if libc follows the Single Unix Spec @@ -40,11 +47,12 @@ unsetenv(const char *name) envstr = (char *) malloc(strlen(name) + 2); if (!envstr) /* not much we can do if no memory */ - return; + return -1; /* Override the existing setting by forcibly defining the var */ sprintf(envstr, "%s=", name); - putenv(envstr); + if (putenv(envstr)) + return -1; /* Now we can clobber the variable definition this way: */ strcpy(envstr, "="); @@ -53,5 +61,5 @@ unsetenv(const char *name) * This last putenv cleans up if we have multiple zero-length names as a * result of unsetting multiple things. */ - putenv(envstr); + return putenv(envstr); } diff --git a/src/port/win32env.c b/src/port/win32env.c index 177488cc67ea9..f5bed67297481 100644 --- a/src/port/win32env.c +++ b/src/port/win32env.c @@ -1,8 +1,10 @@ /*------------------------------------------------------------------------- * * win32env.c - * putenv() and unsetenv() for win32, which update both process environment - * and caches in (potentially multiple) C run-time library (CRT) versions. + * putenv(), setenv(), and unsetenv() for win32. + * + * These functions update both the process environment and caches in + * (potentially multiple) C run-time library (CRT) versions. * * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California @@ -16,6 +18,11 @@ #include "c.h" + +/* + * Note that unlike POSIX putenv(), this doesn't use the passed-in string + * as permanent storage. + */ int pgwin32_putenv(const char *envval) { @@ -64,7 +71,7 @@ pgwin32_putenv(const char *envval) } *cp = '\0'; cp++; - if (strlen(cp)) + if (*cp) { /* * Only call SetEnvironmentVariable() when we are adding a variable, @@ -110,16 +117,47 @@ pgwin32_putenv(const char *envval) return _putenv(envval); } -void +int +pgwin32_setenv(const char *name, const char *value, int overwrite) +{ + int res; + char *envstr; + + /* Error conditions, per POSIX */ + if (name == NULL || name[0] == '\0' || strchr(name, '=') != NULL || + value == NULL) + { + errno = EINVAL; + return -1; + } + + /* No work if variable exists and we're not to replace it */ + if (overwrite == 0 && getenv(name) != NULL) + return 0; + + envstr = (char *) malloc(strlen(name) + strlen(value) + 2); + if (!envstr) /* not much we can do if no memory */ + return -1; + + sprintf(envstr, "%s=%s", name, value); + + res = pgwin32_putenv(envstr); + free(envstr); + return res; +} + +int pgwin32_unsetenv(const char *name) { + int res; char *envbuf; envbuf = (char *) malloc(strlen(name) + 2); if (!envbuf) - return; + return -1; sprintf(envbuf, "%s=", name); - pgwin32_putenv(envbuf); + res = pgwin32_putenv(envbuf); free(envbuf); + return res; } diff --git a/src/test/isolation/isolation_main.c b/src/test/isolation/isolation_main.c index 50916b00dca2c..a6a64e7ec527d 100644 --- a/src/test/isolation/isolation_main.c +++ b/src/test/isolation/isolation_main.c @@ -98,8 +98,9 @@ isolation_start_test(const char *testname, exit(2); } - appnameenv = psprintf("PGAPPNAME=isolation/%s", testname); - putenv(appnameenv); + appnameenv = psprintf("isolation/%s", testname); + setenv("PGAPPNAME", appnameenv, 1); + free(appnameenv); pid = spawn_process(psql_cmd); @@ -111,7 +112,6 @@ isolation_start_test(const char *testname, } unsetenv("PGAPPNAME"); - free(appnameenv); return pid; } diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c index 23d7d0beb2e8d..866bc8c4704dd 100644 --- a/src/test/regress/pg_regress.c +++ b/src/test/regress/pg_regress.c @@ -724,18 +724,6 @@ get_expectfile(const char *testname, const char *file) return NULL; } -/* - * Handy subroutine for setting an environment variable "var" to "val" - */ -static void -doputenv(const char *var, const char *val) -{ - char *s; - - s = psprintf("%s=%s", var, val); - putenv(s); -} - /* * Prepare environment variables for running regression tests */ @@ -746,7 +734,7 @@ initialize_environment(void) * Set default application_name. (The test_function may choose to * override this, but if it doesn't, we have something useful in place.) */ - putenv("PGAPPNAME=pg_regress"); + setenv("PGAPPNAME", "pg_regress", 1); if (nolocale) { @@ -769,7 +757,7 @@ initialize_environment(void) * variables unset; see PostmasterMain(). */ #if defined(WIN32) || defined(__CYGWIN__) || defined(__darwin__) - putenv("LANG=C"); + setenv("LANG", "C", 1); #endif } @@ -781,21 +769,21 @@ initialize_environment(void) */ unsetenv("LANGUAGE"); unsetenv("LC_ALL"); - putenv("LC_MESSAGES=C"); + setenv("LC_MESSAGES", "C", 1); /* * Set encoding as requested */ if (encoding) - doputenv("PGCLIENTENCODING", encoding); + setenv("PGCLIENTENCODING", encoding, 1); else unsetenv("PGCLIENTENCODING"); /* * Set timezone and datestyle for datetime-related tests */ - putenv("PGTZ=PST8PDT"); - putenv("PGDATESTYLE=Postgres, MDY"); + setenv("PGTZ", "PST8PDT", 1); + setenv("PGDATESTYLE", "Postgres, MDY", 1); /* * Likewise set intervalstyle to ensure consistent results. This is a bit @@ -809,9 +797,10 @@ initialize_environment(void) if (!old_pgoptions) old_pgoptions = ""; - new_pgoptions = psprintf("PGOPTIONS=%s %s", + new_pgoptions = psprintf("%s %s", old_pgoptions, my_pgoptions); - putenv(new_pgoptions); + setenv("PGOPTIONS", new_pgoptions, 1); + free(new_pgoptions); } if (temp_instance) @@ -832,17 +821,17 @@ initialize_environment(void) unsetenv("PGDATA"); #ifdef HAVE_UNIX_SOCKETS if (hostname != NULL) - doputenv("PGHOST", hostname); + setenv("PGHOST", hostname, 1); else { sockdir = getenv("PG_REGRESS_SOCK_DIR"); if (!sockdir) sockdir = make_temp_sockdir(); - doputenv("PGHOST", sockdir); + setenv("PGHOST", sockdir, 1); } #else Assert(hostname != NULL); - doputenv("PGHOST", hostname); + setenv("PGHOST", hostname, 1); #endif unsetenv("PGHOSTADDR"); if (port != -1) @@ -850,7 +839,7 @@ initialize_environment(void) char s[16]; sprintf(s, "%d", port); - doputenv("PGPORT", s); + setenv("PGPORT", s, 1); } } else @@ -864,7 +853,7 @@ initialize_environment(void) */ if (hostname != NULL) { - doputenv("PGHOST", hostname); + setenv("PGHOST", hostname, 1); unsetenv("PGHOSTADDR"); } if (port != -1) @@ -872,10 +861,10 @@ initialize_environment(void) char s[16]; sprintf(s, "%d", port); - doputenv("PGPORT", s); + setenv("PGPORT", s, 1); } if (user != NULL) - doputenv("PGUSER", user); + setenv("PGUSER", user, 1); /* * However, we *don't* honor PGDATABASE, since we certainly don't wish @@ -2431,7 +2420,7 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc fprintf(stderr, _("port %d apparently in use, trying %d\n"), port, port + 1); port++; sprintf(s, "%d", port); - doputenv("PGPORT", s); + setenv("PGPORT", s, 1); } else break; diff --git a/src/test/regress/pg_regress_main.c b/src/test/regress/pg_regress_main.c index dd8ad245648cd..5e503efa4a7b3 100644 --- a/src/test/regress/pg_regress_main.c +++ b/src/test/regress/pg_regress_main.c @@ -91,8 +91,9 @@ psql_start_test(const char *testname, exit(2); } - appnameenv = psprintf("PGAPPNAME=pg_regress/%s", testname); - putenv(appnameenv); + appnameenv = psprintf("pg_regress/%s", testname); + setenv("PGAPPNAME", appnameenv, 1); + free(appnameenv); pid = spawn_process(psql_cmd); @@ -104,7 +105,6 @@ psql_start_test(const char *testname, } unsetenv("PGAPPNAME"); - free(appnameenv); return pid; } diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c index 09bc42a8c0f2f..b8b3af4e956eb 100644 --- a/src/test/regress/regress.c +++ b/src/test/regress/regress.c @@ -624,22 +624,18 @@ make_tuple_indirect(PG_FUNCTION_ARGS) PG_RETURN_POINTER(newtup->t_data); } -PG_FUNCTION_INFO_V1(regress_putenv); +PG_FUNCTION_INFO_V1(regress_setenv); Datum -regress_putenv(PG_FUNCTION_ARGS) +regress_setenv(PG_FUNCTION_ARGS) { - MemoryContext oldcontext; - char *envbuf; + char *envvar = text_to_cstring(PG_GETARG_TEXT_PP(0)); + char *envval = text_to_cstring(PG_GETARG_TEXT_PP(1)); if (!superuser()) elog(ERROR, "must be superuser to change environment variables"); - oldcontext = MemoryContextSwitchTo(TopMemoryContext); - envbuf = text_to_cstring((text *) PG_GETARG_POINTER(0)); - MemoryContextSwitchTo(oldcontext); - - if (putenv(envbuf) != 0) + if (setenv(envvar, envval, 1) != 0) elog(ERROR, "could not set environment variable: %m"); PG_RETURN_VOID(); diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm index 22d6abd36748f..95d4e826b1d05 100644 --- a/src/tools/msvc/Solution.pm +++ b/src/tools/msvc/Solution.pm @@ -348,6 +348,7 @@ sub GenerateFiles HAVE_RL_FILENAME_QUOTING_FUNCTION => undef, HAVE_RL_RESET_SCREEN_SIZE => undef, HAVE_SECURITY_PAM_APPL_H => undef, + HAVE_SETENV => undef, HAVE_SETPROCTITLE => undef, HAVE_SETPROCTITLE_FAST => undef, HAVE_SETSID => undef, From 16d531a30a120d13cc3b460fba6570024a1fcfa8 Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Wed, 30 Dec 2020 21:11:31 +0300 Subject: [PATCH 015/240] Refactor multirange_in() This commit preserves the logic of multirange_in() but makes it more clear what's going on. Also, this commit fixes the compiler warning spotted by the buildfarm. Reported-by: Tom Lane Discussion: https://postgr.es/m/2246043.1609290699%40sss.pgh.pa.us --- src/backend/utils/adt/multirangetypes.c | 46 ++++++++++++++++--------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/src/backend/utils/adt/multirangetypes.c b/src/backend/utils/adt/multirangetypes.c index 2d4cee92bcced..63867958cfd96 100644 --- a/src/backend/utils/adt/multirangetypes.c +++ b/src/backend/utils/adt/multirangetypes.c @@ -128,9 +128,9 @@ multirange_in(PG_FUNCTION_ARGS) MultirangeType *ret; MultirangeParseState parse_state; const char *ptr = input_str; - const char *range_str = NULL; + const char *range_str_begin = NULL; int32 range_str_len; - char *range_str_copy; + char *range_str; cache = get_multirange_io_data(fcinfo, mltrngtypoid, IOFunc_input); rangetyp = cache->typcache->rngtype; @@ -170,7 +170,7 @@ multirange_in(PG_FUNCTION_ARGS) case MULTIRANGE_BEFORE_RANGE: if (ch == '[' || ch == '(') { - range_str = ptr; + range_str_begin = ptr; parse_state = MULTIRANGE_IN_RANGE; } else if (ch == '}' && ranges_seen == 0) @@ -191,14 +191,10 @@ multirange_in(PG_FUNCTION_ARGS) errdetail("Expected range start."))); break; case MULTIRANGE_IN_RANGE: - if (ch == '"') - parse_state = MULTIRANGE_IN_RANGE_QUOTED; - else if (ch == '\\') - parse_state = MULTIRANGE_IN_RANGE_ESCAPED; - else if (ch == ']' || ch == ')') + if (ch == ']' || ch == ')') { - range_str_len = ptr - range_str + 1; - range_str_copy = pnstrdup(range_str, range_str_len); + range_str_len = ptr - range_str_begin + 1; + range_str = pnstrdup(range_str_begin, range_str_len); if (range_capacity == range_count) { range_capacity *= 2; @@ -207,7 +203,7 @@ multirange_in(PG_FUNCTION_ARGS) } ranges_seen++; range = DatumGetRangeTypeP(InputFunctionCall(&cache->typioproc, - range_str_copy, + range_str, cache->typioparam, typmod)); if (!RangeIsEmpty(range)) @@ -215,10 +211,22 @@ multirange_in(PG_FUNCTION_ARGS) parse_state = MULTIRANGE_AFTER_RANGE; } else - /* include it in range_str */ ; + { + if (ch == '"') + parse_state = MULTIRANGE_IN_RANGE_QUOTED; + else if (ch == '\\') + parse_state = MULTIRANGE_IN_RANGE_ESCAPED; + /* + * We will include this character into range_str once we + * find the end of the range value. + */ + } break; case MULTIRANGE_IN_RANGE_ESCAPED: - /* include it in range_str */ + /* + * We will include this character into range_str once we find + * the end of the range value. + */ parse_state = MULTIRANGE_IN_RANGE; break; case MULTIRANGE_IN_RANGE_QUOTED: @@ -232,8 +240,11 @@ multirange_in(PG_FUNCTION_ARGS) parse_state = MULTIRANGE_IN_RANGE; else if (ch == '\\') parse_state = MULTIRANGE_IN_RANGE_QUOTED_ESCAPED; - else - /* include it in range_str */ ; + + /* + * We will include this character into range_str once we + * find the end of the range value. + */ break; case MULTIRANGE_AFTER_RANGE: if (ch == ',') @@ -248,7 +259,10 @@ multirange_in(PG_FUNCTION_ARGS) errdetail("Expected comma or end of multirange."))); break; case MULTIRANGE_IN_RANGE_QUOTED_ESCAPED: - /* include it in range_str */ + /* + * We will include this character into range_str once we find + * the end of the range value. + */ parse_state = MULTIRANGE_IN_RANGE_QUOTED; break; default: From 091866724cb3ee7251fa56e2517248c4b7796ca8 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 30 Dec 2020 14:15:41 -0500 Subject: [PATCH 016/240] More fixups for pg_upgrade cross-version tests. Commit 7ca37fb04 removed regress_putenv from the regress.so library, so reloading a SQL function dependent on that would not work. Fix similarly to 52202bb39. Per buildfarm. --- src/bin/pg_upgrade/test.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bin/pg_upgrade/test.sh b/src/bin/pg_upgrade/test.sh index 8b13ec8692d04..47c96df5c303c 100644 --- a/src/bin/pg_upgrade/test.sh +++ b/src/bin/pg_upgrade/test.sh @@ -178,6 +178,8 @@ if "$MAKE" -C "$oldsrc" installcheck-parallel; then fix_sql="$fix_sql DROP FUNCTION IF EXISTS public.oldstyle_length(integer, text); -- last in 9.6 + DROP FUNCTION IF EXISTS + public.putenv(text); -- last in v13 DROP OPERATOR IF EXISTS -- last in v13 public.#@# (pg_catalog.int8, NONE), public.#%# (pg_catalog.int8, NONE), From 319f4d54e82d15d4a0c3f4cc1328c40dba024b5c Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 30 Dec 2020 17:48:43 -0500 Subject: [PATCH 017/240] Doc: spell out comparison behaviors for the date/time types. The behavior of cross-type comparisons among date/time data types was not really explained anywhere. You could probably infer it if you recognized the applicability of comments elsewhere about datatype conversions, but it seems worthy of explicit documentation. Per bug #16797 from Dana Burd. Discussion: https://postgr.es/m/16797-f264b0b980b53b8b@postgresql.org --- doc/src/sgml/func.sgml | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 5021ac1ca96a4..1e044b51a1684 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -8190,14 +8190,30 @@ SELECT regexp_match('abc01234xyz', '(?:(.*?)(\d+)(.*)){1,1}'); linkend="datatype-datetime"/>. + + In addition, the usual comparison operators shown in + are available for the + date/time types. Dates and timestamps (with or without time zone) are + all comparable, while times (with or without time zone) and intervals + can only be compared to other values of the same data type. When + comparing a timestamp without time zone to a timestamp with time zone, + the former value is assumed to be given in the time zone specified by + the configuration parameter, and is + rotated to UTC for comparison to the latter value (which is already + in UTC internally). Similarly, a date value is assumed to represent + midnight in the TimeZone zone when comparing it + to a timestamp. + + All the functions and operators described below that take time or timestamp inputs actually come in two variants: one that takes time with time zone or timestamp with time zone, and one that takes time without time zone or timestamp without time zone. For brevity, these variants are not shown separately. Also, the + and * operators come in commutative pairs (for - example both date + integer and integer + date); we show only one of each - such pair. + example both date + integer + and integer + date); we show + only one of each such pair.
From 422881744997417944634a7f84af7a66a608de9a Mon Sep 17 00:00:00 2001 From: Peter Geoghegan Date: Wed, 30 Dec 2020 16:29:05 -0800 Subject: [PATCH 018/240] Fix index deletion latestRemovedXid bug. The logic for determining the latest removed XID for the purposes of generating recovery conflicts in REDO routines was subtly broken. It failed to follow links from HOT chains, and so failed to consider all relevant heap tuple headers in some cases. To fix, expand the loop that deals with LP_REDIRECT line pointers to also deal with HOT chains. The new version of the loop is loosely based on a similar loop from heap_prune_chain(). The impact of this bug is probably quite limited, since the horizon code necessarily deals with heap tuples that are pointed to by LP_DEAD-set index tuples. The process of setting LP_DEAD index tuples (e.g. within the kill_prior_tuple mechanism) is highly correlated with opportunistic pruning of pointed-to heap tuples. Plus the question of generating a recovery conflict usually comes up some time after index tuple LP_DEAD bits were initially set, unlike heap pruning, where a latestRemovedXid is generated at the point of the pruning operation (heap pruning has no deferred "would-be page split" style processing that produces conflicts lazily). Only backpatch to Postgres 12, the first version where this logic runs during original execution (following commit 558a9165e08). The index latestRemovedXid mechanism has had the same bug since it first appeared over 10 years ago (in commit a760893d), but backpatching to all supported versions now seems like a bad idea on balance. Running the new improved code during recovery seems risky, especially given the lack of complaints from the field. Author: Peter Geoghegan Discussion: https://postgr.es/m/CAH2-Wz=Eib393+HHcERK_9MtgNS7Ew1HY=RDC_g6GL46zM5C6Q@mail.gmail.com Backpatch: 12- --- src/backend/access/heap/heapam.c | 118 ++++++++++++++++++------------ src/backend/storage/ipc/standby.c | 16 ++-- 2 files changed, 79 insertions(+), 55 deletions(-) diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index a9583f3103688..da27903cb4c92 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -6997,10 +6997,13 @@ heap_compute_xid_horizon_for_tuples(Relation rel, ItemPointerData *tids, int nitems) { + /* Initial assumption is that earlier pruning took care of conflict */ TransactionId latestRemovedXid = InvalidTransactionId; - BlockNumber hblkno; + BlockNumber blkno = InvalidBlockNumber; Buffer buf = InvalidBuffer; - Page hpage; + Page page = NULL; + OffsetNumber maxoff = InvalidOffsetNumber; + TransactionId priorXmax; #ifdef USE_PREFETCH XidHorizonPrefetchState prefetch_state; int prefetch_distance; @@ -7040,20 +7043,17 @@ heap_compute_xid_horizon_for_tuples(Relation rel, #endif /* Iterate over all tids, and check their horizon */ - hblkno = InvalidBlockNumber; - hpage = NULL; for (int i = 0; i < nitems; i++) { ItemPointer htid = &tids[i]; - ItemId hitemid; - OffsetNumber hoffnum; + OffsetNumber offnum; /* * Read heap buffer, but avoid refetching if it's the same block as * required for the last tid. */ - if (hblkno == InvalidBlockNumber || - ItemPointerGetBlockNumber(htid) != hblkno) + if (blkno == InvalidBlockNumber || + ItemPointerGetBlockNumber(htid) != blkno) { /* release old buffer */ if (BufferIsValid(buf)) @@ -7062,9 +7062,9 @@ heap_compute_xid_horizon_for_tuples(Relation rel, ReleaseBuffer(buf); } - hblkno = ItemPointerGetBlockNumber(htid); + blkno = ItemPointerGetBlockNumber(htid); - buf = ReadBuffer(rel, hblkno); + buf = ReadBuffer(rel, blkno); #ifdef USE_PREFETCH @@ -7075,49 +7075,79 @@ heap_compute_xid_horizon_for_tuples(Relation rel, xid_horizon_prefetch_buffer(rel, &prefetch_state, 1); #endif - hpage = BufferGetPage(buf); + page = BufferGetPage(buf); + maxoff = PageGetMaxOffsetNumber(page); LockBuffer(buf, BUFFER_LOCK_SHARE); } - hoffnum = ItemPointerGetOffsetNumber(htid); - hitemid = PageGetItemId(hpage, hoffnum); - /* - * Follow any redirections until we find something useful. + * Maintain latestRemovedXid value for deletion operation as a whole + * by advancing current value using heap tuple headers. This is + * loosely based on the logic for pruning a HOT chain. */ - while (ItemIdIsRedirected(hitemid)) + offnum = ItemPointerGetOffsetNumber(htid); + priorXmax = InvalidTransactionId; /* cannot check first XMIN */ + for (;;) { - hoffnum = ItemIdGetRedirect(hitemid); - hitemid = PageGetItemId(hpage, hoffnum); - } + ItemId lp; + HeapTupleHeader htup; - /* - * If the heap item has storage, then read the header and use that to - * set latestRemovedXid. - * - * Some LP_DEAD items may not be accessible, so we ignore them. - */ - if (ItemIdHasStorage(hitemid)) - { - HeapTupleHeader htuphdr; + /* Some sanity checks */ + if (offnum < FirstOffsetNumber || offnum > maxoff) + { + Assert(false); + break; + } - htuphdr = (HeapTupleHeader) PageGetItem(hpage, hitemid); + lp = PageGetItemId(page, offnum); + if (ItemIdIsRedirected(lp)) + { + offnum = ItemIdGetRedirect(lp); + continue; + } - HeapTupleHeaderAdvanceLatestRemovedXid(htuphdr, &latestRemovedXid); - } - else if (ItemIdIsDead(hitemid)) - { /* - * Conjecture: if hitemid is dead then it had xids before the xids - * marked on LP_NORMAL items. So we just ignore this item and move - * onto the next, for the purposes of calculating - * latestRemovedXid. + * We'll often encounter LP_DEAD line pointers. No need to do + * anything more with htid when that happens. This is okay + * because the earlier pruning operation that made the line + * pointer LP_DEAD in the first place must have considered the + * tuple header as part of generating its own latestRemovedXid + * value. + * + * Relying on XLOG_HEAP2_CLEANUP_INFO records like this is the + * same strategy that index vacuuming uses in all cases. Index + * VACUUM WAL records don't even have a latestRemovedXid field of + * their own for this reason. */ - } - else - Assert(!ItemIdIsUsed(hitemid)); + if (!ItemIdIsNormal(lp)) + break; + + htup = (HeapTupleHeader) PageGetItem(page, lp); + + /* + * Check the tuple XMIN against prior XMAX, if any + */ + if (TransactionIdIsValid(priorXmax) && + !TransactionIdEquals(HeapTupleHeaderGetXmin(htup), priorXmax)) + break; + HeapTupleHeaderAdvanceLatestRemovedXid(htup, &latestRemovedXid); + + /* + * If the tuple is not HOT-updated, then we are at the end of this + * HOT-chain. No need to visit later tuples from the same update + * chain (they get their own index entries) -- just move on to + * next htid from index AM caller. + */ + if (!HeapTupleHeaderIsHotUpdated(htup)) + break; + + /* Advance to next HOT chain member */ + Assert(ItemPointerGetBlockNumber(&htup->t_ctid) == blkno); + offnum = ItemPointerGetOffsetNumber(&htup->t_ctid); + priorXmax = HeapTupleHeaderGetUpdateXid(htup); + } } if (BufferIsValid(buf)) @@ -7126,14 +7156,6 @@ heap_compute_xid_horizon_for_tuples(Relation rel, ReleaseBuffer(buf); } - /* - * If all heap tuples were LP_DEAD then we will be returning - * InvalidTransactionId here, which avoids conflicts. This matches - * existing logic which assumes that LP_DEAD tuples must already be older - * than the latestRemovedXid on the cleanup record that set them as - * LP_DEAD, hence must already have generated a conflict. - */ - return latestRemovedXid; } diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c index 92d9027776c65..da8e83a52582f 100644 --- a/src/backend/storage/ipc/standby.c +++ b/src/backend/storage/ipc/standby.c @@ -305,13 +305,15 @@ ResolveRecoveryConflictWithSnapshot(TransactionId latestRemovedXid, RelFileNode VirtualTransactionId *backends; /* - * If we get passed InvalidTransactionId then we are a little surprised, - * but it is theoretically possible in normal running. It also happens - * when replaying already applied WAL records after a standby crash or - * restart, or when replaying an XLOG_HEAP2_VISIBLE record that marks as - * frozen a page which was already all-visible. If latestRemovedXid is - * invalid then there is no conflict. That rule applies across all record - * types that suffer from this conflict. + * If we get passed InvalidTransactionId then we do nothing (no conflict). + * + * This can happen when replaying already-applied WAL records after a + * standby crash or restart, or when replaying an XLOG_HEAP2_VISIBLE + * record that marks as frozen a page which was already all-visible. It's + * also quite common with records generated during index deletion + * (original execution of the deletion can reason that a recovery conflict + * which is sufficient for the deletion operation must take place before + * replay of the deletion record itself). */ if (!TransactionIdIsValid(latestRemovedXid)) return; From 32d6287d2eef6b6a4dde07e0513f3e4f321792ad Mon Sep 17 00:00:00 2001 From: Peter Geoghegan Date: Wed, 30 Dec 2020 17:21:42 -0800 Subject: [PATCH 019/240] Get heap page max offset with buffer lock held. On further reflection it seems better to call PageGetMaxOffsetNumber() after acquiring a buffer lock on the page. This shouldn't really matter, but doing it this way is cleaner. Follow-up to commit 42288174. Backpatch: 12-, just like commit 42288174 --- src/backend/access/heap/heapam.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index da27903cb4c92..26c2006f23c0b 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -7075,10 +7075,10 @@ heap_compute_xid_horizon_for_tuples(Relation rel, xid_horizon_prefetch_buffer(rel, &prefetch_state, 1); #endif + LockBuffer(buf, BUFFER_LOCK_SHARE); + page = BufferGetPage(buf); maxoff = PageGetMaxOffsetNumber(page); - - LockBuffer(buf, BUFFER_LOCK_SHARE); } /* From 4d3f03f42227bb351c2021a9ccea2fff9c023cfc Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 1 Jan 2021 15:51:09 -0500 Subject: [PATCH 020/240] Doc: improve explanation of EXTRACT(EPOCH) for timestamp without tz. Try to be clearer about what computation is actually happening here. Per bug #16797 from Dana Burd. Discussion: https://postgr.es/m/16797-f264b0b980b53b8b@postgresql.org --- doc/src/sgml/func.sgml | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 1e044b51a1684..02a37658ad9a2 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -9354,9 +9354,11 @@ SELECT EXTRACT(DOY FROM TIMESTAMP '2001-02-16 20:38:40'); For timestamp with time zone values, the - number of seconds since 1970-01-01 00:00:00 UTC (can be negative); + number of seconds since 1970-01-01 00:00:00 UTC (negative for + timestamps before that); for date and timestamp values, the - number of seconds since 1970-01-01 00:00:00 local time; + nominal number of seconds since 1970-01-01 00:00:00, + without regard to timezone or daylight-savings rules; for interval values, the total number of seconds in the interval @@ -9365,18 +9367,29 @@ SELECT EXTRACT(DOY FROM TIMESTAMP '2001-02-16 20:38:40'); SELECT EXTRACT(EPOCH FROM TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40.12-08'); Result: 982384720.12 +SELECT EXTRACT(EPOCH FROM TIMESTAMP '2001-02-16 20:38:40.12'); +Result: 982355920.12 + SELECT EXTRACT(EPOCH FROM INTERVAL '5 days 3 hours'); Result: 442800 - You can convert an epoch value back to a time stamp + You can convert an epoch value back to a timestamp with time zone with to_timestamp: SELECT to_timestamp(982384720.12); Result: 2001-02-17 04:38:40.12+00 + + + Beware that applying to_timestamp to an epoch + extracted from a date or timestamp value + could produce a misleading result: the result will effectively + assume that the original value had been given in UTC, which might + not be the case. + From ca3b37487be333a1d241dab1bbdd17a211a88f43 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Sat, 2 Jan 2021 13:06:25 -0500 Subject: [PATCH 021/240] Update copyright for 2021 Backpatch-through: 9.5 --- COPYRIGHT | 2 +- config/thread_test.c | 2 +- configure | 4 ++-- configure.ac | 2 +- contrib/adminpack/adminpack.c | 2 +- contrib/amcheck/verify_heapam.c | 2 +- contrib/amcheck/verify_nbtree.c | 2 +- contrib/auth_delay/auth_delay.c | 2 +- contrib/auto_explain/auto_explain.c | 2 +- contrib/bloom/blcost.c | 2 +- contrib/bloom/blinsert.c | 2 +- contrib/bloom/bloom.h | 2 +- contrib/bloom/blscan.c | 2 +- contrib/bloom/blutils.c | 2 +- contrib/bloom/blvacuum.c | 2 +- contrib/bloom/blvalidate.c | 2 +- contrib/dblink/dblink.c | 2 +- contrib/dict_int/dict_int.c | 2 +- contrib/dict_xsyn/dict_xsyn.c | 2 +- contrib/file_fdw/file_fdw.c | 2 +- contrib/fuzzystrmatch/fuzzystrmatch.c | 2 +- contrib/hstore/hstore_subs.c | 2 +- contrib/intarray/_int_selfuncs.c | 2 +- contrib/isn/isn.c | 2 +- contrib/isn/isn.h | 2 +- contrib/old_snapshot/time_mapping.c | 2 +- contrib/pageinspect/brinfuncs.c | 2 +- contrib/pageinspect/fsmfuncs.c | 2 +- contrib/pageinspect/ginfuncs.c | 2 +- contrib/pageinspect/hashfuncs.c | 2 +- contrib/pageinspect/heapfuncs.c | 2 +- contrib/pageinspect/pageinspect.h | 2 +- contrib/pageinspect/rawpage.c | 2 +- contrib/passwordcheck/passwordcheck.c | 2 +- contrib/pg_prewarm/autoprewarm.c | 2 +- contrib/pg_prewarm/pg_prewarm.c | 2 +- contrib/pg_stat_statements/pg_stat_statements.c | 2 +- contrib/pg_surgery/heap_surgery.c | 2 +- contrib/pg_surgery/pg_surgery--1.0.sql | 2 +- contrib/pg_trgm/trgm_regexp.c | 2 +- contrib/pg_visibility/pg_visibility.c | 2 +- contrib/pgcrypto/imath.c | 2 +- contrib/pgstattuple/pgstatapprox.c | 2 +- contrib/postgres_fdw/connection.c | 2 +- contrib/postgres_fdw/deparse.c | 2 +- contrib/postgres_fdw/option.c | 2 +- contrib/postgres_fdw/postgres_fdw.c | 2 +- contrib/postgres_fdw/postgres_fdw.h | 2 +- contrib/postgres_fdw/shippable.c | 2 +- contrib/sepgsql/database.c | 2 +- contrib/sepgsql/dml.c | 2 +- contrib/sepgsql/hooks.c | 2 +- contrib/sepgsql/label.c | 2 +- contrib/sepgsql/launcher | 2 +- contrib/sepgsql/proc.c | 2 +- contrib/sepgsql/relation.c | 2 +- contrib/sepgsql/schema.c | 2 +- contrib/sepgsql/selinux.c | 2 +- contrib/sepgsql/sepgsql.h | 2 +- contrib/sepgsql/uavc.c | 2 +- contrib/tablefunc/tablefunc.c | 2 +- contrib/tablefunc/tablefunc.h | 2 +- contrib/tcn/tcn.c | 2 +- contrib/test_decoding/test_decoding.c | 2 +- contrib/tsm_system_rows/tsm_system_rows.c | 2 +- contrib/tsm_system_time/tsm_system_time.c | 2 +- contrib/unaccent/unaccent.c | 2 +- contrib/uuid-ossp/uuid-ossp.c | 2 +- contrib/vacuumlo/vacuumlo.c | 2 +- doc/src/sgml/generate-errcodes-table.pl | 2 +- doc/src/sgml/generate-keywords-table.pl | 2 +- doc/src/sgml/legal.sgml | 6 +++--- doc/src/sgml/lobj.sgml | 2 +- src/backend/Makefile | 2 +- src/backend/access/brin/brin.c | 2 +- src/backend/access/brin/brin_inclusion.c | 2 +- src/backend/access/brin/brin_minmax.c | 2 +- src/backend/access/brin/brin_pageops.c | 2 +- src/backend/access/brin/brin_revmap.c | 2 +- src/backend/access/brin/brin_tuple.c | 2 +- src/backend/access/brin/brin_validate.c | 2 +- src/backend/access/brin/brin_xlog.c | 2 +- src/backend/access/common/attmap.c | 2 +- src/backend/access/common/bufmask.c | 2 +- src/backend/access/common/detoast.c | 2 +- src/backend/access/common/heaptuple.c | 2 +- src/backend/access/common/indextuple.c | 2 +- src/backend/access/common/printsimple.c | 2 +- src/backend/access/common/printtup.c | 2 +- src/backend/access/common/relation.c | 2 +- src/backend/access/common/reloptions.c | 2 +- src/backend/access/common/scankey.c | 2 +- src/backend/access/common/session.c | 2 +- src/backend/access/common/syncscan.c | 2 +- src/backend/access/common/toast_internals.c | 2 +- src/backend/access/common/tupconvert.c | 2 +- src/backend/access/common/tupdesc.c | 2 +- src/backend/access/gin/ginarrayproc.c | 2 +- src/backend/access/gin/ginbtree.c | 2 +- src/backend/access/gin/ginbulk.c | 2 +- src/backend/access/gin/gindatapage.c | 2 +- src/backend/access/gin/ginentrypage.c | 2 +- src/backend/access/gin/ginfast.c | 2 +- src/backend/access/gin/ginget.c | 2 +- src/backend/access/gin/gininsert.c | 2 +- src/backend/access/gin/ginlogic.c | 2 +- src/backend/access/gin/ginpostinglist.c | 2 +- src/backend/access/gin/ginscan.c | 2 +- src/backend/access/gin/ginutil.c | 2 +- src/backend/access/gin/ginvacuum.c | 2 +- src/backend/access/gin/ginvalidate.c | 2 +- src/backend/access/gin/ginxlog.c | 2 +- src/backend/access/gist/gist.c | 2 +- src/backend/access/gist/gistbuild.c | 2 +- src/backend/access/gist/gistbuildbuffers.c | 2 +- src/backend/access/gist/gistget.c | 2 +- src/backend/access/gist/gistproc.c | 2 +- src/backend/access/gist/gistscan.c | 2 +- src/backend/access/gist/gistsplit.c | 2 +- src/backend/access/gist/gistutil.c | 2 +- src/backend/access/gist/gistvacuum.c | 2 +- src/backend/access/gist/gistvalidate.c | 2 +- src/backend/access/gist/gistxlog.c | 2 +- src/backend/access/hash/hash.c | 2 +- src/backend/access/hash/hash_xlog.c | 2 +- src/backend/access/hash/hashfunc.c | 2 +- src/backend/access/hash/hashinsert.c | 2 +- src/backend/access/hash/hashovfl.c | 2 +- src/backend/access/hash/hashpage.c | 2 +- src/backend/access/hash/hashsearch.c | 2 +- src/backend/access/hash/hashsort.c | 2 +- src/backend/access/hash/hashutil.c | 2 +- src/backend/access/hash/hashvalidate.c | 2 +- src/backend/access/heap/heapam.c | 2 +- src/backend/access/heap/heapam_handler.c | 2 +- src/backend/access/heap/heapam_visibility.c | 2 +- src/backend/access/heap/heaptoast.c | 2 +- src/backend/access/heap/hio.c | 2 +- src/backend/access/heap/pruneheap.c | 2 +- src/backend/access/heap/rewriteheap.c | 2 +- src/backend/access/heap/vacuumlazy.c | 2 +- src/backend/access/heap/visibilitymap.c | 2 +- src/backend/access/index/amapi.c | 2 +- src/backend/access/index/amvalidate.c | 2 +- src/backend/access/index/genam.c | 2 +- src/backend/access/index/indexam.c | 2 +- src/backend/access/nbtree/nbtcompare.c | 2 +- src/backend/access/nbtree/nbtdedup.c | 2 +- src/backend/access/nbtree/nbtinsert.c | 2 +- src/backend/access/nbtree/nbtpage.c | 2 +- src/backend/access/nbtree/nbtree.c | 2 +- src/backend/access/nbtree/nbtsearch.c | 2 +- src/backend/access/nbtree/nbtsort.c | 2 +- src/backend/access/nbtree/nbtsplitloc.c | 2 +- src/backend/access/nbtree/nbtutils.c | 2 +- src/backend/access/nbtree/nbtvalidate.c | 2 +- src/backend/access/nbtree/nbtxlog.c | 2 +- src/backend/access/rmgrdesc/brindesc.c | 2 +- src/backend/access/rmgrdesc/clogdesc.c | 2 +- src/backend/access/rmgrdesc/committsdesc.c | 2 +- src/backend/access/rmgrdesc/dbasedesc.c | 2 +- src/backend/access/rmgrdesc/genericdesc.c | 2 +- src/backend/access/rmgrdesc/gindesc.c | 2 +- src/backend/access/rmgrdesc/gistdesc.c | 2 +- src/backend/access/rmgrdesc/hashdesc.c | 2 +- src/backend/access/rmgrdesc/heapdesc.c | 2 +- src/backend/access/rmgrdesc/logicalmsgdesc.c | 2 +- src/backend/access/rmgrdesc/mxactdesc.c | 2 +- src/backend/access/rmgrdesc/nbtdesc.c | 2 +- src/backend/access/rmgrdesc/relmapdesc.c | 2 +- src/backend/access/rmgrdesc/replorigindesc.c | 2 +- src/backend/access/rmgrdesc/seqdesc.c | 2 +- src/backend/access/rmgrdesc/smgrdesc.c | 2 +- src/backend/access/rmgrdesc/spgdesc.c | 2 +- src/backend/access/rmgrdesc/standbydesc.c | 2 +- src/backend/access/rmgrdesc/tblspcdesc.c | 2 +- src/backend/access/rmgrdesc/xactdesc.c | 2 +- src/backend/access/rmgrdesc/xlogdesc.c | 2 +- src/backend/access/spgist/spgdoinsert.c | 2 +- src/backend/access/spgist/spginsert.c | 2 +- src/backend/access/spgist/spgkdtreeproc.c | 2 +- src/backend/access/spgist/spgproc.c | 2 +- src/backend/access/spgist/spgquadtreeproc.c | 2 +- src/backend/access/spgist/spgscan.c | 2 +- src/backend/access/spgist/spgtextproc.c | 2 +- src/backend/access/spgist/spgutils.c | 2 +- src/backend/access/spgist/spgvacuum.c | 2 +- src/backend/access/spgist/spgvalidate.c | 2 +- src/backend/access/spgist/spgxlog.c | 2 +- src/backend/access/table/table.c | 2 +- src/backend/access/table/tableam.c | 2 +- src/backend/access/table/tableamapi.c | 2 +- src/backend/access/table/toast_helper.c | 2 +- src/backend/access/tablesample/bernoulli.c | 2 +- src/backend/access/tablesample/system.c | 2 +- src/backend/access/tablesample/tablesample.c | 2 +- src/backend/access/transam/clog.c | 2 +- src/backend/access/transam/commit_ts.c | 2 +- src/backend/access/transam/generic_xlog.c | 2 +- src/backend/access/transam/multixact.c | 2 +- src/backend/access/transam/parallel.c | 2 +- src/backend/access/transam/slru.c | 2 +- src/backend/access/transam/subtrans.c | 2 +- src/backend/access/transam/timeline.c | 2 +- src/backend/access/transam/transam.c | 2 +- src/backend/access/transam/twophase.c | 2 +- src/backend/access/transam/twophase_rmgr.c | 2 +- src/backend/access/transam/varsup.c | 2 +- src/backend/access/transam/xact.c | 2 +- src/backend/access/transam/xlog.c | 2 +- src/backend/access/transam/xlogarchive.c | 2 +- src/backend/access/transam/xlogfuncs.c | 2 +- src/backend/access/transam/xloginsert.c | 2 +- src/backend/access/transam/xlogreader.c | 2 +- src/backend/access/transam/xlogutils.c | 2 +- src/backend/bootstrap/bootparse.y | 2 +- src/backend/bootstrap/bootscanner.l | 2 +- src/backend/bootstrap/bootstrap.c | 2 +- src/backend/catalog/Catalog.pm | 2 +- src/backend/catalog/Makefile | 2 +- src/backend/catalog/aclchk.c | 2 +- src/backend/catalog/catalog.c | 2 +- src/backend/catalog/dependency.c | 2 +- src/backend/catalog/genbki.pl | 6 +++--- src/backend/catalog/heap.c | 2 +- src/backend/catalog/index.c | 2 +- src/backend/catalog/indexing.c | 2 +- src/backend/catalog/information_schema.sql | 2 +- src/backend/catalog/namespace.c | 2 +- src/backend/catalog/objectaccess.c | 2 +- src/backend/catalog/objectaddress.c | 2 +- src/backend/catalog/partition.c | 2 +- src/backend/catalog/pg_aggregate.c | 2 +- src/backend/catalog/pg_cast.c | 2 +- src/backend/catalog/pg_collation.c | 2 +- src/backend/catalog/pg_constraint.c | 2 +- src/backend/catalog/pg_conversion.c | 2 +- src/backend/catalog/pg_db_role_setting.c | 2 +- src/backend/catalog/pg_depend.c | 2 +- src/backend/catalog/pg_enum.c | 2 +- src/backend/catalog/pg_inherits.c | 2 +- src/backend/catalog/pg_largeobject.c | 2 +- src/backend/catalog/pg_namespace.c | 2 +- src/backend/catalog/pg_operator.c | 2 +- src/backend/catalog/pg_proc.c | 2 +- src/backend/catalog/pg_publication.c | 2 +- src/backend/catalog/pg_range.c | 2 +- src/backend/catalog/pg_shdepend.c | 2 +- src/backend/catalog/pg_subscription.c | 2 +- src/backend/catalog/pg_type.c | 2 +- src/backend/catalog/storage.c | 2 +- src/backend/catalog/system_views.sql | 2 +- src/backend/catalog/toasting.c | 2 +- src/backend/commands/aggregatecmds.c | 2 +- src/backend/commands/alter.c | 2 +- src/backend/commands/amcmds.c | 2 +- src/backend/commands/analyze.c | 2 +- src/backend/commands/async.c | 2 +- src/backend/commands/cluster.c | 2 +- src/backend/commands/collationcmds.c | 2 +- src/backend/commands/comment.c | 2 +- src/backend/commands/constraint.c | 2 +- src/backend/commands/conversioncmds.c | 2 +- src/backend/commands/copy.c | 2 +- src/backend/commands/copyfrom.c | 2 +- src/backend/commands/copyfromparse.c | 2 +- src/backend/commands/copyto.c | 2 +- src/backend/commands/createas.c | 2 +- src/backend/commands/dbcommands.c | 2 +- src/backend/commands/define.c | 2 +- src/backend/commands/discard.c | 2 +- src/backend/commands/dropcmds.c | 2 +- src/backend/commands/event_trigger.c | 2 +- src/backend/commands/explain.c | 2 +- src/backend/commands/extension.c | 2 +- src/backend/commands/foreigncmds.c | 2 +- src/backend/commands/functioncmds.c | 2 +- src/backend/commands/indexcmds.c | 2 +- src/backend/commands/lockcmds.c | 2 +- src/backend/commands/matview.c | 2 +- src/backend/commands/opclasscmds.c | 2 +- src/backend/commands/operatorcmds.c | 2 +- src/backend/commands/policy.c | 2 +- src/backend/commands/portalcmds.c | 2 +- src/backend/commands/prepare.c | 2 +- src/backend/commands/proclang.c | 2 +- src/backend/commands/publicationcmds.c | 2 +- src/backend/commands/schemacmds.c | 2 +- src/backend/commands/seclabel.c | 2 +- src/backend/commands/sequence.c | 2 +- src/backend/commands/statscmds.c | 2 +- src/backend/commands/subscriptioncmds.c | 2 +- src/backend/commands/tablecmds.c | 2 +- src/backend/commands/tablespace.c | 2 +- src/backend/commands/trigger.c | 2 +- src/backend/commands/tsearchcmds.c | 2 +- src/backend/commands/typecmds.c | 2 +- src/backend/commands/user.c | 2 +- src/backend/commands/vacuum.c | 2 +- src/backend/commands/variable.c | 2 +- src/backend/commands/view.c | 2 +- src/backend/executor/execAmi.c | 2 +- src/backend/executor/execCurrent.c | 2 +- src/backend/executor/execExpr.c | 2 +- src/backend/executor/execExprInterp.c | 2 +- src/backend/executor/execGrouping.c | 2 +- src/backend/executor/execIndexing.c | 2 +- src/backend/executor/execJunk.c | 2 +- src/backend/executor/execMain.c | 2 +- src/backend/executor/execParallel.c | 2 +- src/backend/executor/execPartition.c | 2 +- src/backend/executor/execProcnode.c | 2 +- src/backend/executor/execReplication.c | 2 +- src/backend/executor/execSRF.c | 2 +- src/backend/executor/execScan.c | 2 +- src/backend/executor/execTuples.c | 2 +- src/backend/executor/execUtils.c | 2 +- src/backend/executor/functions.c | 2 +- src/backend/executor/instrument.c | 2 +- src/backend/executor/nodeAgg.c | 2 +- src/backend/executor/nodeAppend.c | 2 +- src/backend/executor/nodeBitmapAnd.c | 2 +- src/backend/executor/nodeBitmapHeapscan.c | 2 +- src/backend/executor/nodeBitmapIndexscan.c | 2 +- src/backend/executor/nodeBitmapOr.c | 2 +- src/backend/executor/nodeCtescan.c | 2 +- src/backend/executor/nodeCustom.c | 2 +- src/backend/executor/nodeForeignscan.c | 2 +- src/backend/executor/nodeFunctionscan.c | 2 +- src/backend/executor/nodeGather.c | 2 +- src/backend/executor/nodeGatherMerge.c | 2 +- src/backend/executor/nodeGroup.c | 2 +- src/backend/executor/nodeHash.c | 2 +- src/backend/executor/nodeHashjoin.c | 2 +- src/backend/executor/nodeIncrementalSort.c | 2 +- src/backend/executor/nodeIndexonlyscan.c | 2 +- src/backend/executor/nodeIndexscan.c | 2 +- src/backend/executor/nodeLimit.c | 2 +- src/backend/executor/nodeLockRows.c | 2 +- src/backend/executor/nodeMaterial.c | 2 +- src/backend/executor/nodeMergeAppend.c | 2 +- src/backend/executor/nodeMergejoin.c | 2 +- src/backend/executor/nodeModifyTable.c | 2 +- src/backend/executor/nodeNamedtuplestorescan.c | 2 +- src/backend/executor/nodeNestloop.c | 2 +- src/backend/executor/nodeProjectSet.c | 2 +- src/backend/executor/nodeRecursiveunion.c | 2 +- src/backend/executor/nodeResult.c | 2 +- src/backend/executor/nodeSamplescan.c | 2 +- src/backend/executor/nodeSeqscan.c | 2 +- src/backend/executor/nodeSetOp.c | 2 +- src/backend/executor/nodeSort.c | 2 +- src/backend/executor/nodeSubplan.c | 2 +- src/backend/executor/nodeSubqueryscan.c | 2 +- src/backend/executor/nodeTableFuncscan.c | 2 +- src/backend/executor/nodeTidscan.c | 2 +- src/backend/executor/nodeUnique.c | 2 +- src/backend/executor/nodeValuesscan.c | 2 +- src/backend/executor/nodeWindowAgg.c | 2 +- src/backend/executor/nodeWorktablescan.c | 2 +- src/backend/executor/spi.c | 2 +- src/backend/executor/tqueue.c | 2 +- src/backend/executor/tstoreReceiver.c | 2 +- src/backend/foreign/foreign.c | 2 +- src/backend/jit/jit.c | 2 +- src/backend/jit/llvm/llvmjit.c | 2 +- src/backend/jit/llvm/llvmjit_deform.c | 2 +- src/backend/jit/llvm/llvmjit_error.cpp | 2 +- src/backend/jit/llvm/llvmjit_expr.c | 2 +- src/backend/jit/llvm/llvmjit_inline.cpp | 2 +- src/backend/jit/llvm/llvmjit_types.c | 2 +- src/backend/jit/llvm/llvmjit_wrap.cpp | 2 +- src/backend/lib/binaryheap.c | 2 +- src/backend/lib/bipartite_match.c | 2 +- src/backend/lib/bloomfilter.c | 2 +- src/backend/lib/dshash.c | 2 +- src/backend/lib/hyperloglog.c | 2 +- src/backend/lib/ilist.c | 2 +- src/backend/lib/integerset.c | 2 +- src/backend/lib/knapsack.c | 2 +- src/backend/lib/pairingheap.c | 2 +- src/backend/lib/rbtree.c | 2 +- src/backend/libpq/auth-scram.c | 2 +- src/backend/libpq/auth.c | 2 +- src/backend/libpq/be-fsstubs.c | 2 +- src/backend/libpq/be-gssapi-common.c | 2 +- src/backend/libpq/be-secure-common.c | 2 +- src/backend/libpq/be-secure-gssapi.c | 2 +- src/backend/libpq/be-secure-openssl.c | 2 +- src/backend/libpq/be-secure.c | 2 +- src/backend/libpq/crypt.c | 2 +- src/backend/libpq/hba.c | 2 +- src/backend/libpq/ifaddr.c | 2 +- src/backend/libpq/pqcomm.c | 2 +- src/backend/libpq/pqformat.c | 2 +- src/backend/libpq/pqmq.c | 2 +- src/backend/libpq/pqsignal.c | 2 +- src/backend/main/main.c | 2 +- src/backend/nodes/bitmapset.c | 2 +- src/backend/nodes/copyfuncs.c | 2 +- src/backend/nodes/equalfuncs.c | 2 +- src/backend/nodes/extensible.c | 2 +- src/backend/nodes/list.c | 2 +- src/backend/nodes/makefuncs.c | 2 +- src/backend/nodes/nodeFuncs.c | 2 +- src/backend/nodes/nodes.c | 2 +- src/backend/nodes/outfuncs.c | 2 +- src/backend/nodes/params.c | 2 +- src/backend/nodes/print.c | 2 +- src/backend/nodes/read.c | 2 +- src/backend/nodes/readfuncs.c | 2 +- src/backend/nodes/tidbitmap.c | 2 +- src/backend/nodes/value.c | 2 +- src/backend/optimizer/geqo/geqo_copy.c | 2 +- src/backend/optimizer/geqo/geqo_eval.c | 2 +- src/backend/optimizer/geqo/geqo_main.c | 2 +- src/backend/optimizer/geqo/geqo_misc.c | 2 +- src/backend/optimizer/geqo/geqo_pool.c | 2 +- src/backend/optimizer/geqo/geqo_random.c | 2 +- src/backend/optimizer/geqo/geqo_selection.c | 2 +- src/backend/optimizer/path/allpaths.c | 2 +- src/backend/optimizer/path/clausesel.c | 2 +- src/backend/optimizer/path/costsize.c | 2 +- src/backend/optimizer/path/equivclass.c | 2 +- src/backend/optimizer/path/indxpath.c | 2 +- src/backend/optimizer/path/joinpath.c | 2 +- src/backend/optimizer/path/joinrels.c | 2 +- src/backend/optimizer/path/pathkeys.c | 2 +- src/backend/optimizer/path/tidpath.c | 2 +- src/backend/optimizer/plan/analyzejoins.c | 2 +- src/backend/optimizer/plan/createplan.c | 2 +- src/backend/optimizer/plan/initsplan.c | 2 +- src/backend/optimizer/plan/planagg.c | 2 +- src/backend/optimizer/plan/planmain.c | 2 +- src/backend/optimizer/plan/planner.c | 2 +- src/backend/optimizer/plan/setrefs.c | 2 +- src/backend/optimizer/plan/subselect.c | 2 +- src/backend/optimizer/prep/prepagg.c | 2 +- src/backend/optimizer/prep/prepjointree.c | 2 +- src/backend/optimizer/prep/prepqual.c | 2 +- src/backend/optimizer/prep/preptlist.c | 2 +- src/backend/optimizer/prep/prepunion.c | 2 +- src/backend/optimizer/util/appendinfo.c | 2 +- src/backend/optimizer/util/clauses.c | 2 +- src/backend/optimizer/util/inherit.c | 2 +- src/backend/optimizer/util/joininfo.c | 2 +- src/backend/optimizer/util/orclauses.c | 2 +- src/backend/optimizer/util/paramassign.c | 2 +- src/backend/optimizer/util/pathnode.c | 2 +- src/backend/optimizer/util/placeholder.c | 2 +- src/backend/optimizer/util/plancat.c | 2 +- src/backend/optimizer/util/predtest.c | 2 +- src/backend/optimizer/util/relnode.c | 2 +- src/backend/optimizer/util/restrictinfo.c | 2 +- src/backend/optimizer/util/tlist.c | 2 +- src/backend/optimizer/util/var.c | 2 +- src/backend/parser/analyze.c | 2 +- src/backend/parser/check_keywords.pl | 2 +- src/backend/parser/gram.y | 2 +- src/backend/parser/parse_agg.c | 2 +- src/backend/parser/parse_clause.c | 2 +- src/backend/parser/parse_coerce.c | 2 +- src/backend/parser/parse_collate.c | 2 +- src/backend/parser/parse_cte.c | 2 +- src/backend/parser/parse_enr.c | 2 +- src/backend/parser/parse_expr.c | 2 +- src/backend/parser/parse_func.c | 2 +- src/backend/parser/parse_node.c | 2 +- src/backend/parser/parse_oper.c | 2 +- src/backend/parser/parse_param.c | 2 +- src/backend/parser/parse_relation.c | 2 +- src/backend/parser/parse_target.c | 2 +- src/backend/parser/parse_type.c | 2 +- src/backend/parser/parse_utilcmd.c | 2 +- src/backend/parser/parser.c | 2 +- src/backend/parser/scan.l | 2 +- src/backend/parser/scansup.c | 2 +- src/backend/partitioning/partbounds.c | 2 +- src/backend/partitioning/partdesc.c | 2 +- src/backend/partitioning/partprune.c | 2 +- src/backend/port/atomics.c | 2 +- src/backend/port/posix_sema.c | 2 +- src/backend/port/sysv_sema.c | 2 +- src/backend/port/sysv_shmem.c | 2 +- src/backend/port/tas/sunstudio_sparc.s | 2 +- src/backend/port/tas/sunstudio_x86.s | 2 +- src/backend/port/win32/crashdump.c | 2 +- src/backend/port/win32/signal.c | 2 +- src/backend/port/win32/socket.c | 2 +- src/backend/port/win32/timer.c | 2 +- src/backend/port/win32_sema.c | 2 +- src/backend/port/win32_shmem.c | 2 +- src/backend/postmaster/autovacuum.c | 2 +- src/backend/postmaster/bgworker.c | 2 +- src/backend/postmaster/bgwriter.c | 2 +- src/backend/postmaster/checkpointer.c | 2 +- src/backend/postmaster/fork_process.c | 2 +- src/backend/postmaster/interrupt.c | 2 +- src/backend/postmaster/pgarch.c | 2 +- src/backend/postmaster/pgstat.c | 2 +- src/backend/postmaster/postmaster.c | 2 +- src/backend/postmaster/startup.c | 2 +- src/backend/postmaster/syslogger.c | 2 +- src/backend/postmaster/walwriter.c | 2 +- src/backend/regex/regc_pg_locale.c | 2 +- src/backend/regex/regexport.c | 2 +- src/backend/regex/regprefix.c | 2 +- src/backend/replication/backup_manifest.c | 2 +- src/backend/replication/basebackup.c | 2 +- .../replication/libpqwalreceiver/libpqwalreceiver.c | 2 +- src/backend/replication/logical/decode.c | 2 +- src/backend/replication/logical/launcher.c | 2 +- src/backend/replication/logical/logical.c | 2 +- src/backend/replication/logical/logicalfuncs.c | 2 +- src/backend/replication/logical/message.c | 2 +- src/backend/replication/logical/origin.c | 2 +- src/backend/replication/logical/proto.c | 2 +- src/backend/replication/logical/relation.c | 2 +- src/backend/replication/logical/reorderbuffer.c | 2 +- src/backend/replication/logical/snapbuild.c | 2 +- src/backend/replication/logical/tablesync.c | 2 +- src/backend/replication/logical/worker.c | 2 +- src/backend/replication/pgoutput/pgoutput.c | 2 +- src/backend/replication/repl_gram.y | 2 +- src/backend/replication/repl_scanner.l | 2 +- src/backend/replication/slot.c | 2 +- src/backend/replication/slotfuncs.c | 2 +- src/backend/replication/syncrep.c | 2 +- src/backend/replication/syncrep_gram.y | 2 +- src/backend/replication/syncrep_scanner.l | 2 +- src/backend/replication/walreceiver.c | 2 +- src/backend/replication/walreceiverfuncs.c | 2 +- src/backend/replication/walsender.c | 2 +- src/backend/rewrite/rewriteDefine.c | 2 +- src/backend/rewrite/rewriteHandler.c | 2 +- src/backend/rewrite/rewriteManip.c | 2 +- src/backend/rewrite/rewriteRemove.c | 2 +- src/backend/rewrite/rewriteSupport.c | 2 +- src/backend/rewrite/rowsecurity.c | 2 +- src/backend/snowball/dict_snowball.c | 2 +- src/backend/snowball/snowball.sql.in | 2 +- src/backend/snowball/snowball_func.sql.in | 2 +- src/backend/statistics/dependencies.c | 2 +- src/backend/statistics/extended_stats.c | 2 +- src/backend/statistics/mcv.c | 2 +- src/backend/statistics/mvdistinct.c | 2 +- src/backend/storage/buffer/buf_init.c | 2 +- src/backend/storage/buffer/buf_table.c | 2 +- src/backend/storage/buffer/bufmgr.c | 2 +- src/backend/storage/buffer/freelist.c | 2 +- src/backend/storage/buffer/localbuf.c | 2 +- src/backend/storage/file/buffile.c | 2 +- src/backend/storage/file/copydir.c | 2 +- src/backend/storage/file/fd.c | 2 +- src/backend/storage/file/reinit.c | 2 +- src/backend/storage/file/sharedfileset.c | 2 +- src/backend/storage/freespace/freespace.c | 2 +- src/backend/storage/freespace/fsmpage.c | 2 +- src/backend/storage/freespace/indexfsm.c | 2 +- src/backend/storage/ipc/barrier.c | 2 +- src/backend/storage/ipc/dsm.c | 2 +- src/backend/storage/ipc/dsm_impl.c | 2 +- src/backend/storage/ipc/ipc.c | 2 +- src/backend/storage/ipc/ipci.c | 2 +- src/backend/storage/ipc/latch.c | 2 +- src/backend/storage/ipc/pmsignal.c | 2 +- src/backend/storage/ipc/procarray.c | 2 +- src/backend/storage/ipc/procsignal.c | 2 +- src/backend/storage/ipc/shm_mq.c | 2 +- src/backend/storage/ipc/shm_toc.c | 2 +- src/backend/storage/ipc/shmem.c | 2 +- src/backend/storage/ipc/shmqueue.c | 2 +- src/backend/storage/ipc/signalfuncs.c | 2 +- src/backend/storage/ipc/sinval.c | 2 +- src/backend/storage/ipc/sinvaladt.c | 2 +- src/backend/storage/ipc/standby.c | 2 +- src/backend/storage/large_object/inv_api.c | 2 +- src/backend/storage/lmgr/condition_variable.c | 2 +- src/backend/storage/lmgr/deadlock.c | 2 +- src/backend/storage/lmgr/generate-lwlocknames.pl | 2 +- src/backend/storage/lmgr/lmgr.c | 2 +- src/backend/storage/lmgr/lock.c | 2 +- src/backend/storage/lmgr/lwlock.c | 2 +- src/backend/storage/lmgr/predicate.c | 2 +- src/backend/storage/lmgr/proc.c | 2 +- src/backend/storage/lmgr/s_lock.c | 2 +- src/backend/storage/lmgr/spin.c | 2 +- src/backend/storage/page/bufpage.c | 2 +- src/backend/storage/page/checksum.c | 2 +- src/backend/storage/page/itemptr.c | 2 +- src/backend/storage/smgr/md.c | 2 +- src/backend/storage/smgr/smgr.c | 2 +- src/backend/storage/sync/sync.c | 2 +- src/backend/tcop/cmdtag.c | 2 +- src/backend/tcop/dest.c | 2 +- src/backend/tcop/fastpath.c | 2 +- src/backend/tcop/postgres.c | 2 +- src/backend/tcop/pquery.c | 2 +- src/backend/tcop/utility.c | 2 +- src/backend/tsearch/Makefile | 2 +- src/backend/tsearch/dict.c | 2 +- src/backend/tsearch/dict_ispell.c | 2 +- src/backend/tsearch/dict_simple.c | 2 +- src/backend/tsearch/dict_synonym.c | 2 +- src/backend/tsearch/dict_thesaurus.c | 2 +- src/backend/tsearch/regis.c | 2 +- src/backend/tsearch/spell.c | 2 +- src/backend/tsearch/to_tsany.c | 2 +- src/backend/tsearch/ts_locale.c | 2 +- src/backend/tsearch/ts_parse.c | 2 +- src/backend/tsearch/ts_selfuncs.c | 2 +- src/backend/tsearch/ts_typanalyze.c | 2 +- src/backend/tsearch/ts_utils.c | 2 +- src/backend/tsearch/wparser.c | 2 +- src/backend/tsearch/wparser_def.c | 2 +- src/backend/utils/Gen_dummy_probes.pl | 2 +- src/backend/utils/Gen_dummy_probes.sed | 2 +- src/backend/utils/Gen_fmgrtab.pl | 8 ++++---- src/backend/utils/Makefile | 2 +- src/backend/utils/adt/acl.c | 2 +- src/backend/utils/adt/amutils.c | 2 +- src/backend/utils/adt/array_expanded.c | 2 +- src/backend/utils/adt/array_selfuncs.c | 2 +- src/backend/utils/adt/array_typanalyze.c | 2 +- src/backend/utils/adt/array_userfuncs.c | 2 +- src/backend/utils/adt/arrayfuncs.c | 2 +- src/backend/utils/adt/arraysubs.c | 2 +- src/backend/utils/adt/arrayutils.c | 2 +- src/backend/utils/adt/ascii.c | 2 +- src/backend/utils/adt/bool.c | 2 +- src/backend/utils/adt/char.c | 2 +- src/backend/utils/adt/cryptohashfuncs.c | 2 +- src/backend/utils/adt/date.c | 2 +- src/backend/utils/adt/datetime.c | 2 +- src/backend/utils/adt/datum.c | 2 +- src/backend/utils/adt/dbsize.c | 2 +- src/backend/utils/adt/domains.c | 2 +- src/backend/utils/adt/encode.c | 2 +- src/backend/utils/adt/enum.c | 2 +- src/backend/utils/adt/expandeddatum.c | 2 +- src/backend/utils/adt/expandedrecord.c | 2 +- src/backend/utils/adt/float.c | 2 +- src/backend/utils/adt/format_type.c | 2 +- src/backend/utils/adt/formatting.c | 2 +- src/backend/utils/adt/genfile.c | 2 +- src/backend/utils/adt/geo_ops.c | 2 +- src/backend/utils/adt/geo_selfuncs.c | 2 +- src/backend/utils/adt/geo_spgist.c | 2 +- src/backend/utils/adt/int.c | 2 +- src/backend/utils/adt/int8.c | 2 +- src/backend/utils/adt/json.c | 2 +- src/backend/utils/adt/jsonb.c | 2 +- src/backend/utils/adt/jsonb_gin.c | 2 +- src/backend/utils/adt/jsonb_op.c | 2 +- src/backend/utils/adt/jsonb_util.c | 2 +- src/backend/utils/adt/jsonfuncs.c | 2 +- src/backend/utils/adt/jsonpath.c | 2 +- src/backend/utils/adt/jsonpath_exec.c | 2 +- src/backend/utils/adt/jsonpath_gram.y | 2 +- src/backend/utils/adt/jsonpath_scan.l | 2 +- src/backend/utils/adt/levenshtein.c | 2 +- src/backend/utils/adt/like.c | 2 +- src/backend/utils/adt/like_match.c | 2 +- src/backend/utils/adt/like_support.c | 2 +- src/backend/utils/adt/lockfuncs.c | 2 +- src/backend/utils/adt/mac.c | 2 +- src/backend/utils/adt/mac8.c | 2 +- src/backend/utils/adt/mcxtfuncs.c | 2 +- src/backend/utils/adt/misc.c | 2 +- src/backend/utils/adt/multirangetypes.c | 2 +- src/backend/utils/adt/multirangetypes_selfuncs.c | 2 +- src/backend/utils/adt/name.c | 2 +- src/backend/utils/adt/network_gist.c | 2 +- src/backend/utils/adt/network_selfuncs.c | 2 +- src/backend/utils/adt/network_spgist.c | 2 +- src/backend/utils/adt/numeric.c | 2 +- src/backend/utils/adt/numutils.c | 2 +- src/backend/utils/adt/oid.c | 2 +- src/backend/utils/adt/oracle_compat.c | 2 +- src/backend/utils/adt/orderedsetaggs.c | 2 +- src/backend/utils/adt/partitionfuncs.c | 2 +- src/backend/utils/adt/pg_locale.c | 2 +- src/backend/utils/adt/pg_lsn.c | 2 +- src/backend/utils/adt/pg_upgrade_support.c | 2 +- src/backend/utils/adt/pgstatfuncs.c | 2 +- src/backend/utils/adt/pseudotypes.c | 2 +- src/backend/utils/adt/quote.c | 2 +- src/backend/utils/adt/rangetypes.c | 2 +- src/backend/utils/adt/rangetypes_gist.c | 2 +- src/backend/utils/adt/rangetypes_selfuncs.c | 2 +- src/backend/utils/adt/rangetypes_spgist.c | 2 +- src/backend/utils/adt/rangetypes_typanalyze.c | 2 +- src/backend/utils/adt/regexp.c | 2 +- src/backend/utils/adt/regproc.c | 2 +- src/backend/utils/adt/ri_triggers.c | 2 +- src/backend/utils/adt/rowtypes.c | 2 +- src/backend/utils/adt/ruleutils.c | 2 +- src/backend/utils/adt/selfuncs.c | 2 +- src/backend/utils/adt/tid.c | 2 +- src/backend/utils/adt/timestamp.c | 2 +- src/backend/utils/adt/trigfuncs.c | 2 +- src/backend/utils/adt/tsginidx.c | 2 +- src/backend/utils/adt/tsgistidx.c | 2 +- src/backend/utils/adt/tsquery.c | 2 +- src/backend/utils/adt/tsquery_cleanup.c | 2 +- src/backend/utils/adt/tsquery_gist.c | 2 +- src/backend/utils/adt/tsquery_op.c | 2 +- src/backend/utils/adt/tsquery_rewrite.c | 2 +- src/backend/utils/adt/tsquery_util.c | 2 +- src/backend/utils/adt/tsrank.c | 2 +- src/backend/utils/adt/tsvector.c | 2 +- src/backend/utils/adt/tsvector_op.c | 2 +- src/backend/utils/adt/tsvector_parser.c | 2 +- src/backend/utils/adt/uuid.c | 2 +- src/backend/utils/adt/varbit.c | 2 +- src/backend/utils/adt/varchar.c | 2 +- src/backend/utils/adt/varlena.c | 2 +- src/backend/utils/adt/version.c | 2 +- src/backend/utils/adt/windowfuncs.c | 2 +- src/backend/utils/adt/xid.c | 2 +- src/backend/utils/adt/xid8funcs.c | 2 +- src/backend/utils/adt/xml.c | 2 +- src/backend/utils/cache/attoptcache.c | 2 +- src/backend/utils/cache/catcache.c | 2 +- src/backend/utils/cache/evtcache.c | 2 +- src/backend/utils/cache/inval.c | 2 +- src/backend/utils/cache/lsyscache.c | 2 +- src/backend/utils/cache/partcache.c | 2 +- src/backend/utils/cache/plancache.c | 2 +- src/backend/utils/cache/relcache.c | 2 +- src/backend/utils/cache/relfilenodemap.c | 2 +- src/backend/utils/cache/relmapper.c | 2 +- src/backend/utils/cache/spccache.c | 2 +- src/backend/utils/cache/syscache.c | 2 +- src/backend/utils/cache/ts_cache.c | 2 +- src/backend/utils/cache/typcache.c | 2 +- src/backend/utils/errcodes.txt | 2 +- src/backend/utils/error/assert.c | 2 +- src/backend/utils/error/elog.c | 2 +- src/backend/utils/fmgr/dfmgr.c | 2 +- src/backend/utils/fmgr/fmgr.c | 2 +- src/backend/utils/fmgr/funcapi.c | 2 +- src/backend/utils/generate-errcodes.pl | 2 +- src/backend/utils/hash/dynahash.c | 2 +- src/backend/utils/hash/pg_crc.c | 2 +- src/backend/utils/init/globals.c | 2 +- src/backend/utils/init/miscinit.c | 2 +- src/backend/utils/init/postinit.c | 2 +- src/backend/utils/mb/Unicode/Makefile | 2 +- src/backend/utils/mb/Unicode/UCS_to_BIG5.pl | 2 +- src/backend/utils/mb/Unicode/UCS_to_EUC_CN.pl | 2 +- src/backend/utils/mb/Unicode/UCS_to_EUC_JIS_2004.pl | 2 +- src/backend/utils/mb/Unicode/UCS_to_EUC_JP.pl | 2 +- src/backend/utils/mb/Unicode/UCS_to_EUC_KR.pl | 2 +- src/backend/utils/mb/Unicode/UCS_to_EUC_TW.pl | 2 +- src/backend/utils/mb/Unicode/UCS_to_GB18030.pl | 2 +- src/backend/utils/mb/Unicode/UCS_to_JOHAB.pl | 2 +- src/backend/utils/mb/Unicode/UCS_to_SHIFT_JIS_2004.pl | 2 +- src/backend/utils/mb/Unicode/UCS_to_SJIS.pl | 2 +- src/backend/utils/mb/Unicode/UCS_to_UHC.pl | 2 +- src/backend/utils/mb/Unicode/UCS_to_most.pl | 2 +- src/backend/utils/mb/Unicode/convutils.pm | 2 +- src/backend/utils/mb/conv.c | 2 +- src/backend/utils/mb/conversion_procs/Makefile | 2 +- .../conversion_procs/cyrillic_and_mic/cyrillic_and_mic.c | 2 +- .../conversion_procs/euc2004_sjis2004/euc2004_sjis2004.c | 2 +- .../mb/conversion_procs/euc_cn_and_mic/euc_cn_and_mic.c | 2 +- .../mb/conversion_procs/euc_jp_and_sjis/euc_jp_and_sjis.c | 2 +- .../mb/conversion_procs/euc_kr_and_mic/euc_kr_and_mic.c | 2 +- .../mb/conversion_procs/euc_tw_and_big5/euc_tw_and_big5.c | 2 +- .../latin2_and_win1250/latin2_and_win1250.c | 2 +- .../mb/conversion_procs/latin_and_mic/latin_and_mic.c | 2 +- .../mb/conversion_procs/utf8_and_big5/utf8_and_big5.c | 2 +- .../utf8_and_cyrillic/utf8_and_cyrillic.c | 2 +- .../conversion_procs/utf8_and_euc2004/utf8_and_euc2004.c | 2 +- .../mb/conversion_procs/utf8_and_euc_cn/utf8_and_euc_cn.c | 2 +- .../mb/conversion_procs/utf8_and_euc_jp/utf8_and_euc_jp.c | 2 +- .../mb/conversion_procs/utf8_and_euc_kr/utf8_and_euc_kr.c | 2 +- .../mb/conversion_procs/utf8_and_euc_tw/utf8_and_euc_tw.c | 2 +- .../conversion_procs/utf8_and_gb18030/utf8_and_gb18030.c | 2 +- .../utils/mb/conversion_procs/utf8_and_gbk/utf8_and_gbk.c | 2 +- .../conversion_procs/utf8_and_iso8859/utf8_and_iso8859.c | 2 +- .../utf8_and_iso8859_1/utf8_and_iso8859_1.c | 2 +- .../mb/conversion_procs/utf8_and_johab/utf8_and_johab.c | 2 +- .../mb/conversion_procs/utf8_and_sjis/utf8_and_sjis.c | 2 +- .../utf8_and_sjis2004/utf8_and_sjis2004.c | 2 +- .../utils/mb/conversion_procs/utf8_and_uhc/utf8_and_uhc.c | 2 +- .../utils/mb/conversion_procs/utf8_and_win/utf8_and_win.c | 2 +- src/backend/utils/mb/mbutils.c | 2 +- src/backend/utils/mb/stringinfo_mb.c | 2 +- src/backend/utils/misc/guc-file.l | 2 +- src/backend/utils/misc/guc.c | 2 +- src/backend/utils/misc/help_config.c | 2 +- src/backend/utils/misc/pg_config.c | 2 +- src/backend/utils/misc/pg_controldata.c | 2 +- src/backend/utils/misc/pg_rusage.c | 2 +- src/backend/utils/misc/ps_status.c | 2 +- src/backend/utils/misc/queryenvironment.c | 2 +- src/backend/utils/misc/rls.c | 2 +- src/backend/utils/misc/sampling.c | 2 +- src/backend/utils/misc/superuser.c | 2 +- src/backend/utils/misc/timeout.c | 2 +- src/backend/utils/misc/tzparser.c | 2 +- src/backend/utils/mmgr/aset.c | 2 +- src/backend/utils/mmgr/dsa.c | 2 +- src/backend/utils/mmgr/freepage.c | 2 +- src/backend/utils/mmgr/generation.c | 2 +- src/backend/utils/mmgr/mcxt.c | 2 +- src/backend/utils/mmgr/memdebug.c | 2 +- src/backend/utils/mmgr/portalmem.c | 2 +- src/backend/utils/mmgr/slab.c | 2 +- src/backend/utils/probes.d | 2 +- src/backend/utils/resowner/resowner.c | 2 +- src/backend/utils/sort/logtape.c | 2 +- src/backend/utils/sort/sharedtuplestore.c | 2 +- src/backend/utils/sort/sortsupport.c | 2 +- src/backend/utils/sort/tuplesort.c | 2 +- src/backend/utils/sort/tuplestore.c | 2 +- src/backend/utils/time/combocid.c | 2 +- src/backend/utils/time/snapmgr.c | 2 +- src/bin/Makefile | 2 +- src/bin/initdb/Makefile | 2 +- src/bin/initdb/findtimezone.c | 2 +- src/bin/initdb/initdb.c | 2 +- src/bin/pg_basebackup/Makefile | 2 +- src/bin/pg_basebackup/pg_basebackup.c | 2 +- src/bin/pg_basebackup/pg_receivewal.c | 2 +- src/bin/pg_basebackup/pg_recvlogical.c | 2 +- src/bin/pg_basebackup/receivelog.c | 2 +- src/bin/pg_basebackup/receivelog.h | 2 +- src/bin/pg_basebackup/streamutil.c | 2 +- src/bin/pg_basebackup/streamutil.h | 2 +- src/bin/pg_basebackup/walmethods.c | 2 +- src/bin/pg_basebackup/walmethods.h | 2 +- src/bin/pg_checksums/Makefile | 2 +- src/bin/pg_checksums/pg_checksums.c | 2 +- src/bin/pg_config/Makefile | 2 +- src/bin/pg_config/pg_config.c | 2 +- src/bin/pg_controldata/Makefile | 2 +- src/bin/pg_ctl/Makefile | 2 +- src/bin/pg_ctl/pg_ctl.c | 2 +- src/bin/pg_dump/Makefile | 2 +- src/bin/pg_dump/common.c | 2 +- src/bin/pg_dump/compress_io.c | 2 +- src/bin/pg_dump/compress_io.h | 2 +- src/bin/pg_dump/dumputils.c | 2 +- src/bin/pg_dump/dumputils.h | 2 +- src/bin/pg_dump/parallel.c | 2 +- src/bin/pg_dump/parallel.h | 2 +- src/bin/pg_dump/pg_backup_directory.c | 2 +- src/bin/pg_dump/pg_backup_utils.c | 2 +- src/bin/pg_dump/pg_backup_utils.h | 2 +- src/bin/pg_dump/pg_dump.c | 2 +- src/bin/pg_dump/pg_dump.h | 2 +- src/bin/pg_dump/pg_dump_sort.c | 2 +- src/bin/pg_dump/pg_dumpall.c | 2 +- src/bin/pg_resetwal/Makefile | 2 +- src/bin/pg_resetwal/pg_resetwal.c | 2 +- src/bin/pg_rewind/Makefile | 2 +- src/bin/pg_rewind/datapagemap.c | 2 +- src/bin/pg_rewind/datapagemap.h | 2 +- src/bin/pg_rewind/file_ops.c | 2 +- src/bin/pg_rewind/file_ops.h | 2 +- src/bin/pg_rewind/filemap.c | 2 +- src/bin/pg_rewind/filemap.h | 2 +- src/bin/pg_rewind/libpq_source.c | 2 +- src/bin/pg_rewind/local_source.c | 2 +- src/bin/pg_rewind/parsexlog.c | 2 +- src/bin/pg_rewind/pg_rewind.c | 2 +- src/bin/pg_rewind/pg_rewind.h | 2 +- src/bin/pg_rewind/rewind_source.h | 2 +- src/bin/pg_rewind/timeline.c | 2 +- src/bin/pg_upgrade/check.c | 2 +- src/bin/pg_upgrade/controldata.c | 2 +- src/bin/pg_upgrade/dump.c | 2 +- src/bin/pg_upgrade/exec.c | 2 +- src/bin/pg_upgrade/file.c | 2 +- src/bin/pg_upgrade/function.c | 2 +- src/bin/pg_upgrade/info.c | 2 +- src/bin/pg_upgrade/option.c | 2 +- src/bin/pg_upgrade/parallel.c | 2 +- src/bin/pg_upgrade/pg_upgrade.c | 2 +- src/bin/pg_upgrade/pg_upgrade.h | 2 +- src/bin/pg_upgrade/relfilenode.c | 2 +- src/bin/pg_upgrade/server.c | 2 +- src/bin/pg_upgrade/tablespace.c | 2 +- src/bin/pg_upgrade/test.sh | 2 +- src/bin/pg_upgrade/util.c | 2 +- src/bin/pg_upgrade/version.c | 2 +- src/bin/pg_verifybackup/parse_manifest.c | 2 +- src/bin/pg_verifybackup/parse_manifest.h | 2 +- src/bin/pg_verifybackup/pg_verifybackup.c | 2 +- src/bin/pg_waldump/compat.c | 2 +- src/bin/pg_waldump/pg_waldump.c | 2 +- src/bin/pgbench/exprparse.y | 2 +- src/bin/pgbench/exprscan.l | 2 +- src/bin/pgbench/pgbench.c | 2 +- src/bin/pgbench/pgbench.h | 2 +- src/bin/pgevent/Makefile | 2 +- src/bin/psql/Makefile | 2 +- src/bin/psql/command.c | 2 +- src/bin/psql/command.h | 2 +- src/bin/psql/common.c | 2 +- src/bin/psql/common.h | 2 +- src/bin/psql/copy.c | 2 +- src/bin/psql/copy.h | 2 +- src/bin/psql/create_help.pl | 2 +- src/bin/psql/crosstabview.c | 2 +- src/bin/psql/crosstabview.h | 2 +- src/bin/psql/describe.c | 2 +- src/bin/psql/describe.h | 2 +- src/bin/psql/help.c | 4 ++-- src/bin/psql/help.h | 2 +- src/bin/psql/input.c | 2 +- src/bin/psql/input.h | 2 +- src/bin/psql/large_obj.c | 2 +- src/bin/psql/large_obj.h | 2 +- src/bin/psql/mainloop.c | 2 +- src/bin/psql/mainloop.h | 2 +- src/bin/psql/prompt.c | 2 +- src/bin/psql/prompt.h | 2 +- src/bin/psql/psqlscanslash.h | 2 +- src/bin/psql/psqlscanslash.l | 2 +- src/bin/psql/settings.h | 2 +- src/bin/psql/startup.c | 2 +- src/bin/psql/stringutils.c | 2 +- src/bin/psql/stringutils.h | 2 +- src/bin/psql/tab-complete.c | 2 +- src/bin/psql/tab-complete.h | 2 +- src/bin/psql/variables.c | 2 +- src/bin/psql/variables.h | 2 +- src/bin/scripts/Makefile | 2 +- src/bin/scripts/clusterdb.c | 2 +- src/bin/scripts/common.c | 2 +- src/bin/scripts/common.h | 2 +- src/bin/scripts/createdb.c | 2 +- src/bin/scripts/createuser.c | 2 +- src/bin/scripts/dropdb.c | 2 +- src/bin/scripts/dropuser.c | 2 +- src/bin/scripts/pg_isready.c | 2 +- src/bin/scripts/reindexdb.c | 2 +- src/bin/scripts/scripts_parallel.c | 2 +- src/bin/scripts/scripts_parallel.h | 2 +- src/bin/scripts/vacuumdb.c | 2 +- src/common/archive.c | 2 +- src/common/base64.c | 2 +- src/common/checksum_helper.c | 2 +- src/common/config_info.c | 2 +- src/common/controldata_utils.c | 2 +- src/common/cryptohash.c | 2 +- src/common/cryptohash_openssl.c | 2 +- src/common/d2s.c | 2 +- src/common/d2s_full_table.h | 2 +- src/common/d2s_intrinsics.h | 2 +- src/common/encnames.c | 2 +- src/common/exec.c | 2 +- src/common/f2s.c | 2 +- src/common/fe_memutils.c | 2 +- src/common/file_perm.c | 2 +- src/common/file_utils.c | 2 +- src/common/hashfn.c | 2 +- src/common/hex_decode.c | 2 +- src/common/ip.c | 2 +- src/common/jsonapi.c | 2 +- src/common/keywords.c | 2 +- src/common/kwlookup.c | 2 +- src/common/link-canary.c | 2 +- src/common/logging.c | 2 +- src/common/md5.c | 2 +- src/common/md5_common.c | 2 +- src/common/md5_int.h | 2 +- src/common/pg_get_line.c | 2 +- src/common/pg_lzcompress.c | 2 +- src/common/pgfnames.c | 2 +- src/common/protocol_openssl.c | 2 +- src/common/psprintf.c | 2 +- src/common/relpath.c | 2 +- src/common/restricted_token.c | 2 +- src/common/rmtree.c | 2 +- src/common/ryu_common.h | 2 +- src/common/saslprep.c | 2 +- src/common/scram-common.c | 2 +- src/common/sha2.c | 2 +- src/common/sha2_int.h | 2 +- src/common/sprompt.c | 2 +- src/common/string.c | 2 +- src/common/stringinfo.c | 2 +- src/common/unicode/generate-norm_test_table.pl | 4 ++-- src/common/unicode/generate-unicode_combining_table.pl | 2 +- src/common/unicode/generate-unicode_norm_table.pl | 6 +++--- src/common/unicode/generate-unicode_normprops_table.pl | 2 +- src/common/unicode/norm_test.c | 2 +- src/common/unicode_norm.c | 2 +- src/common/username.c | 2 +- src/common/wait_error.c | 2 +- src/common/wchar.c | 2 +- src/fe_utils/Makefile | 2 +- src/fe_utils/archive.c | 2 +- src/fe_utils/cancel.c | 2 +- src/fe_utils/conditional.c | 2 +- src/fe_utils/mbprint.c | 2 +- src/fe_utils/print.c | 2 +- src/fe_utils/psqlscan.l | 2 +- src/fe_utils/recovery_gen.c | 2 +- src/fe_utils/simple_list.c | 2 +- src/fe_utils/string_utils.c | 2 +- src/include/access/amapi.h | 2 +- src/include/access/amvalidate.h | 2 +- src/include/access/attmap.h | 2 +- src/include/access/attnum.h | 2 +- src/include/access/brin.h | 2 +- src/include/access/brin_internal.h | 2 +- src/include/access/brin_page.h | 2 +- src/include/access/brin_pageops.h | 2 +- src/include/access/brin_revmap.h | 2 +- src/include/access/brin_tuple.h | 2 +- src/include/access/brin_xlog.h | 2 +- src/include/access/bufmask.h | 2 +- src/include/access/clog.h | 2 +- src/include/access/commit_ts.h | 2 +- src/include/access/detoast.h | 2 +- src/include/access/genam.h | 2 +- src/include/access/generic_xlog.h | 2 +- src/include/access/gin.h | 2 +- src/include/access/gin_private.h | 2 +- src/include/access/ginblock.h | 2 +- src/include/access/ginxlog.h | 2 +- src/include/access/gist.h | 2 +- src/include/access/gist_private.h | 2 +- src/include/access/gistscan.h | 2 +- src/include/access/gistxlog.h | 2 +- src/include/access/hash.h | 2 +- src/include/access/hash_xlog.h | 2 +- src/include/access/heapam.h | 2 +- src/include/access/heapam_xlog.h | 2 +- src/include/access/heaptoast.h | 2 +- src/include/access/hio.h | 2 +- src/include/access/htup.h | 2 +- src/include/access/htup_details.h | 2 +- src/include/access/itup.h | 2 +- src/include/access/multixact.h | 2 +- src/include/access/nbtree.h | 2 +- src/include/access/nbtxlog.h | 2 +- src/include/access/parallel.h | 2 +- src/include/access/printsimple.h | 2 +- src/include/access/printtup.h | 2 +- src/include/access/relation.h | 2 +- src/include/access/reloptions.h | 2 +- src/include/access/relscan.h | 2 +- src/include/access/rewriteheap.h | 2 +- src/include/access/rmgrlist.h | 2 +- src/include/access/sdir.h | 2 +- src/include/access/session.h | 2 +- src/include/access/skey.h | 2 +- src/include/access/slru.h | 2 +- src/include/access/spgist.h | 2 +- src/include/access/spgist_private.h | 2 +- src/include/access/spgxlog.h | 2 +- src/include/access/stratnum.h | 2 +- src/include/access/subtrans.h | 2 +- src/include/access/syncscan.h | 2 +- src/include/access/sysattr.h | 2 +- src/include/access/table.h | 2 +- src/include/access/tableam.h | 2 +- src/include/access/timeline.h | 2 +- src/include/access/toast_helper.h | 2 +- src/include/access/toast_internals.h | 2 +- src/include/access/transam.h | 2 +- src/include/access/tsmapi.h | 2 +- src/include/access/tupconvert.h | 2 +- src/include/access/tupdesc.h | 2 +- src/include/access/tupdesc_details.h | 2 +- src/include/access/tupmacs.h | 2 +- src/include/access/twophase.h | 2 +- src/include/access/twophase_rmgr.h | 2 +- src/include/access/valid.h | 2 +- src/include/access/visibilitymap.h | 2 +- src/include/access/xact.h | 2 +- src/include/access/xlog.h | 2 +- src/include/access/xlog_internal.h | 2 +- src/include/access/xlogarchive.h | 2 +- src/include/access/xlogdefs.h | 2 +- src/include/access/xloginsert.h | 2 +- src/include/access/xlogreader.h | 2 +- src/include/access/xlogrecord.h | 2 +- src/include/access/xlogutils.h | 2 +- src/include/bootstrap/bootstrap.h | 2 +- src/include/c.h | 2 +- src/include/catalog/Makefile | 2 +- src/include/catalog/binary_upgrade.h | 2 +- src/include/catalog/catalog.h | 2 +- src/include/catalog/catversion.h | 2 +- src/include/catalog/dependency.h | 2 +- src/include/catalog/duplicate_oids | 2 +- src/include/catalog/genbki.h | 2 +- src/include/catalog/heap.h | 2 +- src/include/catalog/index.h | 2 +- src/include/catalog/indexing.h | 2 +- src/include/catalog/namespace.h | 2 +- src/include/catalog/objectaccess.h | 2 +- src/include/catalog/objectaddress.h | 2 +- src/include/catalog/partition.h | 2 +- src/include/catalog/pg_aggregate.dat | 2 +- src/include/catalog/pg_aggregate.h | 2 +- src/include/catalog/pg_am.dat | 2 +- src/include/catalog/pg_am.h | 2 +- src/include/catalog/pg_amop.dat | 2 +- src/include/catalog/pg_amop.h | 2 +- src/include/catalog/pg_amproc.dat | 2 +- src/include/catalog/pg_amproc.h | 2 +- src/include/catalog/pg_attrdef.h | 2 +- src/include/catalog/pg_attribute.h | 2 +- src/include/catalog/pg_auth_members.h | 2 +- src/include/catalog/pg_authid.dat | 2 +- src/include/catalog/pg_authid.h | 2 +- src/include/catalog/pg_cast.dat | 2 +- src/include/catalog/pg_cast.h | 2 +- src/include/catalog/pg_class.dat | 2 +- src/include/catalog/pg_class.h | 2 +- src/include/catalog/pg_collation.dat | 2 +- src/include/catalog/pg_collation.h | 2 +- src/include/catalog/pg_constraint.h | 2 +- src/include/catalog/pg_control.h | 2 +- src/include/catalog/pg_conversion.dat | 2 +- src/include/catalog/pg_conversion.h | 2 +- src/include/catalog/pg_database.dat | 2 +- src/include/catalog/pg_database.h | 2 +- src/include/catalog/pg_db_role_setting.h | 2 +- src/include/catalog/pg_default_acl.h | 2 +- src/include/catalog/pg_depend.h | 2 +- src/include/catalog/pg_description.h | 2 +- src/include/catalog/pg_enum.h | 2 +- src/include/catalog/pg_event_trigger.h | 2 +- src/include/catalog/pg_extension.h | 2 +- src/include/catalog/pg_foreign_data_wrapper.h | 2 +- src/include/catalog/pg_foreign_server.h | 2 +- src/include/catalog/pg_foreign_table.h | 2 +- src/include/catalog/pg_index.h | 2 +- src/include/catalog/pg_inherits.h | 2 +- src/include/catalog/pg_init_privs.h | 2 +- src/include/catalog/pg_language.dat | 2 +- src/include/catalog/pg_language.h | 2 +- src/include/catalog/pg_largeobject.h | 2 +- src/include/catalog/pg_largeobject_metadata.h | 2 +- src/include/catalog/pg_namespace.dat | 2 +- src/include/catalog/pg_namespace.h | 2 +- src/include/catalog/pg_opclass.dat | 2 +- src/include/catalog/pg_opclass.h | 2 +- src/include/catalog/pg_operator.dat | 2 +- src/include/catalog/pg_operator.h | 2 +- src/include/catalog/pg_opfamily.dat | 2 +- src/include/catalog/pg_opfamily.h | 2 +- src/include/catalog/pg_partitioned_table.h | 2 +- src/include/catalog/pg_policy.h | 2 +- src/include/catalog/pg_proc.dat | 2 +- src/include/catalog/pg_proc.h | 2 +- src/include/catalog/pg_publication.h | 2 +- src/include/catalog/pg_publication_rel.h | 2 +- src/include/catalog/pg_range.dat | 2 +- src/include/catalog/pg_range.h | 2 +- src/include/catalog/pg_replication_origin.h | 2 +- src/include/catalog/pg_rewrite.h | 2 +- src/include/catalog/pg_seclabel.h | 2 +- src/include/catalog/pg_sequence.h | 2 +- src/include/catalog/pg_shdepend.h | 2 +- src/include/catalog/pg_shdescription.h | 2 +- src/include/catalog/pg_shseclabel.h | 2 +- src/include/catalog/pg_statistic.h | 2 +- src/include/catalog/pg_statistic_ext.h | 2 +- src/include/catalog/pg_statistic_ext_data.h | 2 +- src/include/catalog/pg_subscription.h | 2 +- src/include/catalog/pg_subscription_rel.h | 2 +- src/include/catalog/pg_tablespace.dat | 2 +- src/include/catalog/pg_tablespace.h | 2 +- src/include/catalog/pg_transform.h | 2 +- src/include/catalog/pg_trigger.h | 2 +- src/include/catalog/pg_ts_config.dat | 2 +- src/include/catalog/pg_ts_config.h | 2 +- src/include/catalog/pg_ts_config_map.dat | 2 +- src/include/catalog/pg_ts_config_map.h | 2 +- src/include/catalog/pg_ts_dict.dat | 2 +- src/include/catalog/pg_ts_dict.h | 2 +- src/include/catalog/pg_ts_parser.dat | 2 +- src/include/catalog/pg_ts_parser.h | 2 +- src/include/catalog/pg_ts_template.dat | 2 +- src/include/catalog/pg_ts_template.h | 2 +- src/include/catalog/pg_type.dat | 2 +- src/include/catalog/pg_type.h | 2 +- src/include/catalog/pg_user_mapping.h | 2 +- src/include/catalog/reformat_dat_file.pl | 2 +- src/include/catalog/renumber_oids.pl | 2 +- src/include/catalog/storage.h | 2 +- src/include/catalog/storage_xlog.h | 2 +- src/include/catalog/toasting.h | 2 +- src/include/catalog/unused_oids | 2 +- src/include/commands/alter.h | 2 +- src/include/commands/async.h | 2 +- src/include/commands/cluster.h | 2 +- src/include/commands/collationcmds.h | 2 +- src/include/commands/comment.h | 2 +- src/include/commands/conversioncmds.h | 2 +- src/include/commands/copy.h | 2 +- src/include/commands/copyfrom_internal.h | 2 +- src/include/commands/createas.h | 2 +- src/include/commands/dbcommands.h | 2 +- src/include/commands/dbcommands_xlog.h | 2 +- src/include/commands/defrem.h | 2 +- src/include/commands/discard.h | 2 +- src/include/commands/event_trigger.h | 2 +- src/include/commands/explain.h | 2 +- src/include/commands/extension.h | 2 +- src/include/commands/lockcmds.h | 2 +- src/include/commands/matview.h | 2 +- src/include/commands/policy.h | 2 +- src/include/commands/portalcmds.h | 2 +- src/include/commands/prepare.h | 2 +- src/include/commands/proclang.h | 2 +- src/include/commands/progress.h | 2 +- src/include/commands/publicationcmds.h | 2 +- src/include/commands/schemacmds.h | 2 +- src/include/commands/seclabel.h | 2 +- src/include/commands/sequence.h | 2 +- src/include/commands/subscriptioncmds.h | 2 +- src/include/commands/tablecmds.h | 2 +- src/include/commands/tablespace.h | 2 +- src/include/commands/trigger.h | 2 +- src/include/commands/typecmds.h | 2 +- src/include/commands/vacuum.h | 2 +- src/include/commands/variable.h | 2 +- src/include/commands/view.h | 2 +- src/include/common/archive.h | 2 +- src/include/common/base64.h | 2 +- src/include/common/checksum_helper.h | 2 +- src/include/common/config_info.h | 2 +- src/include/common/connect.h | 2 +- src/include/common/controldata_utils.h | 2 +- src/include/common/cryptohash.h | 2 +- src/include/common/fe_memutils.h | 2 +- src/include/common/file_perm.h | 2 +- src/include/common/file_utils.h | 2 +- src/include/common/hashfn.h | 2 +- src/include/common/hex_decode.h | 2 +- src/include/common/int.h | 2 +- src/include/common/int128.h | 2 +- src/include/common/ip.h | 2 +- src/include/common/jsonapi.h | 2 +- src/include/common/keywords.h | 2 +- src/include/common/kwlookup.h | 2 +- src/include/common/link-canary.h | 2 +- src/include/common/logging.h | 2 +- src/include/common/md5.h | 2 +- src/include/common/openssl.h | 2 +- src/include/common/relpath.h | 2 +- src/include/common/restricted_token.h | 2 +- src/include/common/saslprep.h | 2 +- src/include/common/scram-common.h | 2 +- src/include/common/sha2.h | 2 +- src/include/common/shortest_dec.h | 2 +- src/include/common/string.h | 2 +- src/include/common/unicode_norm.h | 2 +- src/include/common/unicode_norm_hashfunc.h | 2 +- src/include/common/unicode_norm_table.h | 2 +- src/include/common/username.h | 2 +- src/include/datatype/timestamp.h | 2 +- src/include/executor/execExpr.h | 2 +- src/include/executor/execParallel.h | 2 +- src/include/executor/execPartition.h | 2 +- src/include/executor/execdebug.h | 2 +- src/include/executor/execdesc.h | 2 +- src/include/executor/executor.h | 2 +- src/include/executor/functions.h | 2 +- src/include/executor/hashjoin.h | 2 +- src/include/executor/instrument.h | 2 +- src/include/executor/nodeAgg.h | 2 +- src/include/executor/nodeAppend.h | 2 +- src/include/executor/nodeBitmapAnd.h | 2 +- src/include/executor/nodeBitmapHeapscan.h | 2 +- src/include/executor/nodeBitmapIndexscan.h | 2 +- src/include/executor/nodeBitmapOr.h | 2 +- src/include/executor/nodeCtescan.h | 2 +- src/include/executor/nodeCustom.h | 2 +- src/include/executor/nodeForeignscan.h | 2 +- src/include/executor/nodeFunctionscan.h | 2 +- src/include/executor/nodeGather.h | 2 +- src/include/executor/nodeGatherMerge.h | 2 +- src/include/executor/nodeGroup.h | 2 +- src/include/executor/nodeHash.h | 2 +- src/include/executor/nodeHashjoin.h | 2 +- src/include/executor/nodeIncrementalSort.h | 2 +- src/include/executor/nodeIndexonlyscan.h | 2 +- src/include/executor/nodeIndexscan.h | 2 +- src/include/executor/nodeLimit.h | 2 +- src/include/executor/nodeLockRows.h | 2 +- src/include/executor/nodeMaterial.h | 2 +- src/include/executor/nodeMergeAppend.h | 2 +- src/include/executor/nodeMergejoin.h | 2 +- src/include/executor/nodeModifyTable.h | 2 +- src/include/executor/nodeNamedtuplestorescan.h | 2 +- src/include/executor/nodeNestloop.h | 2 +- src/include/executor/nodeProjectSet.h | 2 +- src/include/executor/nodeRecursiveunion.h | 2 +- src/include/executor/nodeResult.h | 2 +- src/include/executor/nodeSamplescan.h | 2 +- src/include/executor/nodeSeqscan.h | 2 +- src/include/executor/nodeSetOp.h | 2 +- src/include/executor/nodeSort.h | 2 +- src/include/executor/nodeSubplan.h | 2 +- src/include/executor/nodeSubqueryscan.h | 2 +- src/include/executor/nodeTableFuncscan.h | 2 +- src/include/executor/nodeTidscan.h | 2 +- src/include/executor/nodeUnique.h | 2 +- src/include/executor/nodeValuesscan.h | 2 +- src/include/executor/nodeWindowAgg.h | 2 +- src/include/executor/nodeWorktablescan.h | 2 +- src/include/executor/spi.h | 2 +- src/include/executor/spi_priv.h | 2 +- src/include/executor/tablefunc.h | 2 +- src/include/executor/tqueue.h | 2 +- src/include/executor/tstoreReceiver.h | 2 +- src/include/executor/tuptable.h | 2 +- src/include/fe_utils/archive.h | 2 +- src/include/fe_utils/cancel.h | 2 +- src/include/fe_utils/conditional.h | 2 +- src/include/fe_utils/mbprint.h | 2 +- src/include/fe_utils/print.h | 2 +- src/include/fe_utils/psqlscan.h | 2 +- src/include/fe_utils/psqlscan_int.h | 2 +- src/include/fe_utils/recovery_gen.h | 2 +- src/include/fe_utils/simple_list.h | 2 +- src/include/fe_utils/string_utils.h | 2 +- src/include/fmgr.h | 2 +- src/include/foreign/fdwapi.h | 2 +- src/include/foreign/foreign.h | 2 +- src/include/funcapi.h | 2 +- src/include/getaddrinfo.h | 2 +- src/include/getopt_long.h | 2 +- src/include/jit/jit.h | 2 +- src/include/jit/llvmjit.h | 2 +- src/include/jit/llvmjit_emit.h | 2 +- src/include/lib/binaryheap.h | 2 +- src/include/lib/bipartite_match.h | 2 +- src/include/lib/bloomfilter.h | 2 +- src/include/lib/dshash.h | 2 +- src/include/lib/hyperloglog.h | 2 +- src/include/lib/ilist.h | 2 +- src/include/lib/integerset.h | 2 +- src/include/lib/knapsack.h | 2 +- src/include/lib/pairingheap.h | 2 +- src/include/lib/qunique.h | 2 +- src/include/lib/rbtree.h | 2 +- src/include/lib/stringinfo.h | 2 +- src/include/libpq/auth.h | 2 +- src/include/libpq/be-fsstubs.h | 2 +- src/include/libpq/be-gssapi-common.h | 2 +- src/include/libpq/crypt.h | 2 +- src/include/libpq/ifaddr.h | 2 +- src/include/libpq/libpq-be.h | 2 +- src/include/libpq/libpq-fs.h | 2 +- src/include/libpq/libpq.h | 2 +- src/include/libpq/pqcomm.h | 2 +- src/include/libpq/pqformat.h | 2 +- src/include/libpq/pqmq.h | 2 +- src/include/libpq/pqsignal.h | 2 +- src/include/libpq/scram.h | 2 +- src/include/mb/pg_wchar.h | 2 +- src/include/mb/stringinfo_mb.h | 2 +- src/include/miscadmin.h | 2 +- src/include/nodes/bitmapset.h | 2 +- src/include/nodes/execnodes.h | 2 +- src/include/nodes/extensible.h | 2 +- src/include/nodes/lockoptions.h | 2 +- src/include/nodes/makefuncs.h | 2 +- src/include/nodes/memnodes.h | 2 +- src/include/nodes/nodeFuncs.h | 2 +- src/include/nodes/nodes.h | 2 +- src/include/nodes/params.h | 2 +- src/include/nodes/parsenodes.h | 2 +- src/include/nodes/pathnodes.h | 2 +- src/include/nodes/pg_list.h | 2 +- src/include/nodes/plannodes.h | 2 +- src/include/nodes/primnodes.h | 2 +- src/include/nodes/print.h | 2 +- src/include/nodes/readfuncs.h | 2 +- src/include/nodes/replnodes.h | 2 +- src/include/nodes/subscripting.h | 2 +- src/include/nodes/supportnodes.h | 2 +- src/include/nodes/tidbitmap.h | 2 +- src/include/nodes/value.h | 2 +- src/include/optimizer/appendinfo.h | 2 +- src/include/optimizer/clauses.h | 2 +- src/include/optimizer/cost.h | 2 +- src/include/optimizer/geqo.h | 2 +- src/include/optimizer/geqo_copy.h | 2 +- src/include/optimizer/geqo_gene.h | 2 +- src/include/optimizer/geqo_misc.h | 2 +- src/include/optimizer/geqo_mutation.h | 2 +- src/include/optimizer/geqo_pool.h | 2 +- src/include/optimizer/geqo_random.h | 2 +- src/include/optimizer/geqo_recombination.h | 2 +- src/include/optimizer/geqo_selection.h | 2 +- src/include/optimizer/inherit.h | 2 +- src/include/optimizer/joininfo.h | 2 +- src/include/optimizer/optimizer.h | 2 +- src/include/optimizer/orclauses.h | 2 +- src/include/optimizer/paramassign.h | 2 +- src/include/optimizer/pathnode.h | 2 +- src/include/optimizer/paths.h | 2 +- src/include/optimizer/placeholder.h | 2 +- src/include/optimizer/plancat.h | 2 +- src/include/optimizer/planmain.h | 2 +- src/include/optimizer/planner.h | 2 +- src/include/optimizer/prep.h | 2 +- src/include/optimizer/restrictinfo.h | 2 +- src/include/optimizer/subselect.h | 2 +- src/include/optimizer/tlist.h | 2 +- src/include/parser/analyze.h | 2 +- src/include/parser/gramparse.h | 2 +- src/include/parser/kwlist.h | 2 +- src/include/parser/parse_agg.h | 2 +- src/include/parser/parse_clause.h | 2 +- src/include/parser/parse_coerce.h | 2 +- src/include/parser/parse_collate.h | 2 +- src/include/parser/parse_cte.h | 2 +- src/include/parser/parse_enr.h | 2 +- src/include/parser/parse_expr.h | 2 +- src/include/parser/parse_func.h | 2 +- src/include/parser/parse_node.h | 2 +- src/include/parser/parse_oper.h | 2 +- src/include/parser/parse_param.h | 2 +- src/include/parser/parse_relation.h | 2 +- src/include/parser/parse_target.h | 2 +- src/include/parser/parse_type.h | 2 +- src/include/parser/parse_utilcmd.h | 2 +- src/include/parser/parser.h | 2 +- src/include/parser/parsetree.h | 2 +- src/include/parser/scanner.h | 2 +- src/include/parser/scansup.h | 2 +- src/include/partitioning/partbounds.h | 2 +- src/include/partitioning/partdefs.h | 2 +- src/include/partitioning/partdesc.h | 2 +- src/include/partitioning/partprune.h | 2 +- src/include/pg_config_manual.h | 2 +- src/include/pg_getopt.h | 2 +- src/include/pg_trace.h | 2 +- src/include/pgstat.h | 2 +- src/include/pgtar.h | 2 +- src/include/pgtime.h | 2 +- src/include/port.h | 2 +- src/include/port/atomics.h | 2 +- src/include/port/atomics/arch-arm.h | 2 +- src/include/port/atomics/arch-hppa.h | 2 +- src/include/port/atomics/arch-ia64.h | 2 +- src/include/port/atomics/arch-ppc.h | 2 +- src/include/port/atomics/arch-x86.h | 2 +- src/include/port/atomics/fallback.h | 2 +- src/include/port/atomics/generic-acc.h | 2 +- src/include/port/atomics/generic-gcc.h | 2 +- src/include/port/atomics/generic-msvc.h | 2 +- src/include/port/atomics/generic-sunpro.h | 2 +- src/include/port/atomics/generic.h | 2 +- src/include/port/pg_bitutils.h | 2 +- src/include/port/pg_bswap.h | 2 +- src/include/port/pg_crc32c.h | 2 +- src/include/port/win32_port.h | 2 +- src/include/portability/instr_time.h | 2 +- src/include/portability/mem.h | 2 +- src/include/postgres.h | 2 +- src/include/postgres_fe.h | 2 +- src/include/postmaster/autovacuum.h | 2 +- src/include/postmaster/bgworker.h | 2 +- src/include/postmaster/bgworker_internals.h | 2 +- src/include/postmaster/bgwriter.h | 2 +- src/include/postmaster/fork_process.h | 2 +- src/include/postmaster/interrupt.h | 2 +- src/include/postmaster/pgarch.h | 2 +- src/include/postmaster/postmaster.h | 2 +- src/include/postmaster/startup.h | 2 +- src/include/postmaster/syslogger.h | 2 +- src/include/postmaster/walwriter.h | 2 +- src/include/regex/regexport.h | 2 +- src/include/replication/backup_manifest.h | 2 +- src/include/replication/basebackup.h | 2 +- src/include/replication/decode.h | 2 +- src/include/replication/logical.h | 2 +- src/include/replication/logicallauncher.h | 2 +- src/include/replication/logicalproto.h | 2 +- src/include/replication/logicalrelation.h | 2 +- src/include/replication/logicalworker.h | 2 +- src/include/replication/message.h | 2 +- src/include/replication/origin.h | 2 +- src/include/replication/output_plugin.h | 2 +- src/include/replication/pgoutput.h | 2 +- src/include/replication/reorderbuffer.h | 2 +- src/include/replication/slot.h | 2 +- src/include/replication/snapbuild.h | 2 +- src/include/replication/syncrep.h | 2 +- src/include/replication/walreceiver.h | 2 +- src/include/replication/walsender.h | 2 +- src/include/replication/walsender_private.h | 2 +- src/include/replication/worker_internal.h | 2 +- src/include/rewrite/prs2lock.h | 2 +- src/include/rewrite/rewriteDefine.h | 2 +- src/include/rewrite/rewriteHandler.h | 2 +- src/include/rewrite/rewriteManip.h | 2 +- src/include/rewrite/rewriteRemove.h | 2 +- src/include/rewrite/rewriteSupport.h | 2 +- src/include/rewrite/rowsecurity.h | 2 +- src/include/rusagestub.h | 2 +- src/include/snowball/header.h | 2 +- src/include/statistics/extended_stats_internal.h | 2 +- src/include/statistics/statistics.h | 2 +- src/include/storage/backendid.h | 2 +- src/include/storage/barrier.h | 2 +- src/include/storage/block.h | 2 +- src/include/storage/buf.h | 2 +- src/include/storage/buf_internals.h | 2 +- src/include/storage/buffile.h | 2 +- src/include/storage/bufmgr.h | 2 +- src/include/storage/bufpage.h | 2 +- src/include/storage/checksum.h | 2 +- src/include/storage/checksum_impl.h | 2 +- src/include/storage/condition_variable.h | 2 +- src/include/storage/copydir.h | 2 +- src/include/storage/dsm.h | 2 +- src/include/storage/dsm_impl.h | 2 +- src/include/storage/fd.h | 2 +- src/include/storage/freespace.h | 2 +- src/include/storage/fsm_internals.h | 2 +- src/include/storage/indexfsm.h | 2 +- src/include/storage/ipc.h | 2 +- src/include/storage/item.h | 2 +- src/include/storage/itemid.h | 2 +- src/include/storage/itemptr.h | 2 +- src/include/storage/large_object.h | 2 +- src/include/storage/latch.h | 2 +- src/include/storage/lmgr.h | 2 +- src/include/storage/lock.h | 2 +- src/include/storage/lockdefs.h | 2 +- src/include/storage/lwlock.h | 2 +- src/include/storage/md.h | 2 +- src/include/storage/off.h | 2 +- src/include/storage/pg_sema.h | 2 +- src/include/storage/pg_shmem.h | 2 +- src/include/storage/pmsignal.h | 2 +- src/include/storage/predicate.h | 2 +- src/include/storage/predicate_internals.h | 2 +- src/include/storage/proc.h | 2 +- src/include/storage/procarray.h | 2 +- src/include/storage/proclist.h | 2 +- src/include/storage/proclist_types.h | 2 +- src/include/storage/procsignal.h | 2 +- src/include/storage/reinit.h | 2 +- src/include/storage/relfilenode.h | 2 +- src/include/storage/s_lock.h | 2 +- src/include/storage/sharedfileset.h | 2 +- src/include/storage/shm_mq.h | 2 +- src/include/storage/shm_toc.h | 2 +- src/include/storage/shmem.h | 2 +- src/include/storage/sinval.h | 2 +- src/include/storage/sinvaladt.h | 2 +- src/include/storage/smgr.h | 2 +- src/include/storage/spin.h | 2 +- src/include/storage/standby.h | 2 +- src/include/storage/standbydefs.h | 2 +- src/include/storage/sync.h | 2 +- src/include/tcop/cmdtag.h | 2 +- src/include/tcop/cmdtaglist.h | 2 +- src/include/tcop/deparse_utility.h | 2 +- src/include/tcop/dest.h | 2 +- src/include/tcop/fastpath.h | 2 +- src/include/tcop/pquery.h | 2 +- src/include/tcop/tcopprot.h | 2 +- src/include/tcop/utility.h | 2 +- src/include/tsearch/dicts/regis.h | 2 +- src/include/tsearch/dicts/spell.h | 2 +- src/include/tsearch/ts_cache.h | 2 +- src/include/tsearch/ts_locale.h | 2 +- src/include/tsearch/ts_public.h | 2 +- src/include/tsearch/ts_type.h | 2 +- src/include/tsearch/ts_utils.h | 2 +- src/include/utils/acl.h | 2 +- src/include/utils/aclchk_internal.h | 2 +- src/include/utils/array.h | 2 +- src/include/utils/arrayaccess.h | 2 +- src/include/utils/ascii.h | 2 +- src/include/utils/attoptcache.h | 2 +- src/include/utils/builtins.h | 2 +- src/include/utils/bytea.h | 2 +- src/include/utils/catcache.h | 2 +- src/include/utils/combocid.h | 2 +- src/include/utils/date.h | 2 +- src/include/utils/datetime.h | 2 +- src/include/utils/datum.h | 2 +- src/include/utils/dsa.h | 2 +- src/include/utils/dynahash.h | 2 +- src/include/utils/elog.h | 2 +- src/include/utils/evtcache.h | 2 +- src/include/utils/expandeddatum.h | 2 +- src/include/utils/expandedrecord.h | 2 +- src/include/utils/float.h | 2 +- src/include/utils/fmgrtab.h | 2 +- src/include/utils/formatting.h | 2 +- src/include/utils/freepage.h | 2 +- src/include/utils/geo_decls.h | 2 +- src/include/utils/guc.h | 2 +- src/include/utils/guc_tables.h | 2 +- src/include/utils/help_config.h | 2 +- src/include/utils/hsearch.h | 2 +- src/include/utils/index_selfuncs.h | 2 +- src/include/utils/inet.h | 2 +- src/include/utils/int8.h | 2 +- src/include/utils/inval.h | 2 +- src/include/utils/json.h | 2 +- src/include/utils/jsonb.h | 2 +- src/include/utils/jsonfuncs.h | 2 +- src/include/utils/jsonpath.h | 2 +- src/include/utils/logtape.h | 2 +- src/include/utils/lsyscache.h | 2 +- src/include/utils/memdebug.h | 2 +- src/include/utils/memutils.h | 2 +- src/include/utils/multirangetypes.h | 2 +- src/include/utils/numeric.h | 2 +- src/include/utils/old_snapshot.h | 2 +- src/include/utils/palloc.h | 2 +- src/include/utils/partcache.h | 2 +- src/include/utils/pg_crc.h | 2 +- src/include/utils/pg_locale.h | 2 +- src/include/utils/pg_lsn.h | 2 +- src/include/utils/pg_rusage.h | 2 +- src/include/utils/pidfile.h | 2 +- src/include/utils/plancache.h | 2 +- src/include/utils/portal.h | 2 +- src/include/utils/queryenvironment.h | 2 +- src/include/utils/rangetypes.h | 2 +- src/include/utils/regproc.h | 2 +- src/include/utils/rel.h | 2 +- src/include/utils/relcache.h | 2 +- src/include/utils/relfilenodemap.h | 2 +- src/include/utils/relmapper.h | 2 +- src/include/utils/relptr.h | 2 +- src/include/utils/reltrigger.h | 2 +- src/include/utils/resowner.h | 2 +- src/include/utils/resowner_private.h | 2 +- src/include/utils/rls.h | 2 +- src/include/utils/ruleutils.h | 2 +- src/include/utils/sampling.h | 2 +- src/include/utils/selfuncs.h | 2 +- src/include/utils/sharedtuplestore.h | 2 +- src/include/utils/snapmgr.h | 2 +- src/include/utils/snapshot.h | 2 +- src/include/utils/sortsupport.h | 2 +- src/include/utils/spccache.h | 2 +- src/include/utils/syscache.h | 2 +- src/include/utils/timeout.h | 2 +- src/include/utils/timestamp.h | 2 +- src/include/utils/tuplesort.h | 2 +- src/include/utils/tuplestore.h | 2 +- src/include/utils/typcache.h | 2 +- src/include/utils/tzparser.h | 2 +- src/include/utils/uuid.h | 2 +- src/include/utils/varbit.h | 2 +- src/include/utils/varlena.h | 2 +- src/include/utils/xid8.h | 2 +- src/include/utils/xml.h | 2 +- src/include/windowapi.h | 2 +- src/interfaces/ecpg/compatlib/Makefile | 2 +- src/interfaces/ecpg/ecpglib/Makefile | 2 +- src/interfaces/ecpg/pgtypeslib/Makefile | 2 +- src/interfaces/ecpg/preproc/Makefile | 2 +- src/interfaces/ecpg/preproc/c_kwlist.h | 2 +- src/interfaces/ecpg/preproc/check_rules.pl | 2 +- src/interfaces/ecpg/preproc/ecpg.c | 2 +- src/interfaces/ecpg/preproc/ecpg_kwlist.h | 2 +- src/interfaces/ecpg/preproc/keywords.c | 2 +- src/interfaces/ecpg/preproc/parse.pl | 2 +- src/interfaces/ecpg/preproc/parser.c | 2 +- src/interfaces/ecpg/preproc/pgc.l | 2 +- src/interfaces/ecpg/test/pg_regress_ecpg.c | 2 +- src/interfaces/libpq/Makefile | 2 +- src/interfaces/libpq/fe-auth-scram.c | 2 +- src/interfaces/libpq/fe-auth.c | 2 +- src/interfaces/libpq/fe-auth.h | 2 +- src/interfaces/libpq/fe-connect.c | 2 +- src/interfaces/libpq/fe-exec.c | 2 +- src/interfaces/libpq/fe-gssapi-common.c | 2 +- src/interfaces/libpq/fe-gssapi-common.h | 2 +- src/interfaces/libpq/fe-lobj.c | 2 +- src/interfaces/libpq/fe-misc.c | 2 +- src/interfaces/libpq/fe-print.c | 2 +- src/interfaces/libpq/fe-protocol2.c | 2 +- src/interfaces/libpq/fe-protocol3.c | 2 +- src/interfaces/libpq/fe-secure-common.c | 2 +- src/interfaces/libpq/fe-secure-common.h | 2 +- src/interfaces/libpq/fe-secure-gssapi.c | 2 +- src/interfaces/libpq/fe-secure-openssl.c | 2 +- src/interfaces/libpq/fe-secure.c | 2 +- src/interfaces/libpq/legacy-pqsignal.c | 2 +- src/interfaces/libpq/libpq-events.c | 2 +- src/interfaces/libpq/libpq-events.h | 2 +- src/interfaces/libpq/libpq-fe.h | 2 +- src/interfaces/libpq/libpq-int.h | 2 +- src/interfaces/libpq/pqexpbuffer.c | 2 +- src/interfaces/libpq/pqexpbuffer.h | 2 +- src/interfaces/libpq/pthread-win32.c | 2 +- src/interfaces/libpq/test/uri-regress.c | 2 +- src/interfaces/libpq/win32.c | 2 +- src/pl/plperl/plperl.h | 2 +- src/pl/plpgsql/src/generate-plerrcodes.pl | 2 +- src/pl/plpgsql/src/pl_comp.c | 2 +- src/pl/plpgsql/src/pl_exec.c | 2 +- src/pl/plpgsql/src/pl_funcs.c | 2 +- src/pl/plpgsql/src/pl_gram.y | 2 +- src/pl/plpgsql/src/pl_handler.c | 2 +- src/pl/plpgsql/src/pl_reserved_kwlist.h | 2 +- src/pl/plpgsql/src/pl_scanner.c | 2 +- src/pl/plpgsql/src/pl_unreserved_kwlist.h | 2 +- src/pl/plpgsql/src/plpgsql.h | 2 +- src/pl/plpython/generate-spiexceptions.pl | 2 +- src/pl/plpython/plpython.h | 2 +- src/pl/tcl/generate-pltclerrcodes.pl | 2 +- src/port/chklocale.c | 2 +- src/port/dirent.c | 2 +- src/port/dirmod.c | 2 +- src/port/dlopen.c | 2 +- src/port/erand48.c | 2 +- src/port/explicit_bzero.c | 2 +- src/port/fls.c | 2 +- src/port/getaddrinfo.c | 2 +- src/port/getpeereid.c | 2 +- src/port/getrusage.c | 2 +- src/port/kill.c | 2 +- src/port/link.c | 2 +- src/port/mkdtemp.c | 2 +- src/port/noblock.c | 2 +- src/port/open.c | 2 +- src/port/path.c | 2 +- src/port/pg_bitutils.c | 2 +- src/port/pg_crc32c_armv8.c | 2 +- src/port/pg_crc32c_armv8_choose.c | 2 +- src/port/pg_crc32c_sb8.c | 2 +- src/port/pg_crc32c_sse42.c | 2 +- src/port/pg_crc32c_sse42_choose.c | 2 +- src/port/pg_strong_random.c | 2 +- src/port/pgcheckdir.c | 2 +- src/port/pgsleep.c | 2 +- src/port/pgstrcasecmp.c | 2 +- src/port/pgstrsignal.c | 2 +- src/port/pqsignal.c | 2 +- src/port/pread.c | 2 +- src/port/pwrite.c | 2 +- src/port/quotes.c | 2 +- src/port/random.c | 2 +- src/port/setenv.c | 2 +- src/port/snprintf.c | 2 +- src/port/srandom.c | 2 +- src/port/strerror.c | 2 +- src/port/strlcpy.c | 2 +- src/port/strnlen.c | 2 +- src/port/strtof.c | 2 +- src/port/system.c | 2 +- src/port/thread.c | 2 +- src/port/unsetenv.c | 2 +- src/port/win32env.c | 2 +- src/port/win32error.c | 2 +- src/port/win32security.c | 2 +- src/port/win32setlocale.c | 2 +- src/port/win32stat.c | 2 +- src/port/win32ver.rc | 2 +- src/test/authentication/Makefile | 2 +- src/test/examples/testlo.c | 2 +- src/test/examples/testlo64.c | 2 +- src/test/isolation/isolation_main.c | 2 +- src/test/isolation/isolationtester.h | 2 +- src/test/isolation/specparse.y | 2 +- src/test/isolation/specscanner.l | 2 +- src/test/kerberos/Makefile | 2 +- src/test/ldap/Makefile | 2 +- src/test/modules/delay_execution/delay_execution.c | 2 +- src/test/modules/dummy_index_am/dummy_index_am.c | 2 +- src/test/modules/dummy_seclabel/dummy_seclabel.c | 2 +- src/test/modules/plsample/plsample.c | 2 +- src/test/modules/test_bloomfilter/test_bloomfilter.c | 2 +- src/test/modules/test_ddl_deparse/test_ddl_deparse.c | 2 +- .../modules/test_ginpostinglist/test_ginpostinglist.c | 2 +- src/test/modules/test_integerset/test_integerset.c | 2 +- src/test/modules/test_parser/test_parser.c | 2 +- src/test/modules/test_predtest/test_predtest.c | 2 +- src/test/modules/test_rbtree/test_rbtree.c | 2 +- src/test/modules/test_rls_hooks/test_rls_hooks.c | 2 +- src/test/modules/test_rls_hooks/test_rls_hooks.h | 2 +- src/test/modules/test_shm_mq/setup.c | 2 +- src/test/modules/test_shm_mq/test.c | 2 +- src/test/modules/test_shm_mq/test_shm_mq.h | 2 +- src/test/modules/test_shm_mq/worker.c | 2 +- src/test/modules/worker_spi/worker_spi.c | 2 +- src/test/perl/Makefile | 2 +- src/test/recovery/Makefile | 2 +- src/test/regress/GNUmakefile | 2 +- src/test/regress/pg_regress.c | 2 +- src/test/regress/pg_regress.h | 2 +- src/test/regress/pg_regress_main.c | 2 +- src/test/regress/regress.c | 2 +- src/test/ssl/Makefile | 2 +- src/test/subscription/Makefile | 2 +- src/timezone/pgtz.c | 2 +- src/timezone/pgtz.h | 2 +- src/tools/PerfectHash.pm | 2 +- src/tools/check_bison_recursion.pl | 2 +- src/tools/copyright.pl | 2 +- src/tools/findoidjoins/Makefile | 2 +- src/tools/findoidjoins/findoidjoins.c | 2 +- src/tools/fix-old-flex-code.pl | 2 +- src/tools/gen_keywordlist.pl | 4 ++-- src/tools/ifaddrs/Makefile | 2 +- src/tools/pginclude/cpluspluscheck | 2 +- src/tools/pginclude/headerscheck | 2 +- src/tools/testint128.c | 2 +- src/tools/version_stamp.pl | 2 +- src/tools/win32tzlist.pl | 2 +- src/tutorial/complex.source | 2 +- src/tutorial/syscat.source | 2 +- 1821 files changed, 1834 insertions(+), 1834 deletions(-) diff --git a/COPYRIGHT b/COPYRIGHT index 0fc523af94605..655a3c59d60f5 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,7 +1,7 @@ PostgreSQL Database Management System (formerly known as Postgres, then as Postgres95) -Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group Portions Copyright (c) 1994, The Regents of the University of California diff --git a/config/thread_test.c b/config/thread_test.c index ff2eace87d841..784f4fe8ce3cc 100644 --- a/config/thread_test.c +++ b/config/thread_test.c @@ -3,7 +3,7 @@ * thread_test.c * libc threading test program * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * config/thread_test.c diff --git a/configure b/configure index 07529825d1897..e51b8ce6ec350 100755 --- a/configure +++ b/configure @@ -11,7 +11,7 @@ # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. # -# Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Copyright (c) 1996-2021, PostgreSQL Global Development Group ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## @@ -1676,7 +1676,7 @@ Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. -Copyright (c) 1996-2020, PostgreSQL Global Development Group +Copyright (c) 1996-2021, PostgreSQL Global Development Group _ACEOF exit fi diff --git a/configure.ac b/configure.ac index 7f855783f4ef5..054839f0f25b3 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,7 @@ m4_if(m4_defn([m4_PACKAGE_VERSION]), [2.69], [], [m4_fatal([Autoconf version 2.6 Untested combinations of 'autoconf' and PostgreSQL versions are not recommended. You can remove the check from 'configure.ac' but it is then your responsibility whether the result works or not.])]) -AC_COPYRIGHT([Copyright (c) 1996-2020, PostgreSQL Global Development Group]) +AC_COPYRIGHT([Copyright (c) 1996-2021, PostgreSQL Global Development Group]) AC_CONFIG_SRCDIR([src/backend/access/common/heaptuple.c]) AC_CONFIG_AUX_DIR(config) AC_PREFIX_DEFAULT(/usr/local/pgsql) diff --git a/contrib/adminpack/adminpack.c b/contrib/adminpack/adminpack.c index d064b5a0806df..c3c5e03945de9 100644 --- a/contrib/adminpack/adminpack.c +++ b/contrib/adminpack/adminpack.c @@ -3,7 +3,7 @@ * adminpack.c * * - * Copyright (c) 2002-2020, PostgreSQL Global Development Group + * Copyright (c) 2002-2021, PostgreSQL Global Development Group * * Author: Andreas Pflug * diff --git a/contrib/amcheck/verify_heapam.c b/contrib/amcheck/verify_heapam.c index bc34bb0c839cd..88ab32490c0da 100644 --- a/contrib/amcheck/verify_heapam.c +++ b/contrib/amcheck/verify_heapam.c @@ -3,7 +3,7 @@ * verify_heapam.c * Functions to check postgresql heap relations for corruption * - * Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Copyright (c) 2016-2021, PostgreSQL Global Development Group * * contrib/amcheck/verify_heapam.c *------------------------------------------------------------------------- diff --git a/contrib/amcheck/verify_nbtree.c b/contrib/amcheck/verify_nbtree.c index 6d86e3ccdacfb..b8c7793d9e06a 100644 --- a/contrib/amcheck/verify_nbtree.c +++ b/contrib/amcheck/verify_nbtree.c @@ -14,7 +14,7 @@ * that every visible heap tuple has a matching index tuple. * * - * Copyright (c) 2017-2020, PostgreSQL Global Development Group + * Copyright (c) 2017-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/amcheck/verify_nbtree.c diff --git a/contrib/auth_delay/auth_delay.c b/contrib/auth_delay/auth_delay.c index 11c2f059e4c59..5820ac328db15 100644 --- a/contrib/auth_delay/auth_delay.c +++ b/contrib/auth_delay/auth_delay.c @@ -2,7 +2,7 @@ * * auth_delay.c * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/auth_delay/auth_delay.c diff --git a/contrib/auto_explain/auto_explain.c b/contrib/auto_explain/auto_explain.c index 56c549d84c1d3..faa6231d8722d 100644 --- a/contrib/auto_explain/auto_explain.c +++ b/contrib/auto_explain/auto_explain.c @@ -3,7 +3,7 @@ * auto_explain.c * * - * Copyright (c) 2008-2020, PostgreSQL Global Development Group + * Copyright (c) 2008-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/auto_explain/auto_explain.c diff --git a/contrib/bloom/blcost.c b/contrib/bloom/blcost.c index 54f954dce8c9a..4af1fc9e1cc0b 100644 --- a/contrib/bloom/blcost.c +++ b/contrib/bloom/blcost.c @@ -3,7 +3,7 @@ * blcost.c * Cost estimate function for bloom indexes. * - * Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Copyright (c) 2016-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/bloom/blcost.c diff --git a/contrib/bloom/blinsert.c b/contrib/bloom/blinsert.c index 6d3fd5c432cd6..32b5d62e1f34c 100644 --- a/contrib/bloom/blinsert.c +++ b/contrib/bloom/blinsert.c @@ -3,7 +3,7 @@ * blinsert.c * Bloom index build and insert functions. * - * Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Copyright (c) 2016-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/bloom/blinsert.c diff --git a/contrib/bloom/bloom.h b/contrib/bloom/bloom.h index 23aa7ac4416cc..436bd43209245 100644 --- a/contrib/bloom/bloom.h +++ b/contrib/bloom/bloom.h @@ -3,7 +3,7 @@ * bloom.h * Header for bloom index. * - * Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Copyright (c) 2016-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/bloom/bloom.h diff --git a/contrib/bloom/blscan.c b/contrib/bloom/blscan.c index 3c71401c8c6f4..6ae3710d9f785 100644 --- a/contrib/bloom/blscan.c +++ b/contrib/bloom/blscan.c @@ -3,7 +3,7 @@ * blscan.c * Bloom index scan functions. * - * Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Copyright (c) 2016-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/bloom/blscan.c diff --git a/contrib/bloom/blutils.c b/contrib/bloom/blutils.c index 26b9927c3aaf9..1e505b1da5424 100644 --- a/contrib/bloom/blutils.c +++ b/contrib/bloom/blutils.c @@ -3,7 +3,7 @@ * blutils.c * Bloom index utilities. * - * Portions Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2016-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1990-1993, Regents of the University of California * * IDENTIFICATION diff --git a/contrib/bloom/blvacuum.c b/contrib/bloom/blvacuum.c index 3282adde03b1d..88b0a6d29002d 100644 --- a/contrib/bloom/blvacuum.c +++ b/contrib/bloom/blvacuum.c @@ -3,7 +3,7 @@ * blvacuum.c * Bloom VACUUM functions. * - * Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Copyright (c) 2016-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/bloom/blvacuum.c diff --git a/contrib/bloom/blvalidate.c b/contrib/bloom/blvalidate.c index 3c05e5b01c99d..aa8c87c077275 100644 --- a/contrib/bloom/blvalidate.c +++ b/contrib/bloom/blvalidate.c @@ -3,7 +3,7 @@ * blvalidate.c * Opclass validator for bloom. * - * Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Copyright (c) 2016-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/bloom/blvalidate.c diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c index 651227f510e9a..3a0beaa88e7b5 100644 --- a/contrib/dblink/dblink.c +++ b/contrib/dblink/dblink.c @@ -9,7 +9,7 @@ * Shridhar Daithankar * * contrib/dblink/dblink.c - * Copyright (c) 2001-2020, PostgreSQL Global Development Group + * Copyright (c) 2001-2021, PostgreSQL Global Development Group * ALL RIGHTS RESERVED; * * Permission to use, copy, modify, and distribute this software and its diff --git a/contrib/dict_int/dict_int.c b/contrib/dict_int/dict_int.c index a7e9890fcc4f8..3c84208b11e3b 100644 --- a/contrib/dict_int/dict_int.c +++ b/contrib/dict_int/dict_int.c @@ -3,7 +3,7 @@ * dict_int.c * Text search dictionary for integers * - * Copyright (c) 2007-2020, PostgreSQL Global Development Group + * Copyright (c) 2007-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/dict_int/dict_int.c diff --git a/contrib/dict_xsyn/dict_xsyn.c b/contrib/dict_xsyn/dict_xsyn.c index 1065d64ccb0ad..79c4f18f409c7 100644 --- a/contrib/dict_xsyn/dict_xsyn.c +++ b/contrib/dict_xsyn/dict_xsyn.c @@ -3,7 +3,7 @@ * dict_xsyn.c * Extended synonym dictionary * - * Copyright (c) 2007-2020, PostgreSQL Global Development Group + * Copyright (c) 2007-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/dict_xsyn/dict_xsyn.c diff --git a/contrib/file_fdw/file_fdw.c b/contrib/file_fdw/file_fdw.c index 9863e3274807b..2059c07349bf7 100644 --- a/contrib/file_fdw/file_fdw.c +++ b/contrib/file_fdw/file_fdw.c @@ -3,7 +3,7 @@ * file_fdw.c * foreign-data wrapper for server-side flat files (or programs). * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/file_fdw/file_fdw.c diff --git a/contrib/fuzzystrmatch/fuzzystrmatch.c b/contrib/fuzzystrmatch/fuzzystrmatch.c index ccbb84b481ba3..d237772a3b212 100644 --- a/contrib/fuzzystrmatch/fuzzystrmatch.c +++ b/contrib/fuzzystrmatch/fuzzystrmatch.c @@ -6,7 +6,7 @@ * Joe Conway * * contrib/fuzzystrmatch/fuzzystrmatch.c - * Copyright (c) 2001-2020, PostgreSQL Global Development Group + * Copyright (c) 2001-2021, PostgreSQL Global Development Group * ALL RIGHTS RESERVED; * * metaphone() diff --git a/contrib/hstore/hstore_subs.c b/contrib/hstore/hstore_subs.c index e52de04f1a6b2..ca4c174a51501 100644 --- a/contrib/hstore/hstore_subs.c +++ b/contrib/hstore/hstore_subs.c @@ -12,7 +12,7 @@ * check_subscripts function and just let the fetch and assign functions * do everything. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/contrib/intarray/_int_selfuncs.c b/contrib/intarray/_int_selfuncs.c index a3a538a20d96e..38d68c12d231d 100644 --- a/contrib/intarray/_int_selfuncs.c +++ b/contrib/intarray/_int_selfuncs.c @@ -3,7 +3,7 @@ * _int_selfuncs.c * Functions for selectivity estimation of intarray operators * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/contrib/isn/isn.c b/contrib/isn/isn.c index cf36bb69d4d5a..1cf1669f25cac 100644 --- a/contrib/isn/isn.c +++ b/contrib/isn/isn.c @@ -4,7 +4,7 @@ * PostgreSQL type definitions for ISNs (ISBN, ISMN, ISSN, EAN13, UPC) * * Author: German Mendez Bravo (Kronuz) - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/isn/isn.c diff --git a/contrib/isn/isn.h b/contrib/isn/isn.h index 017f5974db568..4f4935f80d855 100644 --- a/contrib/isn/isn.h +++ b/contrib/isn/isn.h @@ -4,7 +4,7 @@ * PostgreSQL type definitions for ISNs (ISBN, ISMN, ISSN, EAN13, UPC) * * Author: German Mendez Bravo (Kronuz) - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/isn/isn.h diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c index 37e0055a00860..3df07177ed661 100644 --- a/contrib/old_snapshot/time_mapping.c +++ b/contrib/old_snapshot/time_mapping.c @@ -3,7 +3,7 @@ * time_mapping.c * time to XID mapping information * - * Copyright (c) 2020, PostgreSQL Global Development Group + * Copyright (c) 2020-2021, PostgreSQL Global Development Group * * contrib/old_snapshot/time_mapping.c *------------------------------------------------------------------------- diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c index fb32d74a66a98..e872f65f012e7 100644 --- a/contrib/pageinspect/brinfuncs.c +++ b/contrib/pageinspect/brinfuncs.c @@ -2,7 +2,7 @@ * brinfuncs.c * Functions to investigate BRIN indexes * - * Copyright (c) 2014-2020, PostgreSQL Global Development Group + * Copyright (c) 2014-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/pageinspect/brinfuncs.c diff --git a/contrib/pageinspect/fsmfuncs.c b/contrib/pageinspect/fsmfuncs.c index 099acbb2fe4b0..930f1df339000 100644 --- a/contrib/pageinspect/fsmfuncs.c +++ b/contrib/pageinspect/fsmfuncs.c @@ -9,7 +9,7 @@ * there's hardly any use case for using these without superuser-rights * anyway. * - * Copyright (c) 2007-2020, PostgreSQL Global Development Group + * Copyright (c) 2007-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/pageinspect/fsmfuncs.c diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c index 711473579a86f..e425cbcdb8e19 100644 --- a/contrib/pageinspect/ginfuncs.c +++ b/contrib/pageinspect/ginfuncs.c @@ -2,7 +2,7 @@ * ginfuncs.c * Functions to investigate the content of GIN indexes * - * Copyright (c) 2014-2020, PostgreSQL Global Development Group + * Copyright (c) 2014-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/pageinspect/ginfuncs.c diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c index 3b2f0339cfe09..aa11ef396b06c 100644 --- a/contrib/pageinspect/hashfuncs.c +++ b/contrib/pageinspect/hashfuncs.c @@ -2,7 +2,7 @@ * hashfuncs.c * Functions to investigate the content of HASH indexes * - * Copyright (c) 2017-2020, PostgreSQL Global Development Group + * Copyright (c) 2017-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/pageinspect/hashfuncs.c diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c index f04455da127c0..9abcee32afbcf 100644 --- a/contrib/pageinspect/heapfuncs.c +++ b/contrib/pageinspect/heapfuncs.c @@ -15,7 +15,7 @@ * there's hardly any use case for using these without superuser-rights * anyway. * - * Copyright (c) 2007-2020, PostgreSQL Global Development Group + * Copyright (c) 2007-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/pageinspect/heapfuncs.c diff --git a/contrib/pageinspect/pageinspect.h b/contrib/pageinspect/pageinspect.h index 478e0d2d20d88..c15bc23fe6b4d 100644 --- a/contrib/pageinspect/pageinspect.h +++ b/contrib/pageinspect/pageinspect.h @@ -3,7 +3,7 @@ * pageinspect.h * Common functions for pageinspect. * - * Copyright (c) 2017-2020, PostgreSQL Global Development Group + * Copyright (c) 2017-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/pageinspect/pageinspect.h diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c index c0181506a5d0b..ae1dc41e0551e 100644 --- a/contrib/pageinspect/rawpage.c +++ b/contrib/pageinspect/rawpage.c @@ -5,7 +5,7 @@ * * Access-method specific inspection functions are in separate files. * - * Copyright (c) 2007-2020, PostgreSQL Global Development Group + * Copyright (c) 2007-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/pageinspect/rawpage.c diff --git a/contrib/passwordcheck/passwordcheck.c b/contrib/passwordcheck/passwordcheck.c index 70f056232fe72..3d644be8dd558 100644 --- a/contrib/passwordcheck/passwordcheck.c +++ b/contrib/passwordcheck/passwordcheck.c @@ -3,7 +3,7 @@ * passwordcheck.c * * - * Copyright (c) 2009-2020, PostgreSQL Global Development Group + * Copyright (c) 2009-2021, PostgreSQL Global Development Group * * Author: Laurenz Albe * diff --git a/contrib/pg_prewarm/autoprewarm.c b/contrib/pg_prewarm/autoprewarm.c index a85ee0450ec33..4c08d2b386b9c 100644 --- a/contrib/pg_prewarm/autoprewarm.c +++ b/contrib/pg_prewarm/autoprewarm.c @@ -16,7 +16,7 @@ * relevant database in turn. The former keeps running after the * initial prewarm is complete to update the dump file periodically. * - * Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Copyright (c) 2016-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/pg_prewarm/autoprewarm.c diff --git a/contrib/pg_prewarm/pg_prewarm.c b/contrib/pg_prewarm/pg_prewarm.c index 33e2d28b2767e..a8554529361e6 100644 --- a/contrib/pg_prewarm/pg_prewarm.c +++ b/contrib/pg_prewarm/pg_prewarm.c @@ -3,7 +3,7 @@ * pg_prewarm.c * prewarming utilities * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/pg_prewarm/pg_prewarm.c diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c index 196e1e214204f..72a117fc19712 100644 --- a/contrib/pg_stat_statements/pg_stat_statements.c +++ b/contrib/pg_stat_statements/pg_stat_statements.c @@ -49,7 +49,7 @@ * in the file to be read or written while holding only shared lock. * * - * Copyright (c) 2008-2020, PostgreSQL Global Development Group + * Copyright (c) 2008-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/pg_stat_statements/pg_stat_statements.c diff --git a/contrib/pg_surgery/heap_surgery.c b/contrib/pg_surgery/heap_surgery.c index eb96b4bb36d84..d31e5f31fd42a 100644 --- a/contrib/pg_surgery/heap_surgery.c +++ b/contrib/pg_surgery/heap_surgery.c @@ -3,7 +3,7 @@ * heap_surgery.c * Functions to perform surgery on the damaged heap table. * - * Copyright (c) 2020, PostgreSQL Global Development Group + * Copyright (c) 2020-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/pg_surgery/heap_surgery.c diff --git a/contrib/pg_surgery/pg_surgery--1.0.sql b/contrib/pg_surgery/pg_surgery--1.0.sql index 2ae7f228c74b8..d1e53a07bc9d5 100644 --- a/contrib/pg_surgery/pg_surgery--1.0.sql +++ b/contrib/pg_surgery/pg_surgery--1.0.sql @@ -15,4 +15,4 @@ RETURNS VOID AS 'MODULE_PATHNAME', 'heap_force_freeze' LANGUAGE C STRICT; -REVOKE EXECUTE ON FUNCTION heap_force_freeze(regclass, tid[]) FROM PUBLIC; \ No newline at end of file +REVOKE EXECUTE ON FUNCTION heap_force_freeze(regclass, tid[]) FROM PUBLIC; diff --git a/contrib/pg_trgm/trgm_regexp.c b/contrib/pg_trgm/trgm_regexp.c index 21e8a9f343514..1e4f0121f3d97 100644 --- a/contrib/pg_trgm/trgm_regexp.c +++ b/contrib/pg_trgm/trgm_regexp.c @@ -181,7 +181,7 @@ * 7) Mark state 3 final because state 5 of source NFA is marked as final. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c index 54e47b810fd2d..dd0c124e6255e 100644 --- a/contrib/pg_visibility/pg_visibility.c +++ b/contrib/pg_visibility/pg_visibility.c @@ -3,7 +3,7 @@ * pg_visibility.c * display visibility map information and page-level visibility bits * - * Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Copyright (c) 2016-2021, PostgreSQL Global Development Group * * contrib/pg_visibility/pg_visibility.c *------------------------------------------------------------------------- diff --git a/contrib/pgcrypto/imath.c b/contrib/pgcrypto/imath.c index 9deaa797c1a0f..0bfa080fa5502 100644 --- a/contrib/pgcrypto/imath.c +++ b/contrib/pgcrypto/imath.c @@ -29,7 +29,7 @@ * * 4. Update this header comment. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/pgcrypto/imath.c diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c index 23306e11a78d6..1fe193bb256f2 100644 --- a/contrib/pgstattuple/pgstatapprox.c +++ b/contrib/pgstattuple/pgstatapprox.c @@ -3,7 +3,7 @@ * pgstatapprox.c * Bloat estimation functions * - * Copyright (c) 2014-2020, PostgreSQL Global Development Group + * Copyright (c) 2014-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/pgstattuple/pgstatapprox.c diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c index d841cec39b563..266f66cc62ce1 100644 --- a/contrib/postgres_fdw/connection.c +++ b/contrib/postgres_fdw/connection.c @@ -3,7 +3,7 @@ * connection.c * Connection management functions for postgres_fdw * - * Portions Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2012-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/postgres_fdw/connection.c diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c index ca2f9f321570f..3cf7b4eb1e046 100644 --- a/contrib/postgres_fdw/deparse.c +++ b/contrib/postgres_fdw/deparse.c @@ -24,7 +24,7 @@ * with collations that match the remote table's columns, which we can * consider to be user error. * - * Portions Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2012-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/postgres_fdw/deparse.c diff --git a/contrib/postgres_fdw/option.c b/contrib/postgres_fdw/option.c index 1a03e02263eeb..1fec3c3eeac61 100644 --- a/contrib/postgres_fdw/option.c +++ b/contrib/postgres_fdw/option.c @@ -3,7 +3,7 @@ * option.c * FDW option handling for postgres_fdw * - * Portions Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2012-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/postgres_fdw/option.c diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index b6c72e1d1e642..2f2d4d171c18b 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -3,7 +3,7 @@ * postgres_fdw.c * Foreign-data wrapper for remote PostgreSQL servers * - * Portions Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2012-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/postgres_fdw/postgres_fdw.c diff --git a/contrib/postgres_fdw/postgres_fdw.h b/contrib/postgres_fdw/postgres_fdw.h index eef410db3921f..277a30f5000da 100644 --- a/contrib/postgres_fdw/postgres_fdw.h +++ b/contrib/postgres_fdw/postgres_fdw.h @@ -3,7 +3,7 @@ * postgres_fdw.h * Foreign-data wrapper for remote PostgreSQL servers * - * Portions Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2012-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/postgres_fdw/postgres_fdw.h diff --git a/contrib/postgres_fdw/shippable.c b/contrib/postgres_fdw/shippable.c index b4766dc5ff807..c43e7e5ec594e 100644 --- a/contrib/postgres_fdw/shippable.c +++ b/contrib/postgres_fdw/shippable.c @@ -13,7 +13,7 @@ * functions or functions using nonportable collations. Those considerations * need not be accounted for here. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/postgres_fdw/shippable.c diff --git a/contrib/sepgsql/database.c b/contrib/sepgsql/database.c index 3881a019cba21..14a74fb29503e 100644 --- a/contrib/sepgsql/database.c +++ b/contrib/sepgsql/database.c @@ -4,7 +4,7 @@ * * Routines corresponding to database objects * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * * ------------------------------------------------------------------------- */ diff --git a/contrib/sepgsql/dml.c b/contrib/sepgsql/dml.c index 75ee612bcdaea..1f96e8b507a42 100644 --- a/contrib/sepgsql/dml.c +++ b/contrib/sepgsql/dml.c @@ -4,7 +4,7 @@ * * Routines to handle DML permission checks * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * * ------------------------------------------------------------------------- */ diff --git a/contrib/sepgsql/hooks.c b/contrib/sepgsql/hooks.c index 853b5b04ab8b1..34de6158d6047 100644 --- a/contrib/sepgsql/hooks.c +++ b/contrib/sepgsql/hooks.c @@ -4,7 +4,7 @@ * * Entrypoints of the hooks in PostgreSQL, and dispatches the callbacks. * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * * ------------------------------------------------------------------------- */ diff --git a/contrib/sepgsql/label.c b/contrib/sepgsql/label.c index bee4380edcd78..7f23124009d58 100644 --- a/contrib/sepgsql/label.c +++ b/contrib/sepgsql/label.c @@ -4,7 +4,7 @@ * * Routines to support SELinux labels (security context) * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * * ------------------------------------------------------------------------- */ diff --git a/contrib/sepgsql/launcher b/contrib/sepgsql/launcher index 0fddaf59634d4..6574eb9ea9e16 100755 --- a/contrib/sepgsql/launcher +++ b/contrib/sepgsql/launcher @@ -2,7 +2,7 @@ # # A wrapper script to launch psql command in regression test # -# Copyright (c) 2010-2020, PostgreSQL Global Development Group +# Copyright (c) 2010-2021, PostgreSQL Global Development Group # # ------------------------------------------------------------------------- diff --git a/contrib/sepgsql/proc.c b/contrib/sepgsql/proc.c index e40d9095ba310..e0ff3f03701a9 100644 --- a/contrib/sepgsql/proc.c +++ b/contrib/sepgsql/proc.c @@ -4,7 +4,7 @@ * * Routines corresponding to procedure objects * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * * ------------------------------------------------------------------------- */ diff --git a/contrib/sepgsql/relation.c b/contrib/sepgsql/relation.c index a783767f81c9e..31e2ed5b14316 100644 --- a/contrib/sepgsql/relation.c +++ b/contrib/sepgsql/relation.c @@ -4,7 +4,7 @@ * * Routines corresponding to relation/attribute objects * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * * ------------------------------------------------------------------------- */ diff --git a/contrib/sepgsql/schema.c b/contrib/sepgsql/schema.c index f7b1a27e1a9ce..0285c57114c19 100644 --- a/contrib/sepgsql/schema.c +++ b/contrib/sepgsql/schema.c @@ -4,7 +4,7 @@ * * Routines corresponding to schema objects * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * * ------------------------------------------------------------------------- */ diff --git a/contrib/sepgsql/selinux.c b/contrib/sepgsql/selinux.c index 64ae53e867de0..f11968bcaa294 100644 --- a/contrib/sepgsql/selinux.c +++ b/contrib/sepgsql/selinux.c @@ -5,7 +5,7 @@ * Interactions between userspace and selinux in kernelspace, * using libselinux api. * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * * ------------------------------------------------------------------------- */ diff --git a/contrib/sepgsql/sepgsql.h b/contrib/sepgsql/sepgsql.h index 38302b530b133..219373426730b 100644 --- a/contrib/sepgsql/sepgsql.h +++ b/contrib/sepgsql/sepgsql.h @@ -4,7 +4,7 @@ * * Definitions corresponding to SE-PostgreSQL * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * * ------------------------------------------------------------------------- */ diff --git a/contrib/sepgsql/uavc.c b/contrib/sepgsql/uavc.c index 97189b7c46f04..4cc48d5f82eb7 100644 --- a/contrib/sepgsql/uavc.c +++ b/contrib/sepgsql/uavc.c @@ -6,7 +6,7 @@ * access control decisions recently used, and reduce number of kernel * invocations to avoid unnecessary performance hit. * - * Copyright (c) 2011-2020, PostgreSQL Global Development Group + * Copyright (c) 2011-2021, PostgreSQL Global Development Group * * ------------------------------------------------------------------------- */ diff --git a/contrib/tablefunc/tablefunc.c b/contrib/tablefunc/tablefunc.c index e9a9741154a2e..779bd4415e6ac 100644 --- a/contrib/tablefunc/tablefunc.c +++ b/contrib/tablefunc/tablefunc.c @@ -10,7 +10,7 @@ * And contributors: * Nabil Sayegh * - * Copyright (c) 2002-2020, PostgreSQL Global Development Group + * Copyright (c) 2002-2021, PostgreSQL Global Development Group * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without a written agreement diff --git a/contrib/tablefunc/tablefunc.h b/contrib/tablefunc/tablefunc.h index 794957ca21914..918518223d265 100644 --- a/contrib/tablefunc/tablefunc.h +++ b/contrib/tablefunc/tablefunc.h @@ -10,7 +10,7 @@ * And contributors: * Nabil Sayegh * - * Copyright (c) 2002-2020, PostgreSQL Global Development Group + * Copyright (c) 2002-2021, PostgreSQL Global Development Group * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without a written agreement diff --git a/contrib/tcn/tcn.c b/contrib/tcn/tcn.c index 552f107bf6b06..06847024a31b0 100644 --- a/contrib/tcn/tcn.c +++ b/contrib/tcn/tcn.c @@ -3,7 +3,7 @@ * tcn.c * triggered change notification support for PostgreSQL * - * Portions Copyright (c) 2011-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2011-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/contrib/test_decoding/test_decoding.c b/contrib/test_decoding/test_decoding.c index 05763553a40ee..929255eac7466 100644 --- a/contrib/test_decoding/test_decoding.c +++ b/contrib/test_decoding/test_decoding.c @@ -3,7 +3,7 @@ * test_decoding.c * example logical decoding output plugin * - * Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Copyright (c) 2012-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/test_decoding/test_decoding.c diff --git a/contrib/tsm_system_rows/tsm_system_rows.c b/contrib/tsm_system_rows/tsm_system_rows.c index 8bf0b2078ccac..4996612902492 100644 --- a/contrib/tsm_system_rows/tsm_system_rows.c +++ b/contrib/tsm_system_rows/tsm_system_rows.c @@ -17,7 +17,7 @@ * won't visit blocks added after the first scan, but that is fine since * such blocks shouldn't contain any visible tuples anyway. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/contrib/tsm_system_time/tsm_system_time.c b/contrib/tsm_system_time/tsm_system_time.c index 2fda572e6522d..788d8f9a68d3d 100644 --- a/contrib/tsm_system_time/tsm_system_time.c +++ b/contrib/tsm_system_time/tsm_system_time.c @@ -13,7 +13,7 @@ * However, we do what we can to reduce surprising behavior by selecting * the sampling pattern just once per query, much as in tsm_system_rows. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/contrib/unaccent/unaccent.c b/contrib/unaccent/unaccent.c index 0047efc075f30..2b3819fb2e827 100644 --- a/contrib/unaccent/unaccent.c +++ b/contrib/unaccent/unaccent.c @@ -3,7 +3,7 @@ * unaccent.c * Text search unaccent dictionary * - * Copyright (c) 2009-2020, PostgreSQL Global Development Group + * Copyright (c) 2009-2021, PostgreSQL Global Development Group * * IDENTIFICATION * contrib/unaccent/unaccent.c diff --git a/contrib/uuid-ossp/uuid-ossp.c b/contrib/uuid-ossp/uuid-ossp.c index 2ff7d9448bcad..049efc979ff6b 100644 --- a/contrib/uuid-ossp/uuid-ossp.c +++ b/contrib/uuid-ossp/uuid-ossp.c @@ -2,7 +2,7 @@ * * UUID generation functions using the BSD, E2FS or OSSP UUID library * - * Copyright (c) 2007-2020, PostgreSQL Global Development Group + * Copyright (c) 2007-2021, PostgreSQL Global Development Group * * Portions Copyright (c) 2009 Andrew Gierth * diff --git a/contrib/vacuumlo/vacuumlo.c b/contrib/vacuumlo/vacuumlo.c index 532cc596c4128..cdc2c02b8e825 100644 --- a/contrib/vacuumlo/vacuumlo.c +++ b/contrib/vacuumlo/vacuumlo.c @@ -3,7 +3,7 @@ * vacuumlo.c * This removes orphaned large objects from a database. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/doc/src/sgml/generate-errcodes-table.pl b/doc/src/sgml/generate-errcodes-table.pl index 66a3ee00298a1..bbce3762c2913 100644 --- a/doc/src/sgml/generate-errcodes-table.pl +++ b/doc/src/sgml/generate-errcodes-table.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl # # Generate the errcodes-table.sgml file from errcodes.txt -# Copyright (c) 2000-2020, PostgreSQL Global Development Group +# Copyright (c) 2000-2021, PostgreSQL Global Development Group use strict; use warnings; diff --git a/doc/src/sgml/generate-keywords-table.pl b/doc/src/sgml/generate-keywords-table.pl index 6332d65aadc78..30037c773d9b7 100644 --- a/doc/src/sgml/generate-keywords-table.pl +++ b/doc/src/sgml/generate-keywords-table.pl @@ -2,7 +2,7 @@ # # Generate the keywords table for the documentation's SQL Key Words appendix # -# Copyright (c) 2019-2020, PostgreSQL Global Development Group +# Copyright (c) 2019-2021, PostgreSQL Global Development Group use strict; use warnings; diff --git a/doc/src/sgml/legal.sgml b/doc/src/sgml/legal.sgml index 904512f9f4ab0..f3d31b002aa0b 100644 --- a/doc/src/sgml/legal.sgml +++ b/doc/src/sgml/legal.sgml @@ -1,9 +1,9 @@ -2020 +2021 - 1996–2020 + 1996–2021 The PostgreSQL Global Development Group @@ -11,7 +11,7 @@ Legal Notice - PostgreSQL is Copyright © 1996–2020 + PostgreSQL is Copyright © 1996–2021 by the PostgreSQL Global Development Group. diff --git a/doc/src/sgml/lobj.sgml b/doc/src/sgml/lobj.sgml index 6329cf0796beb..413eda50af370 100644 --- a/doc/src/sgml/lobj.sgml +++ b/doc/src/sgml/lobj.sgml @@ -717,7 +717,7 @@ SELECT lo_export(image.raster, '/tmp/motd') FROM image * testlo.c * test using large objects with libpq * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/Makefile b/src/backend/Makefile index 9706a95848842..9672e2cb43aa4 100644 --- a/src/backend/Makefile +++ b/src/backend/Makefile @@ -2,7 +2,7 @@ # # Makefile for the postgres backend # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/backend/Makefile diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 1f72562c60307..58fe109d2d9c5 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -4,7 +4,7 @@ * * See src/backend/access/brin/README for details. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 986f76bd9b067..12e5bddd1fc1c 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -16,7 +16,7 @@ * writing is the INET type, where IPv6 values cannot be merged with IPv4 * values. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 4b5d6a7213520..2ffbd9bf0ddba 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -2,7 +2,7 @@ * brin_minmax.c * Implementation of Min/Max opclass for BRIN * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/brin/brin_pageops.c b/src/backend/access/brin/brin_pageops.c index 87de0b855b5e3..df9ffc2fb86e9 100644 --- a/src/backend/access/brin/brin_pageops.c +++ b/src/backend/access/brin/brin_pageops.c @@ -2,7 +2,7 @@ * brin_pageops.c * Page-handling routines for BRIN indexes * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/brin/brin_revmap.c b/src/backend/access/brin/brin_revmap.c index 35746714a7c4f..bab2a88ee3f3c 100644 --- a/src/backend/access/brin/brin_revmap.c +++ b/src/backend/access/brin/brin_revmap.c @@ -12,7 +12,7 @@ * the metapage. When the revmap needs to be expanded, all tuples on the * regular BRIN page at that block (if any) are moved out of the way. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/brin/brin_tuple.c b/src/backend/access/brin/brin_tuple.c index 17e50de530982..a7eb1c9473af7 100644 --- a/src/backend/access/brin/brin_tuple.c +++ b/src/backend/access/brin/brin_tuple.c @@ -23,7 +23,7 @@ * Note the size of the null bitmask may not be the same as that of the * datum array. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/brin/brin_validate.c b/src/backend/access/brin/brin_validate.c index fb0615463e0f5..6d4253c05e205 100644 --- a/src/backend/access/brin/brin_validate.c +++ b/src/backend/access/brin/brin_validate.c @@ -3,7 +3,7 @@ * brin_validate.c * Opclass validator for BRIN. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/brin/brin_xlog.c b/src/backend/access/brin/brin_xlog.c index da47603e2588a..39dc130e16240 100644 --- a/src/backend/access/brin/brin_xlog.c +++ b/src/backend/access/brin/brin_xlog.c @@ -2,7 +2,7 @@ * brin_xlog.c * XLog replay routines for BRIN indexes * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/common/attmap.c b/src/backend/access/common/attmap.c index 2cd16d7eafb16..32405f8610636 100644 --- a/src/backend/access/common/attmap.c +++ b/src/backend/access/common/attmap.c @@ -10,7 +10,7 @@ * columns in a different order, taking into account dropped columns. * They are also used by the tuple conversion routines in tupconvert.c. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/common/bufmask.c b/src/backend/access/common/bufmask.c index 4bdb1848ad24b..003a0befb25d8 100644 --- a/src/backend/access/common/bufmask.c +++ b/src/backend/access/common/bufmask.c @@ -5,7 +5,7 @@ * in a page which can be different when the WAL is generated * and when the WAL is applied. * - * Portions Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2016-2021, PostgreSQL Global Development Group * * Contains common routines required for masking a page. * diff --git a/src/backend/access/common/detoast.c b/src/backend/access/common/detoast.c index 44c37edcbb45a..b118f4a7146b6 100644 --- a/src/backend/access/common/detoast.c +++ b/src/backend/access/common/detoast.c @@ -3,7 +3,7 @@ * detoast.c * Retrieve compressed or external variable size attributes. * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/access/common/detoast.c diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c index f08221eed3c9a..24a27e387de0c 100644 --- a/src/backend/access/common/heaptuple.c +++ b/src/backend/access/common/heaptuple.c @@ -45,7 +45,7 @@ * and we'd like to still refer to them via C struct offsets. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/common/indextuple.c b/src/backend/access/common/indextuple.c index 634016b9b7c04..b72a1384973d1 100644 --- a/src/backend/access/common/indextuple.c +++ b/src/backend/access/common/indextuple.c @@ -4,7 +4,7 @@ * This file contains index tuple accessor and mutator routines, * as well as various tuple utilities. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/common/printsimple.c b/src/backend/access/common/printsimple.c index df27700df92a2..93c3c4f66a837 100644 --- a/src/backend/access/common/printsimple.c +++ b/src/backend/access/common/printsimple.c @@ -8,7 +8,7 @@ * doesn't handle standalone backends or protocol versions other than * 3.0, because we don't need such handling for current applications. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/common/printtup.c b/src/backend/access/common/printtup.c index dd1bac0aa9e5b..4468480e9b36a 100644 --- a/src/backend/access/common/printtup.c +++ b/src/backend/access/common/printtup.c @@ -5,7 +5,7 @@ * clients and standalone backends are supported here). * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/common/relation.c b/src/backend/access/common/relation.c index 641da9dbd6cfe..632d13c1eafe4 100644 --- a/src/backend/access/common/relation.c +++ b/src/backend/access/common/relation.c @@ -3,7 +3,7 @@ * relation.c * Generic relation related routines. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 8ccc228a8cc04..c687d3ee9ef42 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -3,7 +3,7 @@ * reloptions.c * Core support for relation options (pg_class.reloptions) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/common/scankey.c b/src/backend/access/common/scankey.c index 3c4bd53f3f869..bf33c50d959a5 100644 --- a/src/backend/access/common/scankey.c +++ b/src/backend/access/common/scankey.c @@ -3,7 +3,7 @@ * scankey.c * scan key support code * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/common/session.c b/src/backend/access/common/session.c index 0ec61d48a2d1f..61b3206befb95 100644 --- a/src/backend/access/common/session.c +++ b/src/backend/access/common/session.c @@ -12,7 +12,7 @@ * Currently this infrastructure is used to share: * - typemod registry for ephemeral row-types, i.e. BlessTupleDesc etc. * - * Portions Copyright (c) 2017-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2017-2021, PostgreSQL Global Development Group * * src/backend/access/common/session.c * diff --git a/src/backend/access/common/syncscan.c b/src/backend/access/common/syncscan.c index c1ce156902bef..b7a28af4ad822 100644 --- a/src/backend/access/common/syncscan.c +++ b/src/backend/access/common/syncscan.c @@ -36,7 +36,7 @@ * ss_report_location - update current scan location * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c index 25a81e5ec655d..70a9f771884fb 100644 --- a/src/backend/access/common/toast_internals.c +++ b/src/backend/access/common/toast_internals.c @@ -3,7 +3,7 @@ * toast_internals.c * Functions for internal use by the TOAST system. * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/access/common/toast_internals.c diff --git a/src/backend/access/common/tupconvert.c b/src/backend/access/common/tupconvert.c index 3cb0cbefaa36c..4229c9bf76425 100644 --- a/src/backend/access/common/tupconvert.c +++ b/src/backend/access/common/tupconvert.c @@ -7,7 +7,7 @@ * equivalent but might have columns in a different order or different sets of * dropped columns. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c index 30c30cf3a2e44..902f59440cd07 100644 --- a/src/backend/access/common/tupdesc.c +++ b/src/backend/access/common/tupdesc.c @@ -3,7 +3,7 @@ * tupdesc.c * POSTGRES tuple descriptor support code * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/gin/ginarrayproc.c b/src/backend/access/gin/ginarrayproc.c index 3a6d54b38ce1f..bf73e32932e0c 100644 --- a/src/backend/access/gin/ginarrayproc.c +++ b/src/backend/access/gin/ginarrayproc.c @@ -4,7 +4,7 @@ * support functions for GIN's indexing of any array * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gin/ginbtree.c b/src/backend/access/gin/ginbtree.c index 82788a5c367a9..482cf10877cd2 100644 --- a/src/backend/access/gin/ginbtree.c +++ b/src/backend/access/gin/ginbtree.c @@ -4,7 +4,7 @@ * page utilities routines for the postgres inverted index access method. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gin/ginbulk.c b/src/backend/access/gin/ginbulk.c index 9008c125fe998..4c5067ccf96e2 100644 --- a/src/backend/access/gin/ginbulk.c +++ b/src/backend/access/gin/ginbulk.c @@ -4,7 +4,7 @@ * routines for fast build of inverted index * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gin/gindatapage.c b/src/backend/access/gin/gindatapage.c index 7a2690e97f2ca..06c05865435f0 100644 --- a/src/backend/access/gin/gindatapage.c +++ b/src/backend/access/gin/gindatapage.c @@ -4,7 +4,7 @@ * routines for handling GIN posting tree pages. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gin/ginentrypage.c b/src/backend/access/gin/ginentrypage.c index af14baf93cee8..29c36bc0678e1 100644 --- a/src/backend/access/gin/ginentrypage.c +++ b/src/backend/access/gin/ginentrypage.c @@ -4,7 +4,7 @@ * routines for handling GIN entry tree pages. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gin/ginfast.c b/src/backend/access/gin/ginfast.c index 2e41b34d8d518..e0d99409461c3 100644 --- a/src/backend/access/gin/ginfast.c +++ b/src/backend/access/gin/ginfast.c @@ -7,7 +7,7 @@ * transfer pending entries into the regular index structure. This * wins because bulk insertion is much more efficient than retail. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gin/ginget.c b/src/backend/access/gin/ginget.c index 2cfccdedcf59f..03191e016ce5c 100644 --- a/src/backend/access/gin/ginget.c +++ b/src/backend/access/gin/ginget.c @@ -4,7 +4,7 @@ * fetch tuples from a GIN scan. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c index 77433dc8a41e7..29546ce0ae48d 100644 --- a/src/backend/access/gin/gininsert.c +++ b/src/backend/access/gin/gininsert.c @@ -4,7 +4,7 @@ * insert routines for the postgres inverted index access method. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gin/ginlogic.c b/src/backend/access/gin/ginlogic.c index bcbc26efdb674..6bf3288f5b9ed 100644 --- a/src/backend/access/gin/ginlogic.c +++ b/src/backend/access/gin/ginlogic.c @@ -24,7 +24,7 @@ * is used for.) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gin/ginpostinglist.c b/src/backend/access/gin/ginpostinglist.c index 461ec93fdef51..216b2b9a2c3f5 100644 --- a/src/backend/access/gin/ginpostinglist.c +++ b/src/backend/access/gin/ginpostinglist.c @@ -4,7 +4,7 @@ * routines for dealing with posting lists. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gin/ginscan.c b/src/backend/access/gin/ginscan.c index 0a685bdbfc653..55e2d49fd7224 100644 --- a/src/backend/access/gin/ginscan.c +++ b/src/backend/access/gin/ginscan.c @@ -4,7 +4,7 @@ * routines to manage scans of inverted index relations * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c index ef9b56fd363af..6b9b04cf429e3 100644 --- a/src/backend/access/gin/ginutil.c +++ b/src/backend/access/gin/ginutil.c @@ -4,7 +4,7 @@ * Utility routines for the Postgres inverted index access method. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gin/ginvacuum.c b/src/backend/access/gin/ginvacuum.c index 0935a6d9e53d6..35b85a9bff0c0 100644 --- a/src/backend/access/gin/ginvacuum.c +++ b/src/backend/access/gin/ginvacuum.c @@ -4,7 +4,7 @@ * delete & vacuum routines for the postgres GIN * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gin/ginvalidate.c b/src/backend/access/gin/ginvalidate.c index 60ce1ae10663b..d2510daadb38c 100644 --- a/src/backend/access/gin/ginvalidate.c +++ b/src/backend/access/gin/ginvalidate.c @@ -3,7 +3,7 @@ * ginvalidate.c * Opclass validator for GIN. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gin/ginxlog.c b/src/backend/access/gin/ginxlog.c index 9f8640565bf92..09ce4d6a5ba58 100644 --- a/src/backend/access/gin/ginxlog.c +++ b/src/backend/access/gin/ginxlog.c @@ -4,7 +4,7 @@ * WAL replay logic for inverted index. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index 3f2b416ce1cef..e4b251a58fb57 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -4,7 +4,7 @@ * interface routines for the postgres GiST index access method. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9d3fa9c3b75b2..1054f6f1f2e34 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -22,7 +22,7 @@ * tuples (unless buffering mode is disabled). * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gist/gistbuildbuffers.c b/src/backend/access/gist/gistbuildbuffers.c index 217c199a14709..95cc3348442b9 100644 --- a/src/backend/access/gist/gistbuildbuffers.c +++ b/src/backend/access/gist/gistbuildbuffers.c @@ -4,7 +4,7 @@ * node buffer management functions for GiST buffering build algorithm. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c index a4edcc77e96f0..c8f7e781c6c36 100644 --- a/src/backend/access/gist/gistget.c +++ b/src/backend/access/gist/gistget.c @@ -4,7 +4,7 @@ * fetch tuples from a GiST scan. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c index 784807c636ba0..b8a39cd543997 100644 --- a/src/backend/access/gist/gistproc.c +++ b/src/backend/access/gist/gistproc.c @@ -7,7 +7,7 @@ * This gives R-tree behavior, with Guttman's poly-time split algorithm. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gist/gistscan.c b/src/backend/access/gist/gistscan.c index b8aa77f70feac..61e92cf0f5dfb 100644 --- a/src/backend/access/gist/gistscan.c +++ b/src/backend/access/gist/gistscan.c @@ -4,7 +4,7 @@ * routines to manage scans on GiST index relations * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gist/gistsplit.c b/src/backend/access/gist/gistsplit.c index 1bf48b4e14721..526ed1218e60f 100644 --- a/src/backend/access/gist/gistsplit.c +++ b/src/backend/access/gist/gistsplit.c @@ -15,7 +15,7 @@ * gistSplitByKey() is the entry point to this file. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c index 615b5ade23310..cf53dad474372 100644 --- a/src/backend/access/gist/gistutil.c +++ b/src/backend/access/gist/gistutil.c @@ -4,7 +4,7 @@ * utilities routines for the postgres GiST index access method. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c index a9c616c772454..94a7e12763931 100644 --- a/src/backend/access/gist/gistvacuum.c +++ b/src/backend/access/gist/gistvacuum.c @@ -4,7 +4,7 @@ * vacuuming routines for the postgres GiST index access method. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gist/gistvalidate.c b/src/backend/access/gist/gistvalidate.c index e600015b12d6e..7d83b1143c665 100644 --- a/src/backend/access/gist/gistvalidate.c +++ b/src/backend/access/gist/gistvalidate.c @@ -3,7 +3,7 @@ * gistvalidate.c * Opclass validator for GiST. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/gist/gistxlog.c b/src/backend/access/gist/gistxlog.c index 91b3e111820d2..c1d4b5d4f2321 100644 --- a/src/backend/access/gist/gistxlog.c +++ b/src/backend/access/gist/gistxlog.c @@ -4,7 +4,7 @@ * WAL replay logic for GiST. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c index 7c9ccf446c8a4..263ae23ab0ad9 100644 --- a/src/backend/access/hash/hash.c +++ b/src/backend/access/hash/hash.c @@ -3,7 +3,7 @@ * hash.c * Implementation of Margo Seltzer's Hashing package for postgres. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/hash/hash_xlog.c b/src/backend/access/hash/hash_xlog.c index 3c606776624a6..02d9e6cdfd989 100644 --- a/src/backend/access/hash/hash_xlog.c +++ b/src/backend/access/hash/hash_xlog.c @@ -4,7 +4,7 @@ * WAL replay logic for hash index. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/hash/hashfunc.c b/src/backend/access/hash/hashfunc.c index a8498226e32d7..db20d9d1c1456 100644 --- a/src/backend/access/hash/hashfunc.c +++ b/src/backend/access/hash/hashfunc.c @@ -3,7 +3,7 @@ * hashfunc.c * Support functions for hash access method. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/hash/hashinsert.c b/src/backend/access/hash/hashinsert.c index 2ebe671967ba2..d254a00b6ac37 100644 --- a/src/backend/access/hash/hashinsert.c +++ b/src/backend/access/hash/hashinsert.c @@ -3,7 +3,7 @@ * hashinsert.c * Item insertion in hash tables for Postgres. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/hash/hashovfl.c b/src/backend/access/hash/hashovfl.c index 00f0a94011628..1ff2e0c18ee0f 100644 --- a/src/backend/access/hash/hashovfl.c +++ b/src/backend/access/hash/hashovfl.c @@ -3,7 +3,7 @@ * hashovfl.c * Overflow page management code for the Postgres hash access method * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/hash/hashpage.c b/src/backend/access/hash/hashpage.c index c77a189907edc..49a9867787689 100644 --- a/src/backend/access/hash/hashpage.c +++ b/src/backend/access/hash/hashpage.c @@ -3,7 +3,7 @@ * hashpage.c * Hash table page management code for the Postgres hash access method * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/hash/hashsearch.c b/src/backend/access/hash/hashsearch.c index 995498e48da1e..2ffa28e8f7711 100644 --- a/src/backend/access/hash/hashsearch.c +++ b/src/backend/access/hash/hashsearch.c @@ -3,7 +3,7 @@ * hashsearch.c * search code for postgres hash tables * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/hash/hashsort.c b/src/backend/access/hash/hashsort.c index 2c7b5857b530a..3ce42483ed199 100644 --- a/src/backend/access/hash/hashsort.c +++ b/src/backend/access/hash/hashsort.c @@ -14,7 +14,7 @@ * plenty of locality of access. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/hash/hashutil.c b/src/backend/access/hash/hashutil.c index eb510be3324ce..519872850e0b7 100644 --- a/src/backend/access/hash/hashutil.c +++ b/src/backend/access/hash/hashutil.c @@ -3,7 +3,7 @@ * hashutil.c * Utility code for Postgres hash implementation. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/hash/hashvalidate.c b/src/backend/access/hash/hashvalidate.c index 0fe97e8276b63..8462540017661 100644 --- a/src/backend/access/hash/hashvalidate.c +++ b/src/backend/access/hash/hashvalidate.c @@ -3,7 +3,7 @@ * hashvalidate.c * Opclass validator for hash. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 26c2006f23c0b..53e997cd5536e 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -3,7 +3,7 @@ * heapam.c * heap access method code * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c index 3eea215b85274..10ddde4ecf949 100644 --- a/src/backend/access/heap/heapam_handler.c +++ b/src/backend/access/heap/heapam_handler.c @@ -3,7 +3,7 @@ * heapam_handler.c * heap table access method code * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/heap/heapam_visibility.c b/src/backend/access/heap/heapam_visibility.c index 80bd4940769c1..65f91c82599cf 100644 --- a/src/backend/access/heap/heapam_visibility.c +++ b/src/backend/access/heap/heapam_visibility.c @@ -52,7 +52,7 @@ * HeapTupleSatisfiesAny() * all tuples are visible * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/heap/heaptoast.c b/src/backend/access/heap/heaptoast.c index 584f101dd987b..55bbe1d584760 100644 --- a/src/backend/access/heap/heaptoast.c +++ b/src/backend/access/heap/heaptoast.c @@ -4,7 +4,7 @@ * Heap-specific definitions for external and compressed storage * of variable size attributes. * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/access/heap/hio.c b/src/backend/access/heap/hio.c index ca357410a293c..fac3b8e9ff287 100644 --- a/src/backend/access/heap/hio.c +++ b/src/backend/access/heap/hio.c @@ -3,7 +3,7 @@ * hio.c * POSTGRES heap access method input/output code. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c index 9e04bc712c94f..e3a716a2a2f24 100644 --- a/src/backend/access/heap/pruneheap.c +++ b/src/backend/access/heap/pruneheap.c @@ -3,7 +3,7 @@ * pruneheap.c * heap page pruning and HOT-chain management code * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c index 65942cc4281b3..29ffe4067042c 100644 --- a/src/backend/access/heap/rewriteheap.c +++ b/src/backend/access/heap/rewriteheap.c @@ -92,7 +92,7 @@ * heap's TOAST table will go through the normal bufmgr. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994-5, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c index 25f2d5df1b8c7..f3d2265fad7e4 100644 --- a/src/backend/access/heap/vacuumlazy.c +++ b/src/backend/access/heap/vacuumlazy.c @@ -37,7 +37,7 @@ * parallel mode we update the index statistics after exiting from the * parallel mode. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/heap/visibilitymap.c b/src/backend/access/heap/visibilitymap.c index b1072183bcd6d..e198df65d8276 100644 --- a/src/backend/access/heap/visibilitymap.c +++ b/src/backend/access/heap/visibilitymap.c @@ -3,7 +3,7 @@ * visibilitymap.c * bitmap for tracking visibility of heap tuples * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/index/amapi.c b/src/backend/access/index/amapi.c index 4e3d7b030ebd3..d30bc435146db 100644 --- a/src/backend/access/index/amapi.c +++ b/src/backend/access/index/amapi.c @@ -3,7 +3,7 @@ * amapi.c * Support routines for API for Postgres index access methods. * - * Copyright (c) 2015-2020, PostgreSQL Global Development Group + * Copyright (c) 2015-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/access/index/amvalidate.c b/src/backend/access/index/amvalidate.c index b58c34aa5f2fd..9dd0ae663ba14 100644 --- a/src/backend/access/index/amvalidate.c +++ b/src/backend/access/index/amvalidate.c @@ -4,7 +4,7 @@ * Support routines for index access methods' amvalidate and * amadjustmembers functions. * - * Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Copyright (c) 2016-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/access/index/genam.c b/src/backend/access/index/genam.c index e3164e674a7bc..e9877906e56d9 100644 --- a/src/backend/access/index/genam.c +++ b/src/backend/access/index/genam.c @@ -3,7 +3,7 @@ * genam.c * general index access method routines * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c index 3fb8688f8f4c1..c2b98e8a727d1 100644 --- a/src/backend/access/index/indexam.c +++ b/src/backend/access/index/indexam.c @@ -3,7 +3,7 @@ * indexam.c * general index access method routines * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/nbtree/nbtcompare.c b/src/backend/access/nbtree/nbtcompare.c index fdaa7a335fb98..7ac73cb8c2d53 100644 --- a/src/backend/access/nbtree/nbtcompare.c +++ b/src/backend/access/nbtree/nbtcompare.c @@ -3,7 +3,7 @@ * nbtcompare.c * Comparison functions for btree access method. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/nbtree/nbtdedup.c b/src/backend/access/nbtree/nbtdedup.c index 9e535124c4652..54fd7658e446e 100644 --- a/src/backend/access/nbtree/nbtdedup.c +++ b/src/backend/access/nbtree/nbtdedup.c @@ -3,7 +3,7 @@ * nbtdedup.c * Deduplicate items in Postgres btrees. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c index dde43b1415ac1..d7566ba082fec 100644 --- a/src/backend/access/nbtree/nbtinsert.c +++ b/src/backend/access/nbtree/nbtinsert.c @@ -3,7 +3,7 @@ * nbtinsert.c * Item insertion in Lehman and Yao btrees for Postgres. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c index 793434c026ca0..89eb66a8a60a0 100644 --- a/src/backend/access/nbtree/nbtpage.c +++ b/src/backend/access/nbtree/nbtpage.c @@ -4,7 +4,7 @@ * BTree-specific page management code for the Postgres btree access * method. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index 0abec1079830d..ba79a7f3e9e2c 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -8,7 +8,7 @@ * This file contains only the public interface routines. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c index 8f6575fdf15c2..2e3bda8171d77 100644 --- a/src/backend/access/nbtree/nbtsearch.c +++ b/src/backend/access/nbtree/nbtsearch.c @@ -4,7 +4,7 @@ * Search code for postgres btrees. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c index 8730de25ed719..c904fc8ef7bd3 100644 --- a/src/backend/access/nbtree/nbtsort.c +++ b/src/backend/access/nbtree/nbtsort.c @@ -34,7 +34,7 @@ * This code isn't concerned about the FSM at all. The caller is responsible * for initializing that. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/nbtree/nbtsplitloc.c b/src/backend/access/nbtree/nbtsplitloc.c index ef6dd1cf1920b..3485e93ef6470 100644 --- a/src/backend/access/nbtree/nbtsplitloc.c +++ b/src/backend/access/nbtree/nbtsplitloc.c @@ -3,7 +3,7 @@ * nbtsplitloc.c * Choose split point code for Postgres btree implementation. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c index 2f5f14e527dd0..d5243107239bb 100644 --- a/src/backend/access/nbtree/nbtutils.c +++ b/src/backend/access/nbtree/nbtutils.c @@ -3,7 +3,7 @@ * nbtutils.c * Utility code for Postgres btree implementation. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/nbtree/nbtvalidate.c b/src/backend/access/nbtree/nbtvalidate.c index 5be728ad07cff..7acb64ee69895 100644 --- a/src/backend/access/nbtree/nbtvalidate.c +++ b/src/backend/access/nbtree/nbtvalidate.c @@ -3,7 +3,7 @@ * nbtvalidate.c * Opclass validator for btree. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/nbtree/nbtxlog.c b/src/backend/access/nbtree/nbtxlog.c index 5135b800af6d3..45313d924c1fc 100644 --- a/src/backend/access/nbtree/nbtxlog.c +++ b/src/backend/access/nbtree/nbtxlog.c @@ -4,7 +4,7 @@ * WAL replay logic for btrees. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/rmgrdesc/brindesc.c b/src/backend/access/rmgrdesc/brindesc.c index 0dc56e5549614..b6265a49bc060 100644 --- a/src/backend/access/rmgrdesc/brindesc.c +++ b/src/backend/access/rmgrdesc/brindesc.c @@ -3,7 +3,7 @@ * brindesc.c * rmgr descriptor routines for BRIN indexes * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/clogdesc.c b/src/backend/access/rmgrdesc/clogdesc.c index fb510e4cd191a..b12f43a1bba28 100644 --- a/src/backend/access/rmgrdesc/clogdesc.c +++ b/src/backend/access/rmgrdesc/clogdesc.c @@ -3,7 +3,7 @@ * clogdesc.c * rmgr descriptor routines for access/transam/clog.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/committsdesc.c b/src/backend/access/rmgrdesc/committsdesc.c index c8bdae761abc1..7ebd3d35efd02 100644 --- a/src/backend/access/rmgrdesc/committsdesc.c +++ b/src/backend/access/rmgrdesc/committsdesc.c @@ -3,7 +3,7 @@ * committsdesc.c * rmgr descriptor routines for access/transam/commit_ts.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/dbasedesc.c b/src/backend/access/rmgrdesc/dbasedesc.c index 47580feaeae41..26609845aac65 100644 --- a/src/backend/access/rmgrdesc/dbasedesc.c +++ b/src/backend/access/rmgrdesc/dbasedesc.c @@ -3,7 +3,7 @@ * dbasedesc.c * rmgr descriptor routines for commands/dbcommands.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/genericdesc.c b/src/backend/access/rmgrdesc/genericdesc.c index f0fd4286195e1..7242d0d214173 100644 --- a/src/backend/access/rmgrdesc/genericdesc.c +++ b/src/backend/access/rmgrdesc/genericdesc.c @@ -4,7 +4,7 @@ * rmgr descriptor routines for access/transam/generic_xlog.c * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/rmgrdesc/genericdesc.c diff --git a/src/backend/access/rmgrdesc/gindesc.c b/src/backend/access/rmgrdesc/gindesc.c index 9ab0d8e1f7e7d..ee9e69cdd094e 100644 --- a/src/backend/access/rmgrdesc/gindesc.c +++ b/src/backend/access/rmgrdesc/gindesc.c @@ -3,7 +3,7 @@ * gindesc.c * rmgr descriptor routines for access/transam/gin/ginxlog.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/gistdesc.c b/src/backend/access/rmgrdesc/gistdesc.c index de309fb1227e8..8ae31126ebf99 100644 --- a/src/backend/access/rmgrdesc/gistdesc.c +++ b/src/backend/access/rmgrdesc/gistdesc.c @@ -3,7 +3,7 @@ * gistdesc.c * rmgr descriptor routines for access/gist/gistxlog.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/hashdesc.c b/src/backend/access/rmgrdesc/hashdesc.c index f7728850419c0..55de27840d98d 100644 --- a/src/backend/access/rmgrdesc/hashdesc.c +++ b/src/backend/access/rmgrdesc/hashdesc.c @@ -3,7 +3,7 @@ * hashdesc.c * rmgr descriptor routines for access/hash/hash.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/heapdesc.c b/src/backend/access/rmgrdesc/heapdesc.c index 3c16e6ef1f211..871c7a155e8c5 100644 --- a/src/backend/access/rmgrdesc/heapdesc.c +++ b/src/backend/access/rmgrdesc/heapdesc.c @@ -3,7 +3,7 @@ * heapdesc.c * rmgr descriptor routines for access/heap/heapam.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/logicalmsgdesc.c b/src/backend/access/rmgrdesc/logicalmsgdesc.c index 83ab93a24be9e..d64ce2e7eff21 100644 --- a/src/backend/access/rmgrdesc/logicalmsgdesc.c +++ b/src/backend/access/rmgrdesc/logicalmsgdesc.c @@ -3,7 +3,7 @@ * logicalmsgdesc.c * rmgr descriptor routines for replication/logical/message.c * - * Portions Copyright (c) 2015-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2015-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/access/rmgrdesc/mxactdesc.c b/src/backend/access/rmgrdesc/mxactdesc.c index 4dd6d7d1f4f17..8c37690e659d7 100644 --- a/src/backend/access/rmgrdesc/mxactdesc.c +++ b/src/backend/access/rmgrdesc/mxactdesc.c @@ -3,7 +3,7 @@ * mxactdesc.c * rmgr descriptor routines for access/transam/multixact.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/nbtdesc.c b/src/backend/access/rmgrdesc/nbtdesc.c index e099107f91ec9..4c4af9fce012c 100644 --- a/src/backend/access/rmgrdesc/nbtdesc.c +++ b/src/backend/access/rmgrdesc/nbtdesc.c @@ -3,7 +3,7 @@ * nbtdesc.c * rmgr descriptor routines for access/nbtree/nbtxlog.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/relmapdesc.c b/src/backend/access/rmgrdesc/relmapdesc.c index 8a8d59495675e..2f9d4f54ba8b4 100644 --- a/src/backend/access/rmgrdesc/relmapdesc.c +++ b/src/backend/access/rmgrdesc/relmapdesc.c @@ -3,7 +3,7 @@ * relmapdesc.c * rmgr descriptor routines for utils/cache/relmapper.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/replorigindesc.c b/src/backend/access/rmgrdesc/replorigindesc.c index 19e14f910bafd..2e29ecc6d576c 100644 --- a/src/backend/access/rmgrdesc/replorigindesc.c +++ b/src/backend/access/rmgrdesc/replorigindesc.c @@ -3,7 +3,7 @@ * replorigindesc.c * rmgr descriptor routines for replication/logical/origin.c * - * Portions Copyright (c) 2015-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2015-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/access/rmgrdesc/seqdesc.c b/src/backend/access/rmgrdesc/seqdesc.c index 1cb1e91a3e952..0bd294687b734 100644 --- a/src/backend/access/rmgrdesc/seqdesc.c +++ b/src/backend/access/rmgrdesc/seqdesc.c @@ -3,7 +3,7 @@ * seqdesc.c * rmgr descriptor routines for commands/sequence.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/smgrdesc.c b/src/backend/access/rmgrdesc/smgrdesc.c index a7c0cb1bc3154..7755553d57f5f 100644 --- a/src/backend/access/rmgrdesc/smgrdesc.c +++ b/src/backend/access/rmgrdesc/smgrdesc.c @@ -3,7 +3,7 @@ * smgrdesc.c * rmgr descriptor routines for catalog/storage.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/spgdesc.c b/src/backend/access/rmgrdesc/spgdesc.c index a5478e3fb45f1..3610dc1b46c89 100644 --- a/src/backend/access/rmgrdesc/spgdesc.c +++ b/src/backend/access/rmgrdesc/spgdesc.c @@ -3,7 +3,7 @@ * spgdesc.c * rmgr descriptor routines for access/spgist/spgxlog.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/standbydesc.c b/src/backend/access/rmgrdesc/standbydesc.c index 1ce2664014630..01ee7ac6d2ca5 100644 --- a/src/backend/access/rmgrdesc/standbydesc.c +++ b/src/backend/access/rmgrdesc/standbydesc.c @@ -3,7 +3,7 @@ * standbydesc.c * rmgr descriptor routines for storage/ipc/standby.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/tblspcdesc.c b/src/backend/access/rmgrdesc/tblspcdesc.c index 2cd361b2c0025..cb356eaa48f15 100644 --- a/src/backend/access/rmgrdesc/tblspcdesc.c +++ b/src/backend/access/rmgrdesc/tblspcdesc.c @@ -3,7 +3,7 @@ * tblspcdesc.c * rmgr descriptor routines for commands/tablespace.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/xactdesc.c b/src/backend/access/rmgrdesc/xactdesc.c index addd95faec140..c6fb1ec572794 100644 --- a/src/backend/access/rmgrdesc/xactdesc.c +++ b/src/backend/access/rmgrdesc/xactdesc.c @@ -3,7 +3,7 @@ * xactdesc.c * rmgr descriptor routines for access/transam/xact.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/rmgrdesc/xlogdesc.c b/src/backend/access/rmgrdesc/xlogdesc.c index 3200f777f5a37..92cc7ea073517 100644 --- a/src/backend/access/rmgrdesc/xlogdesc.c +++ b/src/backend/access/rmgrdesc/xlogdesc.c @@ -3,7 +3,7 @@ * xlogdesc.c * rmgr descriptor routines for access/transam/xlog.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/spgist/spgdoinsert.c b/src/backend/access/spgist/spgdoinsert.c index 934d65b89f2d0..7bd269fd2a0e2 100644 --- a/src/backend/access/spgist/spgdoinsert.c +++ b/src/backend/access/spgist/spgdoinsert.c @@ -4,7 +4,7 @@ * implementation of insert algorithm * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/spgist/spginsert.c b/src/backend/access/spgist/spginsert.c index e4508a2b923a2..2e1d8a33d1f7d 100644 --- a/src/backend/access/spgist/spginsert.c +++ b/src/backend/access/spgist/spginsert.c @@ -5,7 +5,7 @@ * * All the actual insertion logic is in spgdoinsert.c. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/spgist/spgkdtreeproc.c b/src/backend/access/spgist/spgkdtreeproc.c index 6581238cef2f9..d9b3f6a0ea7e6 100644 --- a/src/backend/access/spgist/spgkdtreeproc.c +++ b/src/backend/access/spgist/spgkdtreeproc.c @@ -4,7 +4,7 @@ * implementation of k-d tree over points for SP-GiST * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/spgist/spgproc.c b/src/backend/access/spgist/spgproc.c index 94454f6b70d4f..1bad5d6c06d2e 100644 --- a/src/backend/access/spgist/spgproc.c +++ b/src/backend/access/spgist/spgproc.c @@ -4,7 +4,7 @@ * Common supporting procedures for SP-GiST opclasses. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/spgist/spgquadtreeproc.c b/src/backend/access/spgist/spgquadtreeproc.c index 249b3828fee23..a52d924fdc92c 100644 --- a/src/backend/access/spgist/spgquadtreeproc.c +++ b/src/backend/access/spgist/spgquadtreeproc.c @@ -4,7 +4,7 @@ * implementation of quad tree over points for SP-GiST * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/spgist/spgscan.c b/src/backend/access/spgist/spgscan.c index 4d506bfb9a9b8..20e67c3f7d1eb 100644 --- a/src/backend/access/spgist/spgscan.c +++ b/src/backend/access/spgist/spgscan.c @@ -4,7 +4,7 @@ * routines for scanning SP-GiST indexes * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/spgist/spgtextproc.c b/src/backend/access/spgist/spgtextproc.c index b5ec81937c4b9..f340555336386 100644 --- a/src/backend/access/spgist/spgtextproc.c +++ b/src/backend/access/spgist/spgtextproc.c @@ -29,7 +29,7 @@ * No new entries ever get pushed into a -2-labeled child, either. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/spgist/spgutils.c b/src/backend/access/spgist/spgutils.c index 64d3ba82887bd..d8b18150612d0 100644 --- a/src/backend/access/spgist/spgutils.c +++ b/src/backend/access/spgist/spgutils.c @@ -4,7 +4,7 @@ * various support functions for SP-GiST * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/spgist/spgvacuum.c b/src/backend/access/spgist/spgvacuum.c index e1c58933f979b..0d02a02222e9e 100644 --- a/src/backend/access/spgist/spgvacuum.c +++ b/src/backend/access/spgist/spgvacuum.c @@ -4,7 +4,7 @@ * vacuum for SP-GiST * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/spgist/spgvalidate.c b/src/backend/access/spgist/spgvalidate.c index d4f5841e2656b..8bc3889a4de2a 100644 --- a/src/backend/access/spgist/spgvalidate.c +++ b/src/backend/access/spgist/spgvalidate.c @@ -3,7 +3,7 @@ * spgvalidate.c * Opclass validator for SP-GiST. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/spgist/spgxlog.c b/src/backend/access/spgist/spgxlog.c index 999d0ca15d568..d40c7b58776d7 100644 --- a/src/backend/access/spgist/spgxlog.c +++ b/src/backend/access/spgist/spgxlog.c @@ -4,7 +4,7 @@ * WAL replay logic for SP-GiST * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/table/table.c b/src/backend/access/table/table.c index 7c29091e6c193..545007e6ed480 100644 --- a/src/backend/access/table/table.c +++ b/src/backend/access/table/table.c @@ -3,7 +3,7 @@ * table.c * Generic routines for table related code. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/table/tableam.c b/src/backend/access/table/tableam.c index 6438c457161ac..5ea5bdd810433 100644 --- a/src/backend/access/table/tableam.c +++ b/src/backend/access/table/tableam.c @@ -3,7 +3,7 @@ * tableam.c * Table access method routines too big to be inline functions. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/table/tableamapi.c b/src/backend/access/table/tableamapi.c index 58de0743ba05d..d5a859ea88213 100644 --- a/src/backend/access/table/tableamapi.c +++ b/src/backend/access/table/tableamapi.c @@ -3,7 +3,7 @@ * tableamapi.c * Support routines for API for Postgres table access methods * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/table/tableamapi.c diff --git a/src/backend/access/table/toast_helper.c b/src/backend/access/table/toast_helper.c index 739b6ae9900ec..fb36151ce55f2 100644 --- a/src/backend/access/table/toast_helper.c +++ b/src/backend/access/table/toast_helper.c @@ -4,7 +4,7 @@ * Helper functions for table AMs implementing compressed or * out-of-line storage of varlena attributes. * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/access/table/toast_helper.c diff --git a/src/backend/access/tablesample/bernoulli.c b/src/backend/access/tablesample/bernoulli.c index 606730d6cbe85..ae6e4f581145a 100644 --- a/src/backend/access/tablesample/bernoulli.c +++ b/src/backend/access/tablesample/bernoulli.c @@ -13,7 +13,7 @@ * cutoff value computed from the selection probability by BeginSampleScan. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/tablesample/system.c b/src/backend/access/tablesample/system.c index 29b7c0d3c284d..b0869e5039529 100644 --- a/src/backend/access/tablesample/system.c +++ b/src/backend/access/tablesample/system.c @@ -13,7 +13,7 @@ * cutoff value computed from the selection probability by BeginSampleScan. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/tablesample/tablesample.c b/src/backend/access/tablesample/tablesample.c index f0e2f7be44107..02f2a95e84f17 100644 --- a/src/backend/access/tablesample/tablesample.c +++ b/src/backend/access/tablesample/tablesample.c @@ -3,7 +3,7 @@ * tablesample.c * Support functions for TABLESAMPLE feature * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c index 034349aa7b986..69a81f3246949 100644 --- a/src/backend/access/transam/clog.c +++ b/src/backend/access/transam/clog.c @@ -23,7 +23,7 @@ * for aborts (whether sync or async), since the post-crash assumption would * be that such transactions failed anyway. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/transam/clog.c diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c index 2fe551f17e776..b786eeff7a18a 100644 --- a/src/backend/access/transam/commit_ts.c +++ b/src/backend/access/transam/commit_ts.c @@ -15,7 +15,7 @@ * re-perform the status update on redo; so we need make no additional XLOG * entry here. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/transam/commit_ts.c diff --git a/src/backend/access/transam/generic_xlog.c b/src/backend/access/transam/generic_xlog.c index 5164a1c2f30db..63301a1ab1684 100644 --- a/src/backend/access/transam/generic_xlog.c +++ b/src/backend/access/transam/generic_xlog.c @@ -4,7 +4,7 @@ * Implementation of generic xlog records. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/transam/generic_xlog.c diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c index eb8de7cf3293c..1233448481ae5 100644 --- a/src/backend/access/transam/multixact.c +++ b/src/backend/access/transam/multixact.c @@ -59,7 +59,7 @@ * counter does not fall within the wraparound horizon considering the global * minimum value. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/transam/multixact.c diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c index b0426960c786c..94f9cefa08b04 100644 --- a/src/backend/access/transam/parallel.c +++ b/src/backend/access/transam/parallel.c @@ -3,7 +3,7 @@ * parallel.c * Infrastructure for launching parallel workers * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c index cec17cb2aec0e..244e518e46638 100644 --- a/src/backend/access/transam/slru.c +++ b/src/backend/access/transam/slru.c @@ -38,7 +38,7 @@ * by re-setting the page's page_dirty flag. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/transam/slru.c diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c index 0111e867c79a2..8cdc9e0ab7916 100644 --- a/src/backend/access/transam/subtrans.c +++ b/src/backend/access/transam/subtrans.c @@ -19,7 +19,7 @@ * data across crashes. During database startup, we simply force the * currently-active page of SUBTRANS to zeroes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/transam/subtrans.c diff --git a/src/backend/access/transam/timeline.c b/src/backend/access/transam/timeline.c index e6a29d9a9b7f0..690471ac4ed16 100644 --- a/src/backend/access/transam/timeline.c +++ b/src/backend/access/transam/timeline.c @@ -21,7 +21,7 @@ * The fields are separated by tabs. Lines beginning with # are comments, and * are ignored. Empty lines are also ignored. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/transam/timeline.c diff --git a/src/backend/access/transam/transam.c b/src/backend/access/transam/transam.c index a28918657cfb1..1ba4bbead5599 100644 --- a/src/backend/access/transam/transam.c +++ b/src/backend/access/transam/transam.c @@ -3,7 +3,7 @@ * transam.c * postgres transaction (commit) log interface routines * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c index 873bf9bad9850..fc18b778324dd 100644 --- a/src/backend/access/transam/twophase.c +++ b/src/backend/access/transam/twophase.c @@ -3,7 +3,7 @@ * twophase.c * Two-phase commit support functions. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/access/transam/twophase_rmgr.c b/src/backend/access/transam/twophase_rmgr.c index 3a6a2d1fafd25..1fd785567cc83 100644 --- a/src/backend/access/transam/twophase_rmgr.c +++ b/src/backend/access/transam/twophase_rmgr.c @@ -3,7 +3,7 @@ * twophase_rmgr.c * Two-phase-commit resource managers tables * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/transam/varsup.c b/src/backend/access/transam/varsup.c index a4944faa32e34..2264c2c849cac 100644 --- a/src/backend/access/transam/varsup.c +++ b/src/backend/access/transam/varsup.c @@ -3,7 +3,7 @@ * varsup.c * postgres OID & XID variables support routines * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/access/transam/varsup.c diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 9cd0b7c11bc9f..a2068e3fd45d8 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -5,7 +5,7 @@ * * See src/backend/access/transam/README for more information. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 9867e1b4039cd..ede93ad7fdde2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -4,7 +4,7 @@ * PostgreSQL write-ahead log manager * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/transam/xlog.c diff --git a/src/backend/access/transam/xlogarchive.c b/src/backend/access/transam/xlogarchive.c index f39dc4ddf1a55..1c5a4f8b5a548 100644 --- a/src/backend/access/transam/xlogarchive.c +++ b/src/backend/access/transam/xlogarchive.c @@ -4,7 +4,7 @@ * Functions for archiving WAL files and restoring from the archive. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/transam/xlogarchive.c diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c index 290658b22c17e..5e1aab319dda8 100644 --- a/src/backend/access/transam/xlogfuncs.c +++ b/src/backend/access/transam/xlogfuncs.c @@ -7,7 +7,7 @@ * This file contains WAL control and information functions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/transam/xlogfuncs.c diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c index 1f0e4e01e69b1..7052dc245ee02 100644 --- a/src/backend/access/transam/xloginsert.c +++ b/src/backend/access/transam/xloginsert.c @@ -9,7 +9,7 @@ * of XLogRecData structs by a call to XLogRecordAssemble(). See * access/transam/README for details. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/transam/xloginsert.c diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c index a63ad8cfd0bfc..0e8c74f2bb67b 100644 --- a/src/backend/access/transam/xlogreader.c +++ b/src/backend/access/transam/xlogreader.c @@ -3,7 +3,7 @@ * xlogreader.c * Generic XLog reading facility * - * Portions Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2013-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/access/transam/xlogreader.c diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c index e0ca3859a9553..e72325329755b 100644 --- a/src/backend/access/transam/xlogutils.c +++ b/src/backend/access/transam/xlogutils.c @@ -8,7 +8,7 @@ * None of this code is used during normal system operation. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/access/transam/xlogutils.c diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y index 6bb0c6ed1ea9c..5fcd004e1b182 100644 --- a/src/backend/bootstrap/bootparse.y +++ b/src/backend/bootstrap/bootparse.y @@ -4,7 +4,7 @@ * bootparse.y * yacc grammar for the "bootstrap" mode (BKI file format) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/bootstrap/bootscanner.l b/src/backend/bootstrap/bootscanner.l index 62d67a695ec46..7aecd895fba47 100644 --- a/src/backend/bootstrap/bootscanner.l +++ b/src/backend/bootstrap/bootscanner.l @@ -4,7 +4,7 @@ * bootscanner.l * a lexical scanner for the bootstrap parser * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index a7ed93fdc14d1..6f615e66220b3 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -4,7 +4,7 @@ * routines to support running postgres in 'bootstrap' mode * bootstrap mode is used to create the initial template database * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/catalog/Catalog.pm b/src/backend/catalog/Catalog.pm index dd39a086ce4fd..a37c3271229ce 100644 --- a/src/backend/catalog/Catalog.pm +++ b/src/backend/catalog/Catalog.pm @@ -4,7 +4,7 @@ # Perl module that extracts info from catalog files into Perl # data structures # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/backend/catalog/Catalog.pm diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index 2519771210800..c85f0ca7b66de 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -2,7 +2,7 @@ # # Makefile for backend/catalog # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/backend/catalog/Makefile diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index c4594b0b095ac..1a81e768eccd5 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -3,7 +3,7 @@ * aclchk.c * Routines to check access control permissions. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c index f984514fe062a..e2ed80a5de94d 100644 --- a/src/backend/catalog/catalog.c +++ b/src/backend/catalog/catalog.c @@ -5,7 +5,7 @@ * bits of hard-wired knowledge * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 119006159b60a..2140151a6afd1 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -4,7 +4,7 @@ * Routines to support inter-object dependencies. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl index 66fdaf67b135b..009e215da1c0b 100644 --- a/src/backend/catalog/genbki.pl +++ b/src/backend/catalog/genbki.pl @@ -6,7 +6,7 @@ # headers from specially formatted header files and data files. # postgres.bki is used to initialize the postgres template database. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/backend/catalog/genbki.pl @@ -415,7 +415,7 @@ * %s_d.h * Macro definitions for %s * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES @@ -658,7 +658,7 @@ * schemapg.h * Schema_pg_xxx macros for use by relcache.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 51b5c4f7f682b..21f2240ade842 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -3,7 +3,7 @@ * heap.c * code to create and destroy POSTGRES heap relations * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 731610c70193d..cffbc0ac388ed 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -3,7 +3,7 @@ * index.c * code to create and destroy POSTGRES index relations * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c index 538f6a06b872d..8701653eb6162 100644 --- a/src/backend/catalog/indexing.c +++ b/src/backend/catalog/indexing.c @@ -4,7 +4,7 @@ * This file contains routines to support indexes defined on system * catalogs. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql index 5ab47e774316d..4907855043d87 100644 --- a/src/backend/catalog/information_schema.sql +++ b/src/backend/catalog/information_schema.sql @@ -2,7 +2,7 @@ * SQL Information Schema * as defined in ISO/IEC 9075-11:2016 * - * Copyright (c) 2003-2020, PostgreSQL Global Development Group + * Copyright (c) 2003-2021, PostgreSQL Global Development Group * * src/backend/catalog/information_schema.sql * diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c index 740570c566dd3..005e029c38265 100644 --- a/src/backend/catalog/namespace.c +++ b/src/backend/catalog/namespace.c @@ -9,7 +9,7 @@ * and implementing search-path-controlled searches. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/catalog/objectaccess.c b/src/backend/catalog/objectaccess.c index 17d7c56198a90..4aa445a077ef8 100644 --- a/src/backend/catalog/objectaccess.c +++ b/src/backend/catalog/objectaccess.c @@ -3,7 +3,7 @@ * objectaccess.c * functions for object_access_hook on various events * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * ------------------------------------------------------------------------- diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index a5eccdffd0cb9..6d88b690d87a8 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -3,7 +3,7 @@ * objectaddress.c * functions for working with ObjectAddresses * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c index 4dfac39adfe48..af7754d6ab76a 100644 --- a/src/backend/catalog/partition.c +++ b/src/backend/catalog/partition.c @@ -3,7 +3,7 @@ * partition.c * Partitioning related data structures and functions. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c index 7664bb62859d1..89f23d0add8f8 100644 --- a/src/backend/catalog/pg_aggregate.c +++ b/src/backend/catalog/pg_aggregate.c @@ -3,7 +3,7 @@ * pg_aggregate.c * routines to support manipulation of the pg_aggregate relation * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/pg_cast.c b/src/backend/catalog/pg_cast.c index d3f2db41863b9..b9cda3cf50436 100644 --- a/src/backend/catalog/pg_cast.c +++ b/src/backend/catalog/pg_cast.c @@ -3,7 +3,7 @@ * pg_cast.c * routines to support manipulation of the pg_cast relation * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/pg_collation.c b/src/backend/catalog/pg_collation.c index 3c84378d0255d..40d98a334a6e9 100644 --- a/src/backend/catalog/pg_collation.c +++ b/src/backend/catalog/pg_collation.c @@ -3,7 +3,7 @@ * pg_collation.c * routines to support manipulation of the pg_collation relation * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c index 93774c9d21a59..0081558c48ad3 100644 --- a/src/backend/catalog/pg_constraint.c +++ b/src/backend/catalog/pg_constraint.c @@ -3,7 +3,7 @@ * pg_constraint.c * routines to support manipulation of the pg_constraint relation * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/pg_conversion.c b/src/backend/catalog/pg_conversion.c index 28b676a1fa843..02ac7c4a88552 100644 --- a/src/backend/catalog/pg_conversion.c +++ b/src/backend/catalog/pg_conversion.c @@ -3,7 +3,7 @@ * pg_conversion.c * routines to support manipulation of the pg_conversion relation * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/pg_db_role_setting.c b/src/backend/catalog/pg_db_role_setting.c index 33fc53af7f90c..0c2b02bb2d089 100644 --- a/src/backend/catalog/pg_db_role_setting.c +++ b/src/backend/catalog/pg_db_role_setting.c @@ -2,7 +2,7 @@ * pg_db_role_setting.c * Routines to support manipulation of the pg_db_role_setting relation * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c index 429791694f0fe..63da24322d911 100644 --- a/src/backend/catalog/pg_depend.c +++ b/src/backend/catalog/pg_depend.c @@ -3,7 +3,7 @@ * pg_depend.c * routines to support manipulation of the pg_depend relation * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/pg_enum.c b/src/backend/catalog/pg_enum.c index f2e7bab62a28f..b54f9dff43bd2 100644 --- a/src/backend/catalog/pg_enum.c +++ b/src/backend/catalog/pg_enum.c @@ -3,7 +3,7 @@ * pg_enum.c * routines to support manipulation of the pg_enum relation * - * Copyright (c) 2006-2020, PostgreSQL Global Development Group + * Copyright (c) 2006-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/catalog/pg_inherits.c b/src/backend/catalog/pg_inherits.c index 5c3c78a0e6c80..f3783961b7a11 100644 --- a/src/backend/catalog/pg_inherits.c +++ b/src/backend/catalog/pg_inherits.c @@ -8,7 +8,7 @@ * Perhaps someday that code should be moved here, but it'd have to be * disentangled from other stuff such as pg_depend updates. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/pg_largeobject.c b/src/backend/catalog/pg_largeobject.c index ae9365e3a033c..047bc6883cdde 100644 --- a/src/backend/catalog/pg_largeobject.c +++ b/src/backend/catalog/pg_largeobject.c @@ -3,7 +3,7 @@ * pg_largeobject.c * routines to support manipulation of the pg_largeobject relation * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/pg_namespace.c b/src/backend/catalog/pg_namespace.c index 7d2e26fd359b3..e66e090d4f30b 100644 --- a/src/backend/catalog/pg_namespace.c +++ b/src/backend/catalog/pg_namespace.c @@ -3,7 +3,7 @@ * pg_namespace.c * routines to support manipulation of the pg_namespace relation * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c index 904cb8ef820c1..6c270f9338957 100644 --- a/src/backend/catalog/pg_operator.c +++ b/src/backend/catalog/pg_operator.c @@ -3,7 +3,7 @@ * pg_operator.c * routines to support manipulation of the pg_operator relation * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index 1dd9ecc0634aa..e14eee5a19e14 100644 --- a/src/backend/catalog/pg_proc.c +++ b/src/backend/catalog/pg_proc.c @@ -3,7 +3,7 @@ * pg_proc.c * routines to support manipulation of the pg_proc relation * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c index 09946be788de3..5f8e1c64e18f1 100644 --- a/src/backend/catalog/pg_publication.c +++ b/src/backend/catalog/pg_publication.c @@ -3,7 +3,7 @@ * pg_publication.c * publication C API manipulation * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/catalog/pg_range.c b/src/backend/catalog/pg_range.c index 91b0fb0611a78..839b65eb797d7 100644 --- a/src/backend/catalog/pg_range.c +++ b/src/backend/catalog/pg_range.c @@ -3,7 +3,7 @@ * pg_range.c * routines to support manipulation of the pg_range relation * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c index 3dd7afd343391..86c3be107fffc 100644 --- a/src/backend/catalog/pg_shdepend.c +++ b/src/backend/catalog/pg_shdepend.c @@ -3,7 +3,7 @@ * pg_shdepend.c * routines to support manipulation of the pg_shdepend relation * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/pg_subscription.c b/src/backend/catalog/pg_subscription.c index ca78d395181a9..44cb285b68650 100644 --- a/src/backend/catalog/pg_subscription.c +++ b/src/backend/catalog/pg_subscription.c @@ -3,7 +3,7 @@ * pg_subscription.c * replication subscriptions * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c index 2aa686a640fbd..ec5d1224323cf 100644 --- a/src/backend/catalog/pg_type.c +++ b/src/backend/catalog/pg_type.c @@ -3,7 +3,7 @@ * pg_type.c * routines to support manipulation of the pg_type relation * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c index d538f25726f45..cba7a9ada07e1 100644 --- a/src/backend/catalog/storage.c +++ b/src/backend/catalog/storage.c @@ -3,7 +3,7 @@ * storage.c * code to create and destroy physical storage for relations * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index b140c210bc799..ab4603c69b8e8 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -1,7 +1,7 @@ /* * PostgreSQL System Views * - * Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Copyright (c) 1996-2021, PostgreSQL Global Development Group * * src/backend/catalog/system_views.sql * diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c index f1850436bd745..d7b806020dd28 100644 --- a/src/backend/catalog/toasting.c +++ b/src/backend/catalog/toasting.c @@ -4,7 +4,7 @@ * This file contains routines to support creation of toast tables * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c index 6892204a9aaa6..69c50ac087738 100644 --- a/src/backend/commands/aggregatecmds.c +++ b/src/backend/commands/aggregatecmds.c @@ -4,7 +4,7 @@ * * Routines for aggregate-manipulation commands * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c index b11ebf0f618bb..29249498a9182 100644 --- a/src/backend/commands/alter.c +++ b/src/backend/commands/alter.c @@ -3,7 +3,7 @@ * alter.c * Drivers for generic alter commands * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/amcmds.c b/src/backend/commands/amcmds.c index 6f05ee715b480..eff9535ed0eae 100644 --- a/src/backend/commands/amcmds.c +++ b/src/backend/commands/amcmds.c @@ -3,7 +3,7 @@ * amcmds.c * Routines for SQL commands that manipulate access methods. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index 8af12b5c6b2b3..7295cf02156e9 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -3,7 +3,7 @@ * analyze.c * the Postgres statistics generator * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c index e04afd9963f17..7c133ec8d3301 100644 --- a/src/backend/commands/async.c +++ b/src/backend/commands/async.c @@ -3,7 +3,7 @@ * async.c * Asynchronous notification: NOTIFY, LISTEN, UNLISTEN * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index fd5a6eec86261..d5eeb493ac453 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -6,7 +6,7 @@ * There is hardly anything left of Paul Brown's original implementation... * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994-5, Regents of the University of California * * diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c index d62c8defbabc9..9634ae6809dab 100644 --- a/src/backend/commands/collationcmds.c +++ b/src/backend/commands/collationcmds.c @@ -3,7 +3,7 @@ * collationcmds.c * collation-related commands support code * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c index 0ff9ca9f2c8c6..216b8d3068825 100644 --- a/src/backend/commands/comment.c +++ b/src/backend/commands/comment.c @@ -4,7 +4,7 @@ * * PostgreSQL object comments utility code. * - * Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/commands/comment.c diff --git a/src/backend/commands/constraint.c b/src/backend/commands/constraint.c index fc19307bf2fb3..c2394d2232e6d 100644 --- a/src/backend/commands/constraint.c +++ b/src/backend/commands/constraint.c @@ -3,7 +3,7 @@ * constraint.c * PostgreSQL CONSTRAINT support code. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/commands/conversioncmds.c b/src/backend/commands/conversioncmds.c index 0ee3b6d19a398..f7ff321de71a0 100644 --- a/src/backend/commands/conversioncmds.c +++ b/src/backend/commands/conversioncmds.c @@ -3,7 +3,7 @@ * conversioncmds.c * conversion creation command support code * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index b6143b8bf2178..8c712c8737fa9 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -3,7 +3,7 @@ * copy.c * Implements the COPY utility command * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c index 1b14e9a6eb034..84a5045215b07 100644 --- a/src/backend/commands/copyfrom.c +++ b/src/backend/commands/copyfrom.c @@ -3,7 +3,7 @@ * copyfrom.c * COPY
FROM file/program/client * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/copyfromparse.c b/src/backend/commands/copyfromparse.c index 34ed3cfcd5b43..4360b7788ea0b 100644 --- a/src/backend/commands/copyfromparse.c +++ b/src/backend/commands/copyfromparse.c @@ -3,7 +3,7 @@ * copyfromparse.c * Parse CSV/text/binary format for COPY FROM. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/copyto.c b/src/backend/commands/copyto.c index c7e5f04446310..51597ae523d1a 100644 --- a/src/backend/commands/copyto.c +++ b/src/backend/commands/copyto.c @@ -3,7 +3,7 @@ * copyto.c * COPY
TO file/program/client * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c index 009896bcee78c..dce882012e6ff 100644 --- a/src/backend/commands/createas.c +++ b/src/backend/commands/createas.c @@ -13,7 +13,7 @@ * we must return a tuples-processed count in the QueryCompletion. (We no * longer do that for CTAS ... WITH NO DATA, however.) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index f27c3fe8c1ca2..2b159b60ebb33 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -8,7 +8,7 @@ * stepping on each others' toes. Formerly we used table-level locks * on pg_database, but that's too coarse-grained. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c index 3a2aff79c2847..84487b7d4b426 100644 --- a/src/backend/commands/define.c +++ b/src/backend/commands/define.c @@ -4,7 +4,7 @@ * Support routines for various kinds of object creation. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/discard.c b/src/backend/commands/discard.c index 90dfc58c24d6c..57d3d7dd9b3d7 100644 --- a/src/backend/commands/discard.c +++ b/src/backend/commands/discard.c @@ -3,7 +3,7 @@ * discard.c * The implementation of the DISCARD command * - * Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c index 81f03801086d9..97e5e9a765ca5 100644 --- a/src/backend/commands/dropcmds.c +++ b/src/backend/commands/dropcmds.c @@ -3,7 +3,7 @@ * dropcmds.c * handle various "DROP" operations * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index 3ffba4e63ec27..5bde507c7526a 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -3,7 +3,7 @@ * event_trigger.c * PostgreSQL EVENT TRIGGER support code. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index d797b5f53e039..5d7eb3574c823 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -3,7 +3,7 @@ * explain.c * Explain query execution plans * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994-5, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c index b5630b4c8d981..bac7a9e9b9a2d 100644 --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -12,7 +12,7 @@ * postgresql.conf. An extension also has an installation script file, * containing SQL commands to create the extension's objects. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c index de31ddd1f38cd..eb7103fd3b11f 100644 --- a/src/backend/commands/foreigncmds.c +++ b/src/backend/commands/foreigncmds.c @@ -3,7 +3,7 @@ * foreigncmds.c * foreign-data wrapper/server creation/manipulation commands * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index c3ce480c8f568..55950e754d20f 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -5,7 +5,7 @@ * Routines for CREATE and DROP FUNCTION commands and CREATE and DROP * CAST commands. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 14d24b3cc4034..992f4813b4946 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -3,7 +3,7 @@ * indexcmds.c * POSTGRES define and remove index code. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/lockcmds.c b/src/backend/commands/lockcmds.c index 098227656a823..34f2270cedffc 100644 --- a/src/backend/commands/lockcmds.c +++ b/src/backend/commands/lockcmds.c @@ -3,7 +3,7 @@ * lockcmds.c * LOCK command support code * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c index cfc63915f38cd..c5c25ce11d5e8 100644 --- a/src/backend/commands/matview.c +++ b/src/backend/commands/matview.c @@ -3,7 +3,7 @@ * matview.c * materialized view support * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c index c46db7d11cb47..fad39e2b75c16 100644 --- a/src/backend/commands/opclasscmds.c +++ b/src/backend/commands/opclasscmds.c @@ -4,7 +4,7 @@ * * Routines for opclass (and opfamily) manipulation commands * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c index a791e99092d5b..809043c5d195d 100644 --- a/src/backend/commands/operatorcmds.c +++ b/src/backend/commands/operatorcmds.c @@ -4,7 +4,7 @@ * * Routines for operator manipulation commands * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c index d3f8e8f06c136..5cacc088cd877 100644 --- a/src/backend/commands/policy.c +++ b/src/backend/commands/policy.c @@ -3,7 +3,7 @@ * policy.c * Commands for manipulating policies. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/commands/policy.c diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c index 0b64204975d39..6f2397bd360e6 100644 --- a/src/backend/commands/portalcmds.c +++ b/src/backend/commands/portalcmds.c @@ -9,7 +9,7 @@ * storage management for portals (but doesn't run any queries in them). * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c index 89087a7be3190..653ef8e41a69f 100644 --- a/src/backend/commands/prepare.c +++ b/src/backend/commands/prepare.c @@ -7,7 +7,7 @@ * accessed via the extended FE/BE query protocol. * * - * Copyright (c) 2002-2020, PostgreSQL Global Development Group + * Copyright (c) 2002-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/commands/prepare.c diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c index 8ef60374f590b..81598d3e08e76 100644 --- a/src/backend/commands/proclang.c +++ b/src/backend/commands/proclang.c @@ -3,7 +3,7 @@ * proclang.c * PostgreSQL LANGUAGE support code. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c index eabbc7473bbf1..95c253c8e08ee 100644 --- a/src/backend/commands/publicationcmds.c +++ b/src/backend/commands/publicationcmds.c @@ -3,7 +3,7 @@ * publicationcmds.c * publication manipulation * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c index 3013862528885..a60eb161e4aae 100644 --- a/src/backend/commands/schemacmds.c +++ b/src/backend/commands/schemacmds.c @@ -3,7 +3,7 @@ * schemacmds.c * schema creation/manipulation commands * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c index ee036e908795e..6906714298694 100644 --- a/src/backend/commands/seclabel.c +++ b/src/backend/commands/seclabel.c @@ -3,7 +3,7 @@ * seclabel.c * routines to support security label feature. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * ------------------------------------------------------------------------- diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index fa2eea8af2177..0415df9ccb7eb 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -3,7 +3,7 @@ * sequence.c * PostgreSQL sequences support code. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c index 3057d89d50c01..114ad77142cf3 100644 --- a/src/backend/commands/statscmds.c +++ b/src/backend/commands/statscmds.c @@ -3,7 +3,7 @@ * statscmds.c * Commands for creating and altering extended statistics objects * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c index 1696454c0bbb6..490e93554135e 100644 --- a/src/backend/commands/subscriptioncmds.c +++ b/src/backend/commands/subscriptioncmds.c @@ -3,7 +3,7 @@ * subscriptioncmds.c * subscription catalog manipulation functions * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 1fa9f19f08cbc..11dae782fd2f5 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -3,7 +3,7 @@ * tablecmds.c * Commands for creating and altering table structures and settings * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c index 2c3b9050b2787..a9a2db2834555 100644 --- a/src/backend/commands/tablespace.c +++ b/src/backend/commands/tablespace.c @@ -35,7 +35,7 @@ * and munge the system catalogs of the new database. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index c336b238aac05..12229364f1e92 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -3,7 +3,7 @@ * trigger.c * PostgreSQL TRIGGERs support code. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c index f5d1d137b8141..e06fb32b3d1ec 100644 --- a/src/backend/commands/tsearchcmds.c +++ b/src/backend/commands/tsearchcmds.c @@ -4,7 +4,7 @@ * * Routines for tsearch manipulation commands * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index a0a8695b1bd08..76218fb47ed4a 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -3,7 +3,7 @@ * typecmds.c * Routines for SQL commands that manipulate types (and domains). * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index 0e6800bf3e4f3..ed243e3d1415f 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -3,7 +3,7 @@ * user.c * Commands for manipulating roles (formerly called users). * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/commands/user.c diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 98270a10495d7..b97d48ee01e3b 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -9,7 +9,7 @@ * in cluster.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 484f7ea2c0e6f..c5cf08b423780 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -4,7 +4,7 @@ * Routines for handling specialized SET variables. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c index 6e65103febc60..f2642dba6c982 100644 --- a/src/backend/commands/view.c +++ b/src/backend/commands/view.c @@ -3,7 +3,7 @@ * view.c * use rewrite rules to construct views * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c index 0c10f1d35c2b4..23bdb53cd1037 100644 --- a/src/backend/executor/execAmi.c +++ b/src/backend/executor/execAmi.c @@ -3,7 +3,7 @@ * execAmi.c * miscellaneous executor access method routines * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/executor/execAmi.c diff --git a/src/backend/executor/execCurrent.c b/src/backend/executor/execCurrent.c index f89319fcd89b8..0852bb9cec8c0 100644 --- a/src/backend/executor/execCurrent.c +++ b/src/backend/executor/execCurrent.c @@ -3,7 +3,7 @@ * execCurrent.c * executor support for WHERE CURRENT OF cursor * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/executor/execCurrent.c diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c index 5c3210a9ccadd..8fc2a2666bd80 100644 --- a/src/backend/executor/execExpr.c +++ b/src/backend/executor/execExpr.c @@ -19,7 +19,7 @@ * and "Expression Evaluation" sections. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index 6b9fc38134b8c..6308286d8c35c 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -46,7 +46,7 @@ * exported rather than being "static" in this file.) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/executor/execGrouping.c b/src/backend/executor/execGrouping.c index 90d04f9228aa4..5fd0b26cbc16b 100644 --- a/src/backend/executor/execGrouping.c +++ b/src/backend/executor/execGrouping.c @@ -3,7 +3,7 @@ * execGrouping.c * executor utility routines for grouping, hashing, and aggregation * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/execIndexing.c b/src/backend/executor/execIndexing.c index c6b5bcba7b47f..2aafcc8f2298b 100644 --- a/src/backend/executor/execIndexing.c +++ b/src/backend/executor/execIndexing.c @@ -95,7 +95,7 @@ * with the higher XID backs out. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/execJunk.c b/src/backend/executor/execJunk.c index 1a822ff24b382..970e1c325e33b 100644 --- a/src/backend/executor/execJunk.c +++ b/src/backend/executor/execJunk.c @@ -3,7 +3,7 @@ * execJunk.c * Junk attribute support stuff.... * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 7179f589f9491..b4e25df601bd2 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -26,7 +26,7 @@ * before ExecutorEnd. This can be omitted only in case of EXPLAIN, * which should also omit ExecutorRun. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c index befde526910ae..c95d5170e415a 100644 --- a/src/backend/executor/execParallel.c +++ b/src/backend/executor/execParallel.c @@ -3,7 +3,7 @@ * execParallel.c * Support routines for parallel execution. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * This file contains routines that are intended to support setting up, diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index 97bfc8bd71767..941731a0a9b73 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -3,7 +3,7 @@ * execPartition.c * Support routines for partitioning. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c index 01b7b926bf705..414df50a0545e 100644 --- a/src/backend/executor/execProcnode.c +++ b/src/backend/executor/execProcnode.c @@ -7,7 +7,7 @@ * ExecProcNode, or ExecEndNode on its subnodes and do the appropriate * processing. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/execReplication.c b/src/backend/executor/execReplication.c index 01d26881e770c..12f6e5c6778fa 100644 --- a/src/backend/executor/execReplication.c +++ b/src/backend/executor/execReplication.c @@ -3,7 +3,7 @@ * execReplication.c * miscellaneous executor routines for logical replication * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/executor/execSRF.c b/src/backend/executor/execSRF.c index b0ea72de68500..8aec3b549bdea 100644 --- a/src/backend/executor/execSRF.c +++ b/src/backend/executor/execSRF.c @@ -7,7 +7,7 @@ * common code for calling set-returning functions according to the * ReturnSetInfo API. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c index 642805d90cdc4..69ab34573ec59 100644 --- a/src/backend/executor/execScan.c +++ b/src/backend/executor/execScan.c @@ -7,7 +7,7 @@ * stuff - checking the qualification and projecting the tuple * appropriately. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index 4c90ac5236fb2..73c35df9c9686 100644 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@ -46,7 +46,7 @@ * to avoid physically constructing projection tuples in many cases. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index 071a0007ebcd8..d84fbaded9619 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -3,7 +3,7 @@ * execUtils.c * miscellaneous executor utility routines * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index ca8d637e73ab6..7bb752ace3ada 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -3,7 +3,7 @@ * functions.c * Execution of SQL-language functions * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/instrument.c b/src/backend/executor/instrument.c index fbedb5aaf6002..237e13361b5d0 100644 --- a/src/backend/executor/instrument.c +++ b/src/backend/executor/instrument.c @@ -4,7 +4,7 @@ * functions for instrumentation of plan execution * * - * Copyright (c) 2001-2020, PostgreSQL Global Development Group + * Copyright (c) 2001-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/executor/instrument.c diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index da483268cf707..601b6dab03f1e 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -228,7 +228,7 @@ * to filter expressions having to be evaluated early, and allows to JIT * the entire expression into one native function. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c index 88919e62faee0..15e4115bd6df4 100644 --- a/src/backend/executor/nodeAppend.c +++ b/src/backend/executor/nodeAppend.c @@ -3,7 +3,7 @@ * nodeAppend.c * routines to handle append nodes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeBitmapAnd.c b/src/backend/executor/nodeBitmapAnd.c index 276b6f11a6505..a8d7b1e5eddcc 100644 --- a/src/backend/executor/nodeBitmapAnd.c +++ b/src/backend/executor/nodeBitmapAnd.c @@ -3,7 +3,7 @@ * nodeBitmapAnd.c * routines to handle BitmapAnd nodes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c index 5a5c410106ac6..2db1914affb3b 100644 --- a/src/backend/executor/nodeBitmapHeapscan.c +++ b/src/backend/executor/nodeBitmapHeapscan.c @@ -16,7 +16,7 @@ * required index qual conditions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeBitmapIndexscan.c b/src/backend/executor/nodeBitmapIndexscan.c index 81a120815734a..48c2036297cd6 100644 --- a/src/backend/executor/nodeBitmapIndexscan.c +++ b/src/backend/executor/nodeBitmapIndexscan.c @@ -3,7 +3,7 @@ * nodeBitmapIndexscan.c * Routines to support bitmapped index scans of relations * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeBitmapOr.c b/src/backend/executor/nodeBitmapOr.c index 32fb72f04fbdf..4a8c01d04f706 100644 --- a/src/backend/executor/nodeBitmapOr.c +++ b/src/backend/executor/nodeBitmapOr.c @@ -3,7 +3,7 @@ * nodeBitmapOr.c * routines to handle BitmapOr nodes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeCtescan.c b/src/backend/executor/nodeCtescan.c index 3de9b10c1f7b0..9c2b08d1d8838 100644 --- a/src/backend/executor/nodeCtescan.c +++ b/src/backend/executor/nodeCtescan.c @@ -3,7 +3,7 @@ * nodeCtescan.c * routines to handle CteScan nodes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c index cfa9e46e55f15..c82060e6d1a87 100644 --- a/src/backend/executor/nodeCustom.c +++ b/src/backend/executor/nodeCustom.c @@ -3,7 +3,7 @@ * nodeCustom.c * Routines to handle execution of custom scan node * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * ------------------------------------------------------------------------ diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c index 0b20f94035edd..0969e53c3a44d 100644 --- a/src/backend/executor/nodeForeignscan.c +++ b/src/backend/executor/nodeForeignscan.c @@ -3,7 +3,7 @@ * nodeForeignscan.c * Routines to support scans of foreign tables * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c index ccb66ce1aab2b..b31b2b2886209 100644 --- a/src/backend/executor/nodeFunctionscan.c +++ b/src/backend/executor/nodeFunctionscan.c @@ -3,7 +3,7 @@ * nodeFunctionscan.c * Support routines for scanning RangeFunctions (functions in rangetable). * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c index a01b46af14802..9e1dc464cb097 100644 --- a/src/backend/executor/nodeGather.c +++ b/src/backend/executor/nodeGather.c @@ -3,7 +3,7 @@ * nodeGather.c * Support routines for scanning a plan via multiple workers. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * A Gather executor launches parallel workers to run multiple copies of a diff --git a/src/backend/executor/nodeGatherMerge.c b/src/backend/executor/nodeGatherMerge.c index 47129344f3276..aa5743cebfc1a 100644 --- a/src/backend/executor/nodeGatherMerge.c +++ b/src/backend/executor/nodeGatherMerge.c @@ -3,7 +3,7 @@ * nodeGatherMerge.c * Scan a plan in multiple workers, and do order-preserving merge. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c index c9a846df660a6..1721b2aae48ba 100644 --- a/src/backend/executor/nodeGroup.c +++ b/src/backend/executor/nodeGroup.c @@ -3,7 +3,7 @@ * nodeGroup.c * Routines to handle group nodes (used for queries with GROUP BY clause). * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c index ea69eeb2a1e4b..c5f2d1d22b16a 100644 --- a/src/backend/executor/nodeHash.c +++ b/src/backend/executor/nodeHash.c @@ -3,7 +3,7 @@ * nodeHash.c * Routines to hash relations for hashjoin * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c index 5532b91a71dca..510bdd39adc39 100644 --- a/src/backend/executor/nodeHashjoin.c +++ b/src/backend/executor/nodeHashjoin.c @@ -3,7 +3,7 @@ * nodeHashjoin.c * Routines to handle hash join nodes * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeIncrementalSort.c b/src/backend/executor/nodeIncrementalSort.c index eb1c1326dea26..73e42d79451aa 100644 --- a/src/backend/executor/nodeIncrementalSort.c +++ b/src/backend/executor/nodeIncrementalSort.c @@ -3,7 +3,7 @@ * nodeIncrementalSort.c * Routines to handle incremental sorting of relations. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c index 5617ac29e74cb..0754e28a9aac1 100644 --- a/src/backend/executor/nodeIndexonlyscan.c +++ b/src/backend/executor/nodeIndexonlyscan.c @@ -3,7 +3,7 @@ * nodeIndexonlyscan.c * Routines to support index-only scans * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index d0a96a38e0160..2fffb1b4371eb 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -3,7 +3,7 @@ * nodeIndexscan.c * Routines to support indexed scans of relations * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c index c5896e579089f..128eb3e57814b 100644 --- a/src/backend/executor/nodeLimit.c +++ b/src/backend/executor/nodeLimit.c @@ -3,7 +3,7 @@ * nodeLimit.c * Routines to handle limiting of query results where appropriate * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c index 554c2a5a2c5d4..b2e5c30079e58 100644 --- a/src/backend/executor/nodeLockRows.c +++ b/src/backend/executor/nodeLockRows.c @@ -3,7 +3,7 @@ * nodeLockRows.c * Routines to handle FOR UPDATE/FOR SHARE row locking * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c index dd077f4323032..7c53f8e60f539 100644 --- a/src/backend/executor/nodeMaterial.c +++ b/src/backend/executor/nodeMaterial.c @@ -3,7 +3,7 @@ * nodeMaterial.c * Routines to handle materialization nodes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c index 70090a4906580..617bffb206271 100644 --- a/src/backend/executor/nodeMergeAppend.c +++ b/src/backend/executor/nodeMergeAppend.c @@ -3,7 +3,7 @@ * nodeMergeAppend.c * routines to handle MergeAppend nodes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c index c5658f03ced3b..b41454ab6d92f 100644 --- a/src/backend/executor/nodeMergejoin.c +++ b/src/backend/executor/nodeMergejoin.c @@ -3,7 +3,7 @@ * nodeMergejoin.c * routines supporting merge joins * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index ab3d655e603b7..d7b8f6559196f 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -3,7 +3,7 @@ * nodeModifyTable.c * routines to handle ModifyTable nodes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeNamedtuplestorescan.c b/src/backend/executor/nodeNamedtuplestorescan.c index 3135c7a27e18a..c0d1069f5985c 100644 --- a/src/backend/executor/nodeNamedtuplestorescan.c +++ b/src/backend/executor/nodeNamedtuplestorescan.c @@ -3,7 +3,7 @@ * nodeNamedtuplestorescan.c * routines to handle NamedTuplestoreScan nodes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c index b07c2996d4c93..41e5ecabc72f7 100644 --- a/src/backend/executor/nodeNestloop.c +++ b/src/backend/executor/nodeNestloop.c @@ -3,7 +3,7 @@ * nodeNestloop.c * routines to support nest-loop joins * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeProjectSet.c b/src/backend/executor/nodeProjectSet.c index e8da6eaec9148..07be814d7b52d 100644 --- a/src/backend/executor/nodeProjectSet.c +++ b/src/backend/executor/nodeProjectSet.c @@ -11,7 +11,7 @@ * can't be inside more-complex expressions. If that'd otherwise be * the case, the planner adds additional ProjectSet nodes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/executor/nodeRecursiveunion.c b/src/backend/executor/nodeRecursiveunion.c index 046242682f017..f9e91fdcfc2bd 100644 --- a/src/backend/executor/nodeRecursiveunion.c +++ b/src/backend/executor/nodeRecursiveunion.c @@ -7,7 +7,7 @@ * already seen. The hash key is computed from the grouping columns. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c index 99f91bca53ba2..1762b87c99936 100644 --- a/src/backend/executor/nodeResult.c +++ b/src/backend/executor/nodeResult.c @@ -34,7 +34,7 @@ * plan normally and pass back the results. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c index 4732c926f7ba7..44232d50d0a32 100644 --- a/src/backend/executor/nodeSamplescan.c +++ b/src/backend/executor/nodeSamplescan.c @@ -3,7 +3,7 @@ * nodeSamplescan.c * Support routines for sample scans of relations (table sampling). * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c index 1a7c1e919f366..066f9ae37e0b1 100644 --- a/src/backend/executor/nodeSeqscan.c +++ b/src/backend/executor/nodeSeqscan.c @@ -3,7 +3,7 @@ * nodeSeqscan.c * Support routines for sequential scans of relations. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c index 8d4ccff19cc62..aad7ac0ea2a5e 100644 --- a/src/backend/executor/nodeSetOp.c +++ b/src/backend/executor/nodeSetOp.c @@ -32,7 +32,7 @@ * input group. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c index 9d2bfd7ed6b54..b99027e0d7f4e 100644 --- a/src/backend/executor/nodeSort.c +++ b/src/backend/executor/nodeSort.c @@ -3,7 +3,7 @@ * nodeSort.c * Routines to handle sorting of relations. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c index 152c7ae7eb4ea..d46227e65c5a4 100644 --- a/src/backend/executor/nodeSubplan.c +++ b/src/backend/executor/nodeSubplan.c @@ -11,7 +11,7 @@ * subplans, which are re-evaluated every time their result is required. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c index e82c10981becd..c09f628ded128 100644 --- a/src/backend/executor/nodeSubqueryscan.c +++ b/src/backend/executor/nodeSubqueryscan.c @@ -7,7 +7,7 @@ * we need two sets of code. Ought to look at trying to unify the cases. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeTableFuncscan.c b/src/backend/executor/nodeTableFuncscan.c index 06437a469148f..4d7eca4acedfa 100644 --- a/src/backend/executor/nodeTableFuncscan.c +++ b/src/backend/executor/nodeTableFuncscan.c @@ -3,7 +3,7 @@ * nodeTableFuncscan.c * Support routines for scanning RangeTableFunc (XMLTABLE like functions). * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c index 8049fdc64eac8..48c3737da2e58 100644 --- a/src/backend/executor/nodeTidscan.c +++ b/src/backend/executor/nodeTidscan.c @@ -3,7 +3,7 @@ * nodeTidscan.c * Routines to support direct tid scans of relations * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeUnique.c b/src/backend/executor/nodeUnique.c index a40d619b0ae6f..9214d6fd28f28 100644 --- a/src/backend/executor/nodeUnique.c +++ b/src/backend/executor/nodeUnique.c @@ -11,7 +11,7 @@ * (It's debatable whether the savings justifies carrying two plan node * types, though.) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c index 88661217e9c1e..5de1429fdaa21 100644 --- a/src/backend/executor/nodeValuesscan.c +++ b/src/backend/executor/nodeValuesscan.c @@ -4,7 +4,7 @@ * Support routines for scanning Values lists * ("VALUES (...), (...), ..." in rangetable). * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c index de58df3d3f733..f8ea9e96d86be 100644 --- a/src/backend/executor/nodeWindowAgg.c +++ b/src/backend/executor/nodeWindowAgg.c @@ -23,7 +23,7 @@ * aggregate function over all rows in the current row's window frame. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/executor/nodeWorktablescan.c b/src/backend/executor/nodeWorktablescan.c index e8f5caf34649e..91d3bf376bc46 100644 --- a/src/backend/executor/nodeWorktablescan.c +++ b/src/backend/executor/nodeWorktablescan.c @@ -3,7 +3,7 @@ * nodeWorktablescan.c * routines to handle WorkTableScan nodes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 055ebb77ae2ae..8368ead1ef6c1 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -3,7 +3,7 @@ * spi.c * Server Programming Interface * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/executor/tqueue.c b/src/backend/executor/tqueue.c index 30a264ebea985..7af9fbe984891 100644 --- a/src/backend/executor/tqueue.c +++ b/src/backend/executor/tqueue.c @@ -8,7 +8,7 @@ * * A TupleQueueReader reads tuples from a shm_mq and returns the tuples. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/executor/tstoreReceiver.c b/src/backend/executor/tstoreReceiver.c index e8172bedd0192..e07664ff7085d 100644 --- a/src/backend/executor/tstoreReceiver.c +++ b/src/backend/executor/tstoreReceiver.c @@ -11,7 +11,7 @@ * Also optionally, we can apply a tuple conversion map before storing. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c index 3e79c852c1715..5564dc3a1e285 100644 --- a/src/backend/foreign/foreign.c +++ b/src/backend/foreign/foreign.c @@ -3,7 +3,7 @@ * foreign.c * support for foreign-data wrappers, servers and user mappings. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/foreign/foreign.c diff --git a/src/backend/jit/jit.c b/src/backend/jit/jit.c index 5ca3f922fed79..2da300e000d48 100644 --- a/src/backend/jit/jit.c +++ b/src/backend/jit/jit.c @@ -8,7 +8,7 @@ * should end up here. * * - * Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Copyright (c) 2016-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/jit/jit.c diff --git a/src/backend/jit/llvm/llvmjit.c b/src/backend/jit/llvm/llvmjit.c index 9c4fc75f6567a..b0789a5fb8012 100644 --- a/src/backend/jit/llvm/llvmjit.c +++ b/src/backend/jit/llvm/llvmjit.c @@ -3,7 +3,7 @@ * llvmjit.c * Core part of the LLVM JIT provider. * - * Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Copyright (c) 2016-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/jit/llvm/llvmjit.c diff --git a/src/backend/jit/llvm/llvmjit_deform.c b/src/backend/jit/llvm/llvmjit_deform.c index 8a3064e6819bf..008cd617f6c1d 100644 --- a/src/backend/jit/llvm/llvmjit_deform.c +++ b/src/backend/jit/llvm/llvmjit_deform.c @@ -7,7 +7,7 @@ * knowledge of the tuple descriptor. Fixed column widths, NOT NULLness, etc * can be taken advantage of. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/jit/llvm/llvmjit_error.cpp b/src/backend/jit/llvm/llvmjit_error.cpp index b36c8d53261be..26bc828875ec7 100644 --- a/src/backend/jit/llvm/llvmjit_error.cpp +++ b/src/backend/jit/llvm/llvmjit_error.cpp @@ -6,7 +6,7 @@ * Unfortunately neither (re)setting the C++ new handler, nor the LLVM OOM * handler are exposed to C. Therefore this file wraps the necessary code. * - * Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Copyright (c) 2016-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/jit/llvm/llvmjit_error.cpp diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c index 3aa08a974300e..42bf4754c526f 100644 --- a/src/backend/jit/llvm/llvmjit_expr.c +++ b/src/backend/jit/llvm/llvmjit_expr.c @@ -3,7 +3,7 @@ * llvmjit_expr.c * JIT compile expressions. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/jit/llvm/llvmjit_inline.cpp b/src/backend/jit/llvm/llvmjit_inline.cpp index 2617a461caddf..ea90fd5b24f4b 100644 --- a/src/backend/jit/llvm/llvmjit_inline.cpp +++ b/src/backend/jit/llvm/llvmjit_inline.cpp @@ -11,7 +11,7 @@ * so for all external functions, all the referenced functions (and * prerequisites) will be imported. * - * Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Copyright (c) 2016-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/lib/llvmjit/llvmjit_inline.cpp diff --git a/src/backend/jit/llvm/llvmjit_types.c b/src/backend/jit/llvm/llvmjit_types.c index fb7400e99d4de..8bc58b641cfbe 100644 --- a/src/backend/jit/llvm/llvmjit_types.c +++ b/src/backend/jit/llvm/llvmjit_types.c @@ -16,7 +16,7 @@ * bitcode. * * - * Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Copyright (c) 2016-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/jit/llvm/llvmjit_types.c diff --git a/src/backend/jit/llvm/llvmjit_wrap.cpp b/src/backend/jit/llvm/llvmjit_wrap.cpp index 37c006a1ff50f..692483d3b9384 100644 --- a/src/backend/jit/llvm/llvmjit_wrap.cpp +++ b/src/backend/jit/llvm/llvmjit_wrap.cpp @@ -3,7 +3,7 @@ * llvmjit_wrap.cpp * Parts of the LLVM interface not (yet) exposed to C. * - * Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Copyright (c) 2016-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/lib/llvm/llvmjit_wrap.cpp diff --git a/src/backend/lib/binaryheap.c b/src/backend/lib/binaryheap.c index a1b4f62a71e1a..d54e245299194 100644 --- a/src/backend/lib/binaryheap.c +++ b/src/backend/lib/binaryheap.c @@ -3,7 +3,7 @@ * binaryheap.c * A simple binary heap implementation * - * Portions Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2012-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/lib/binaryheap.c diff --git a/src/backend/lib/bipartite_match.c b/src/backend/lib/bipartite_match.c index 9372c0c83a1e9..baa1c139100be 100644 --- a/src/backend/lib/bipartite_match.c +++ b/src/backend/lib/bipartite_match.c @@ -7,7 +7,7 @@ * * https://en.wikipedia.org/w/index.php?title=Hopcroft%E2%80%93Karp_algorithm&oldid=593898016 * - * Copyright (c) 2015-2020, PostgreSQL Global Development Group + * Copyright (c) 2015-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/lib/bipartite_match.c diff --git a/src/backend/lib/bloomfilter.c b/src/backend/lib/bloomfilter.c index f040e83c01629..daf2c40ebf549 100644 --- a/src/backend/lib/bloomfilter.c +++ b/src/backend/lib/bloomfilter.c @@ -24,7 +24,7 @@ * caller many authoritative lookups, such as expensive probes of a much larger * on-disk structure. * - * Copyright (c) 2018-2020, PostgreSQL Global Development Group + * Copyright (c) 2018-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/lib/bloomfilter.c diff --git a/src/backend/lib/dshash.c b/src/backend/lib/dshash.c index 78ccf03217fe1..e0c763be3261a 100644 --- a/src/backend/lib/dshash.c +++ b/src/backend/lib/dshash.c @@ -20,7 +20,7 @@ * Future versions may support iterators and incremental resizing; for now * the implementation is minimalist. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/lib/hyperloglog.c b/src/backend/lib/hyperloglog.c index 351fed8186fb2..f4e02410adb97 100644 --- a/src/backend/lib/hyperloglog.c +++ b/src/backend/lib/hyperloglog.c @@ -3,7 +3,7 @@ * hyperloglog.c * HyperLogLog cardinality estimator * - * Portions Copyright (c) 2014-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2014-2021, PostgreSQL Global Development Group * * Based on Hideaki Ohno's C++ implementation. This is probably not ideally * suited to estimating the cardinality of very large sets; in particular, we diff --git a/src/backend/lib/ilist.c b/src/backend/lib/ilist.c index 9b02d54607602..e9a07c14f7b5b 100644 --- a/src/backend/lib/ilist.c +++ b/src/backend/lib/ilist.c @@ -3,7 +3,7 @@ * ilist.c * support for integrated/inline doubly- and singly- linked lists * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/lib/integerset.c b/src/backend/lib/integerset.c index 069a35fb23cd5..278a91bdbf823 100644 --- a/src/backend/lib/integerset.c +++ b/src/backend/lib/integerset.c @@ -61,7 +61,7 @@ * (https://doi.org/10.1002/spe.948) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/lib/knapsack.c b/src/backend/lib/knapsack.c index 8ab734b445dfe..50c84b4aed18c 100644 --- a/src/backend/lib/knapsack.c +++ b/src/backend/lib/knapsack.c @@ -15,7 +15,7 @@ * allows approximate solutions in polynomial time (the general case of the * exact problem is NP-hard). * - * Copyright (c) 2017-2020, PostgreSQL Global Development Group + * Copyright (c) 2017-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/lib/knapsack.c diff --git a/src/backend/lib/pairingheap.c b/src/backend/lib/pairingheap.c index 1e45729fc7501..bed3d2efb499d 100644 --- a/src/backend/lib/pairingheap.c +++ b/src/backend/lib/pairingheap.c @@ -14,7 +14,7 @@ * The pairing heap: a new form of self-adjusting heap. * Algorithmica 1, 1 (January 1986), pages 111-129. DOI: 10.1007/BF01840439 * - * Portions Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2012-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/lib/pairingheap.c diff --git a/src/backend/lib/rbtree.c b/src/backend/lib/rbtree.c index 28681b8f6118e..536df1f7715b1 100644 --- a/src/backend/lib/rbtree.c +++ b/src/backend/lib/rbtree.c @@ -17,7 +17,7 @@ * longest path from root to leaf is only about twice as long as the shortest, * so lookups are guaranteed to run in O(lg n) time. * - * Copyright (c) 2009-2020, PostgreSQL Global Development Group + * Copyright (c) 2009-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/lib/rbtree.c diff --git a/src/backend/libpq/auth-scram.c b/src/backend/libpq/auth-scram.c index 6879a81618326..8d857f39df5a0 100644 --- a/src/backend/libpq/auth-scram.c +++ b/src/backend/libpq/auth-scram.c @@ -80,7 +80,7 @@ * general, after logging in, but let's do what we can here. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/libpq/auth-scram.c diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index e51ede5a2228f..545635f41a916 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -3,7 +3,7 @@ * auth.c * Routines to handle network authentication * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/libpq/be-fsstubs.c b/src/backend/libpq/be-fsstubs.c index 6073540d8d9ad..70b4111c14bec 100644 --- a/src/backend/libpq/be-fsstubs.c +++ b/src/backend/libpq/be-fsstubs.c @@ -3,7 +3,7 @@ * be-fsstubs.c * Builtin functions for open/close/read/write operations on large objects * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/libpq/be-gssapi-common.c b/src/backend/libpq/be-gssapi-common.c index be5d051c2027a..cb2df0bfb3dff 100644 --- a/src/backend/libpq/be-gssapi-common.c +++ b/src/backend/libpq/be-gssapi-common.c @@ -3,7 +3,7 @@ * be-gssapi-common.c * Common code for GSSAPI authentication and encryption * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/libpq/be-secure-common.c b/src/backend/libpq/be-secure-common.c index 94cdf4c8874da..a212308666a9a 100644 --- a/src/backend/libpq/be-secure-common.c +++ b/src/backend/libpq/be-secure-common.c @@ -8,7 +8,7 @@ * communications code calls, this file contains support routines that are * used by the library-specific implementations such as be-secure-openssl.c. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/libpq/be-secure-gssapi.c b/src/backend/libpq/be-secure-gssapi.c index 547c7d6a177bd..316ca65db55e9 100644 --- a/src/backend/libpq/be-secure-gssapi.c +++ b/src/backend/libpq/be-secure-gssapi.c @@ -3,7 +3,7 @@ * be-secure-gssapi.c * GSSAPI encryption support * - * Portions Copyright (c) 2018-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2018-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/libpq/be-secure-gssapi.c diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c index e10260051f184..0494ad7ded918 100644 --- a/src/backend/libpq/be-secure-openssl.c +++ b/src/backend/libpq/be-secure-openssl.c @@ -4,7 +4,7 @@ * functions for OpenSSL support in the backend. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c index 59bc02e79c68c..4cf139a223fdc 100644 --- a/src/backend/libpq/be-secure.c +++ b/src/backend/libpq/be-secure.c @@ -6,7 +6,7 @@ * message integrity and endpoint authentication. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c index 17b91ac9e6052..3fcad991a7e63 100644 --- a/src/backend/libpq/crypt.c +++ b/src/backend/libpq/crypt.c @@ -4,7 +4,7 @@ * Functions for dealing with encrypted passwords stored in * pg_authid.rolpassword. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/libpq/crypt.c diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c index 99319b273aa9a..371dccb852fd5 100644 --- a/src/backend/libpq/hba.c +++ b/src/backend/libpq/hba.c @@ -5,7 +5,7 @@ * wherein you authenticate a user by seeing what IP address the system * says he comes from and choosing authentication method based on it). * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/libpq/ifaddr.c b/src/backend/libpq/ifaddr.c index 82adecbf06f45..75760f3b1c179 100644 --- a/src/backend/libpq/ifaddr.c +++ b/src/backend/libpq/ifaddr.c @@ -3,7 +3,7 @@ * ifaddr.c * IP netmask calculations, and enumerating network interfaces. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 3ea7c6167eb21..1e6b6db54002f 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -27,7 +27,7 @@ * the backend's "backend/libpq" is quite separate from "interfaces/libpq". * All that remains is similarities of names to trap the unwary... * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/libpq/pqcomm.c diff --git a/src/backend/libpq/pqformat.c b/src/backend/libpq/pqformat.c index a6f990c2d299c..19998988190c9 100644 --- a/src/backend/libpq/pqformat.c +++ b/src/backend/libpq/pqformat.c @@ -21,7 +21,7 @@ * are different. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/libpq/pqformat.c diff --git a/src/backend/libpq/pqmq.c b/src/backend/libpq/pqmq.c index f51d935daf83f..f468441b7a2c7 100644 --- a/src/backend/libpq/pqmq.c +++ b/src/backend/libpq/pqmq.c @@ -3,7 +3,7 @@ * pqmq.c * Use the frontend/backend protocol for communication over a shm_mq * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/libpq/pqmq.c diff --git a/src/backend/libpq/pqsignal.c b/src/backend/libpq/pqsignal.c index 9289493118f9d..b43af220303e7 100644 --- a/src/backend/libpq/pqsignal.c +++ b/src/backend/libpq/pqsignal.c @@ -3,7 +3,7 @@ * pqsignal.c * Backend signal(2) support (see also src/port/pqsignal.c) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/main/main.c b/src/backend/main/main.c index b6e5128832690..e58e24a6465e1 100644 --- a/src/backend/main/main.c +++ b/src/backend/main/main.c @@ -9,7 +9,7 @@ * proper FooMain() routine for the incarnation. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/nodes/bitmapset.c b/src/backend/nodes/bitmapset.c index 2719ea45a3eb5..649478b0d4d39 100644 --- a/src/backend/nodes/bitmapset.c +++ b/src/backend/nodes/bitmapset.c @@ -11,7 +11,7 @@ * bms_is_empty() in preference to testing for NULL.) * * - * Copyright (c) 2003-2020, PostgreSQL Global Development Group + * Copyright (c) 2003-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/nodes/bitmapset.c diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 70f8b718e0d6c..67d45418662a4 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -11,7 +11,7 @@ * be handled easily in a simple depth-first traversal. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 541e0e6b48522..4d4258b0cb2ce 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -18,7 +18,7 @@ * "x" to be considered equal() to another reference to "x" in the query. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/nodes/extensible.c b/src/backend/nodes/extensible.c index 3a6cfc44d3d72..1489df0729a6f 100644 --- a/src/backend/nodes/extensible.c +++ b/src/backend/nodes/extensible.c @@ -10,7 +10,7 @@ * and GetExtensibleNodeMethods to get information about a previously * registered type of extensible node. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/nodes/list.c b/src/backend/nodes/list.c index efa44342c4b8a..c4eba6b053f86 100644 --- a/src/backend/nodes/list.c +++ b/src/backend/nodes/list.c @@ -6,7 +6,7 @@ * See comments in pg_list.h. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c index ee033ae779446..01c110cd2fc17 100644 --- a/src/backend/nodes/makefuncs.c +++ b/src/backend/nodes/makefuncs.c @@ -4,7 +4,7 @@ * creator functions for various nodes. The functions here are for the * most frequently created nodes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index 963f71e99d4fd..a011bc7b98d7c 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -3,7 +3,7 @@ * nodeFuncs.c * Various general-purpose manipulations of Node trees * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/nodes/nodes.c b/src/backend/nodes/nodes.c index e5dcda3f58ca7..a292b412f282e 100644 --- a/src/backend/nodes/nodes.c +++ b/src/backend/nodes/nodes.c @@ -4,7 +4,7 @@ * support code for nodes (now that we have removed the home-brew * inheritance system, our support code for nodes is much simpler) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index d78b16ed1d95d..6b8ec03fa7738 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -3,7 +3,7 @@ * outfuncs.c * Output functions for Postgres tree nodes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/nodes/params.c b/src/backend/nodes/params.c index c05f04a259c1b..45ebff5103e0c 100644 --- a/src/backend/nodes/params.c +++ b/src/backend/nodes/params.c @@ -4,7 +4,7 @@ * Support for finding the values associated with Param nodes. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/nodes/print.c b/src/backend/nodes/print.c index 970a2d438402a..25ebc76fc5ef5 100644 --- a/src/backend/nodes/print.c +++ b/src/backend/nodes/print.c @@ -3,7 +3,7 @@ * print.c * various print routines (used mostly for debugging) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/nodes/read.c b/src/backend/nodes/read.c index 8c1e39044c81a..d281f7db6c3af 100644 --- a/src/backend/nodes/read.c +++ b/src/backend/nodes/read.c @@ -4,7 +4,7 @@ * routines to convert a string (legal ascii representation of node) back * to nodes * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 0f6a77afc4395..d2c8d58070bcd 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -3,7 +3,7 @@ * readfuncs.c * Reader functions for Postgres tree nodes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/nodes/tidbitmap.c b/src/backend/nodes/tidbitmap.c index 0d5056c3e3dde..c5feacbff48fc 100644 --- a/src/backend/nodes/tidbitmap.c +++ b/src/backend/nodes/tidbitmap.c @@ -29,7 +29,7 @@ * and a non-lossy page. * * - * Copyright (c) 2003-2020, PostgreSQL Global Development Group + * Copyright (c) 2003-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/nodes/tidbitmap.c diff --git a/src/backend/nodes/value.c b/src/backend/nodes/value.c index 45b9b8473e01a..15e6d26752186 100644 --- a/src/backend/nodes/value.c +++ b/src/backend/nodes/value.c @@ -4,7 +4,7 @@ * implementation of Value nodes * * - * Copyright (c) 2003-2020, PostgreSQL Global Development Group + * Copyright (c) 2003-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/optimizer/geqo/geqo_copy.c b/src/backend/optimizer/geqo/geqo_copy.c index a4bfb1ef2acc7..4f6226b0287ab 100644 --- a/src/backend/optimizer/geqo/geqo_copy.c +++ b/src/backend/optimizer/geqo/geqo_copy.c @@ -2,7 +2,7 @@ * * geqo_copy.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/optimizer/geqo/geqo_copy.c diff --git a/src/backend/optimizer/geqo/geqo_eval.c b/src/backend/optimizer/geqo/geqo_eval.c index ff33acc7b66f1..2ecba83490f82 100644 --- a/src/backend/optimizer/geqo/geqo_eval.c +++ b/src/backend/optimizer/geqo/geqo_eval.c @@ -3,7 +3,7 @@ * geqo_eval.c * Routines to evaluate query trees * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/optimizer/geqo/geqo_eval.c diff --git a/src/backend/optimizer/geqo/geqo_main.c b/src/backend/optimizer/geqo/geqo_main.c index 2db490de598cb..09d9e7d4dd61d 100644 --- a/src/backend/optimizer/geqo/geqo_main.c +++ b/src/backend/optimizer/geqo/geqo_main.c @@ -4,7 +4,7 @@ * solution to the query optimization problem * by means of a Genetic Algorithm (GA) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/optimizer/geqo/geqo_main.c diff --git a/src/backend/optimizer/geqo/geqo_misc.c b/src/backend/optimizer/geqo/geqo_misc.c index 06755c0f63a8d..02b5a7015b7fd 100644 --- a/src/backend/optimizer/geqo/geqo_misc.c +++ b/src/backend/optimizer/geqo/geqo_misc.c @@ -3,7 +3,7 @@ * geqo_misc.c * misc. printout and debug stuff * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/optimizer/geqo/geqo_misc.c diff --git a/src/backend/optimizer/geqo/geqo_pool.c b/src/backend/optimizer/geqo/geqo_pool.c index 74dc51091d64c..1fc103ba1132f 100644 --- a/src/backend/optimizer/geqo/geqo_pool.c +++ b/src/backend/optimizer/geqo/geqo_pool.c @@ -3,7 +3,7 @@ * geqo_pool.c * Genetic Algorithm (GA) pool stuff * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/optimizer/geqo/geqo_pool.c diff --git a/src/backend/optimizer/geqo/geqo_random.c b/src/backend/optimizer/geqo/geqo_random.c index d8e6895a6efe7..f21bc047e68b5 100644 --- a/src/backend/optimizer/geqo/geqo_random.c +++ b/src/backend/optimizer/geqo/geqo_random.c @@ -3,7 +3,7 @@ * geqo_random.c * random number generator * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/optimizer/geqo/geqo_random.c diff --git a/src/backend/optimizer/geqo/geqo_selection.c b/src/backend/optimizer/geqo/geqo_selection.c index 5eecefc6a9768..66b6c8ae38e45 100644 --- a/src/backend/optimizer/geqo/geqo_selection.c +++ b/src/backend/optimizer/geqo/geqo_selection.c @@ -3,7 +3,7 @@ * geqo_selection.c * linear selection scheme for the genetic query optimizer * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/optimizer/geqo/geqo_selection.c diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 627d08b78a48f..026a4b08481c9 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -3,7 +3,7 @@ * allpaths.c * Routines to find possible search paths for processing a query * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c index a7e535c27f5a1..4f5b870d1bc21 100644 --- a/src/backend/optimizer/path/clausesel.c +++ b/src/backend/optimizer/path/clausesel.c @@ -3,7 +3,7 @@ * clausesel.c * Routines to compute clause selectivities * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 22d6935824a48..380336518fed7 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -60,7 +60,7 @@ * values. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c index c33af06ec0ed6..ab6eaaead12ee 100644 --- a/src/backend/optimizer/path/equivclass.c +++ b/src/backend/optimizer/path/equivclass.c @@ -6,7 +6,7 @@ * See src/backend/optimizer/README for discussion of EquivalenceClasses. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index bcb1bc6097d01..9c069a213f9b6 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -4,7 +4,7 @@ * Routines to determine which indexes are usable for scanning a * given relation, and create Paths accordingly. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index 4a35903b29f74..57ce97fd53bd1 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -3,7 +3,7 @@ * joinpath.c * Routines to find all possible paths for processing a set of joins * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c index 2d343cd29346d..e19d2e82289eb 100644 --- a/src/backend/optimizer/path/joinrels.c +++ b/src/backend/optimizer/path/joinrels.c @@ -3,7 +3,7 @@ * joinrels.c * Routines to determine which relations should be joined * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c index ce9bf87e9b65a..3ebc57a154567 100644 --- a/src/backend/optimizer/path/pathkeys.c +++ b/src/backend/optimizer/path/pathkeys.c @@ -7,7 +7,7 @@ * the nature and use of path keys. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/optimizer/path/tidpath.c b/src/backend/optimizer/path/tidpath.c index 1463a82be87a8..8ef04060570e9 100644 --- a/src/backend/optimizer/path/tidpath.c +++ b/src/backend/optimizer/path/tidpath.c @@ -24,7 +24,7 @@ * representation all the way through to execution. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/plan/analyzejoins.c b/src/backend/optimizer/plan/analyzejoins.c index 806629fff210b..90460a69bdf4f 100644 --- a/src/backend/optimizer/plan/analyzejoins.c +++ b/src/backend/optimizer/plan/analyzejoins.c @@ -11,7 +11,7 @@ * is that we have to work harder to clean up after ourselves when we modify * the query, since the derived data structures have to be updated too. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index f7a8dae3c6483..25d4750ca66af 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -5,7 +5,7 @@ * Planning is complete, we just need to convert the selected * Path into a Plan. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index aae5df09f9b7f..ac7dd5d4c8689 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -3,7 +3,7 @@ * initsplan.c * Target list, qualification, joininfo initialization routines * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/plan/planagg.c b/src/backend/optimizer/plan/planagg.c index 48c4fee8923b8..c1634d1666942 100644 --- a/src/backend/optimizer/plan/planagg.c +++ b/src/backend/optimizer/plan/planagg.c @@ -17,7 +17,7 @@ * scan all the rows anyway. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c index 62dfc6d44a82e..e1a13e20c5a84 100644 --- a/src/backend/optimizer/plan/planmain.c +++ b/src/backend/optimizer/plan/planmain.c @@ -9,7 +9,7 @@ * shorn of features like subselects, inheritance, aggregates, grouping, * and so on. (Those are the things planner.c deals with.) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 1a94b58f8beee..4e6497ff32877 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -3,7 +3,7 @@ * planner.c * The query optimizer external interface. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 127ea3d856dcb..c3c36be13e10e 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -4,7 +4,7 @@ * Post-processing of a completed plan tree: fix references to subplan * vars, compute regproc values for operators, etc * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index fcce81926b7d6..6d4cc1bcce4aa 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -6,7 +6,7 @@ * This module deals with SubLinks and CTEs, but not subquery RTEs (i.e., * not sub-SELECT-in-FROM cases). * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/optimizer/prep/prepagg.c b/src/backend/optimizer/prep/prepagg.c index 34ac985a6649d..929a8ea13bc04 100644 --- a/src/backend/optimizer/prep/prepagg.c +++ b/src/backend/optimizer/prep/prepagg.c @@ -22,7 +22,7 @@ * at executor startup. The Agg nodes are constructed much later in the * planning, however, so it's not trivial. * - * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c index ce57dfa7cde72..f9ef96991df05 100644 --- a/src/backend/optimizer/prep/prepjointree.c +++ b/src/backend/optimizer/prep/prepjointree.c @@ -14,7 +14,7 @@ * remove_useless_result_rtes * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/prep/prepqual.c b/src/backend/optimizer/prep/prepqual.c index 391bdd659d257..8d4dc9cd10532 100644 --- a/src/backend/optimizer/prep/prepqual.c +++ b/src/backend/optimizer/prep/prepqual.c @@ -19,7 +19,7 @@ * tree after local transformations that might introduce nested AND/ORs. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c index d56d8c6509cde..23f9f861f4428 100644 --- a/src/backend/optimizer/prep/preptlist.c +++ b/src/backend/optimizer/prep/preptlist.c @@ -29,7 +29,7 @@ * that because it's faster in typical non-inherited cases. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index 745f443e5c2df..86f794c19358b 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -12,7 +12,7 @@ * case, but most of the heavy lifting for that is done elsewhere, * notably in prepjointree.c and allpaths.c. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/util/appendinfo.c b/src/backend/optimizer/util/appendinfo.c index d722063cf3b49..86922a273c6eb 100644 --- a/src/backend/optimizer/util/appendinfo.c +++ b/src/backend/optimizer/util/appendinfo.c @@ -3,7 +3,7 @@ * appendinfo.c * Routines for mapping between append parent(s) and children * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 8f5cbf99f43e0..51d26a0691566 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -3,7 +3,7 @@ * clauses.c * routines to manipulate qualification clauses * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/util/inherit.c b/src/backend/optimizer/util/inherit.c index 3132fd35a5185..36d248beb5114 100644 --- a/src/backend/optimizer/util/inherit.c +++ b/src/backend/optimizer/util/inherit.c @@ -3,7 +3,7 @@ * inherit.c * Routines to process child relations in inheritance trees * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/util/joininfo.c b/src/backend/optimizer/util/joininfo.c index ad35f1c4670a7..717808b0377c9 100644 --- a/src/backend/optimizer/util/joininfo.c +++ b/src/backend/optimizer/util/joininfo.c @@ -3,7 +3,7 @@ * joininfo.c * joininfo list manipulation routines * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/util/orclauses.c b/src/backend/optimizer/util/orclauses.c index 002a70e1ed168..a4de576fd8ad9 100644 --- a/src/backend/optimizer/util/orclauses.c +++ b/src/backend/optimizer/util/orclauses.c @@ -3,7 +3,7 @@ * orclauses.c * Routines to extract restriction OR clauses from join OR clauses * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/util/paramassign.c b/src/backend/optimizer/util/paramassign.c index 93fae07311c5c..ebb424112b17f 100644 --- a/src/backend/optimizer/util/paramassign.c +++ b/src/backend/optimizer/util/paramassign.c @@ -40,7 +40,7 @@ * doesn't really save much executor work anyway. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index 51478957fb353..d465b9e213731 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -3,7 +3,7 @@ * pathnode.c * Routines to manipulate pathlists and create path nodes * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/util/placeholder.c b/src/backend/optimizer/util/placeholder.c index bf991018abb68..2f21455c7bc47 100644 --- a/src/backend/optimizer/util/placeholder.c +++ b/src/backend/optimizer/util/placeholder.c @@ -4,7 +4,7 @@ * PlaceHolderVar and PlaceHolderInfo manipulation routines * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index daf17596233f1..da322b453ea74 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -4,7 +4,7 @@ * routines for accessing the system catalogs * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c index d6e83e5f8e5fe..f8be7283f7c05 100644 --- a/src/backend/optimizer/util/predtest.c +++ b/src/backend/optimizer/util/predtest.c @@ -4,7 +4,7 @@ * Routines to attempt to prove logical implications between predicate * expressions. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index 9c9a738c80355..731ff708b905e 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -3,7 +3,7 @@ * relnode.c * Relation-node lookup/construction routines * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c index 7075e93973de3..221e1caa68153 100644 --- a/src/backend/optimizer/util/restrictinfo.c +++ b/src/backend/optimizer/util/restrictinfo.c @@ -3,7 +3,7 @@ * restrictinfo.c * RestrictInfo node manipulation routines. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/util/tlist.c b/src/backend/optimizer/util/tlist.c index 01cea102eab1a..89853a0630236 100644 --- a/src/backend/optimizer/util/tlist.c +++ b/src/backend/optimizer/util/tlist.c @@ -3,7 +3,7 @@ * tlist.c * Target list manipulation routines * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c index 029d546ab2be4..19b2bba707766 100644 --- a/src/backend/optimizer/util/var.c +++ b/src/backend/optimizer/util/var.c @@ -9,7 +9,7 @@ * contains variables. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 084e00f73d818..1066f9458f389 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -14,7 +14,7 @@ * contain optimizable statements, which we should transform. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/parser/analyze.c diff --git a/src/backend/parser/check_keywords.pl b/src/backend/parser/check_keywords.pl index e6c6c98fb5ec7..598f3d20e3573 100644 --- a/src/backend/parser/check_keywords.pl +++ b/src/backend/parser/check_keywords.pl @@ -4,7 +4,7 @@ # Usage: check_keywords.pl gram.y kwlist.h # src/backend/parser/check_keywords.pl -# Copyright (c) 2009-2020, PostgreSQL Global Development Group +# Copyright (c) 2009-2021, PostgreSQL Global Development Group use strict; use warnings; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 8f341ac006126..18e181d5005df 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -6,7 +6,7 @@ * gram.y * POSTGRESQL BISON rules/actions * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c index 783f3fe8f2d1c..588f005dd93bd 100644 --- a/src/backend/parser/parse_agg.c +++ b/src/backend/parser/parse_agg.c @@ -3,7 +3,7 @@ * parse_agg.c * handle aggregates and window functions in parser * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index ea4a1f5aeb9f5..672245ded7a30 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -3,7 +3,7 @@ * parse_clause.c * handle clauses in parser * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index e33618f9744d3..8d01fca6d2178 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -3,7 +3,7 @@ * parse_coerce.c * handle type coercions/conversions for parser * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/parser/parse_collate.c b/src/backend/parser/parse_collate.c index 13e62a201563c..4133526f04601 100644 --- a/src/backend/parser/parse_collate.c +++ b/src/backend/parser/parse_collate.c @@ -29,7 +29,7 @@ * at runtime. If we knew exactly which functions require collation * information, we could throw those errors at parse time instead. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/parser/parse_cte.c b/src/backend/parser/parse_cte.c index 1fca7485ca3ba..4e0029c58c903 100644 --- a/src/backend/parser/parse_cte.c +++ b/src/backend/parser/parse_cte.c @@ -3,7 +3,7 @@ * parse_cte.c * handle CTEs (common table expressions) in parser * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/parser/parse_enr.c b/src/backend/parser/parse_enr.c index 625ded0707a85..8a4071a819a98 100644 --- a/src/backend/parser/parse_enr.c +++ b/src/backend/parser/parse_enr.c @@ -3,7 +3,7 @@ * parse_enr.c * parser support routines dealing with ephemeral named relations * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index ffc96e2a6faff..379355f9bff0b 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -3,7 +3,7 @@ * parse_expr.c * handle expressions in parser * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 23ac2a2fe6533..07d0013e84b19 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -3,7 +3,7 @@ * parse_func.c * handle function calls in parser * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c index 3e20dfff2e250..17c900da31b35 100644 --- a/src/backend/parser/parse_node.c +++ b/src/backend/parser/parse_node.c @@ -3,7 +3,7 @@ * parse_node.c * various routines that make nodes for querytrees * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c index e72d3676f16ed..24013bcac9c61 100644 --- a/src/backend/parser/parse_oper.c +++ b/src/backend/parser/parse_oper.c @@ -3,7 +3,7 @@ * parse_oper.c * handle operator things for parser * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/parser/parse_param.c b/src/backend/parser/parse_param.c index 93c9d82d017d5..68a5534393968 100644 --- a/src/backend/parser/parse_param.c +++ b/src/backend/parser/parse_param.c @@ -12,7 +12,7 @@ * Note that other approaches to parameters are possible using the parser * hooks defined in ParseState. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index a56bd86181a70..e490043cf55f0 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -3,7 +3,7 @@ * parse_relation.c * parser support routines dealing with relations * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index 3dda8e2847db5..fdf5500bf2003 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -3,7 +3,7 @@ * parse_target.c * handle target lists * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c index 2709f6f9c7953..717125ad87388 100644 --- a/src/backend/parser/parse_type.c +++ b/src/backend/parser/parse_type.c @@ -3,7 +3,7 @@ * parse_type.c * handle type operations for parser * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index 89ee990599121..b31f3afa0391a 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -16,7 +16,7 @@ * a quick copyObject() call before manipulating the query tree. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/parser/parse_utilcmd.c diff --git a/src/backend/parser/parser.c b/src/backend/parser/parser.c index be86eb37feff8..b897a5160a22c 100644 --- a/src/backend/parser/parser.c +++ b/src/backend/parser/parser.c @@ -10,7 +10,7 @@ * analyze.c and related files. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l index 4eab2980c9908..9f9d8a17061d1 100644 --- a/src/backend/parser/scan.l +++ b/src/backend/parser/scan.l @@ -22,7 +22,7 @@ * Postgres 9.2, this check is made automatically by the Makefile.) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/parser/scansup.c b/src/backend/parser/scansup.c index d07cbafcee757..f55caccddfda4 100644 --- a/src/backend/parser/scansup.c +++ b/src/backend/parser/scansup.c @@ -3,7 +3,7 @@ * scansup.c * scanner support routines used by the core lexer * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/partitioning/partbounds.c b/src/backend/partitioning/partbounds.c index 299f5deb3290a..b9aeb77bc2bad 100644 --- a/src/backend/partitioning/partbounds.c +++ b/src/backend/partitioning/partbounds.c @@ -3,7 +3,7 @@ * partbounds.c * Support routines for manipulating partition bounds * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/partitioning/partdesc.c b/src/backend/partitioning/partdesc.c index 5b0a15ac0b782..f852b6e99de86 100644 --- a/src/backend/partitioning/partdesc.c +++ b/src/backend/partitioning/partdesc.c @@ -3,7 +3,7 @@ * partdesc.c * Support routines for manipulating partition descriptors * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c index e7c7a6deb6a54..fac921eea5b93 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -25,7 +25,7 @@ * * See gen_partprune_steps_internal() for more details on step generation. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/port/atomics.c b/src/backend/port/atomics.c index c4f83706b43bf..f9f8b098a52a0 100644 --- a/src/backend/port/atomics.c +++ b/src/backend/port/atomics.c @@ -3,7 +3,7 @@ * atomics.c * Non-Inline parts of the atomics implementation * - * Portions Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2013-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/port/posix_sema.c b/src/backend/port/posix_sema.c index 277b82ca8037a..114da3b30cbfb 100644 --- a/src/backend/port/posix_sema.c +++ b/src/backend/port/posix_sema.c @@ -15,7 +15,7 @@ * forked backends, but they could not be accessed by exec'd backends. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/port/sysv_sema.c b/src/backend/port/sysv_sema.c index 88c2862d58b53..21c883ba9acd7 100644 --- a/src/backend/port/sysv_sema.c +++ b/src/backend/port/sysv_sema.c @@ -4,7 +4,7 @@ * Implement PGSemaphores using SysV semaphore facilities * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/port/sysv_shmem.c b/src/backend/port/sysv_shmem.c index 203555822d9a6..0cc83ffc16af5 100644 --- a/src/backend/port/sysv_shmem.c +++ b/src/backend/port/sysv_shmem.c @@ -9,7 +9,7 @@ * exist, though, because mmap'd shmem provides no way to find out how * many processes are attached, which we need for interlocking purposes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/port/tas/sunstudio_sparc.s b/src/backend/port/tas/sunstudio_sparc.s index 4bebf079de3fe..b13ca7937cd04 100644 --- a/src/backend/port/tas/sunstudio_sparc.s +++ b/src/backend/port/tas/sunstudio_sparc.s @@ -3,7 +3,7 @@ ! sunstudio_sparc.s ! compare and swap for Sun Studio on Sparc ! -! Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +! Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group ! Portions Copyright (c) 1994, Regents of the University of California ! ! IDENTIFICATION diff --git a/src/backend/port/tas/sunstudio_x86.s b/src/backend/port/tas/sunstudio_x86.s index d95e17384965a..21d6c636412db 100644 --- a/src/backend/port/tas/sunstudio_x86.s +++ b/src/backend/port/tas/sunstudio_x86.s @@ -3,7 +3,7 @@ / sunstudio_x86.s / compare and swap for Sun Studio on x86 / -/ Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +/ Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group / Portions Copyright (c) 1994, Regents of the University of California / / IDENTIFICATION diff --git a/src/backend/port/win32/crashdump.c b/src/backend/port/win32/crashdump.c index 47114d916cc1d..45b6696ba17e6 100644 --- a/src/backend/port/win32/crashdump.c +++ b/src/backend/port/win32/crashdump.c @@ -28,7 +28,7 @@ * be added, though at the cost of a greater chance of the crash dump failing. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/port/win32/crashdump.c diff --git a/src/backend/port/win32/signal.c b/src/backend/port/win32/signal.c index 3218b38240c25..580a517f3f56f 100644 --- a/src/backend/port/win32/signal.c +++ b/src/backend/port/win32/signal.c @@ -3,7 +3,7 @@ * signal.c * Microsoft Windows Win32 Signal Emulation Functions * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/port/win32/signal.c diff --git a/src/backend/port/win32/socket.c b/src/backend/port/win32/socket.c index 7c7611a01e233..a8012c2798df9 100644 --- a/src/backend/port/win32/socket.c +++ b/src/backend/port/win32/socket.c @@ -3,7 +3,7 @@ * socket.c * Microsoft Windows Win32 Socket Functions * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/port/win32/socket.c diff --git a/src/backend/port/win32/timer.c b/src/backend/port/win32/timer.c index bb98178fe1d05..53fdae9468b71 100644 --- a/src/backend/port/win32/timer.c +++ b/src/backend/port/win32/timer.c @@ -8,7 +8,7 @@ * - Does not support interval timer (value->it_interval) * - Only supports ITIMER_REAL * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/port/win32/timer.c diff --git a/src/backend/port/win32_sema.c b/src/backend/port/win32_sema.c index d15c4c1dc4256..858b88adae8b2 100644 --- a/src/backend/port/win32_sema.c +++ b/src/backend/port/win32_sema.c @@ -3,7 +3,7 @@ * win32_sema.c * Microsoft Windows Win32 Semaphores Emulation * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/port/win32_sema.c diff --git a/src/backend/port/win32_shmem.c b/src/backend/port/win32_shmem.c index 30b07303ff7c0..177315f238d07 100644 --- a/src/backend/port/win32_shmem.c +++ b/src/backend/port/win32_shmem.c @@ -3,7 +3,7 @@ * win32_shmem.c * Implement shared memory using win32 facilities * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/port/win32_shmem.c diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index ed127a1032d61..47e60ca5613f8 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -50,7 +50,7 @@ * there is a window (caused by pgstat delay) on which a worker may choose a * table that was already vacuumed; this is a bug in the current design. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c index d209b69ec05e9..dd3dad3de35fa 100644 --- a/src/backend/postmaster/bgworker.c +++ b/src/backend/postmaster/bgworker.c @@ -2,7 +2,7 @@ * bgworker.c * POSTGRES pluggable background workers implementation * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/postmaster/bgworker.c diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c index a7afa758b618d..715d5195bb671 100644 --- a/src/backend/postmaster/bgwriter.c +++ b/src/backend/postmaster/bgwriter.c @@ -24,7 +24,7 @@ * should be killed by SIGQUIT and then a recovery cycle started. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c index a62c6d4d0acc5..54a818bf611a6 100644 --- a/src/backend/postmaster/checkpointer.c +++ b/src/backend/postmaster/checkpointer.c @@ -26,7 +26,7 @@ * restart needs to be forced.) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/postmaster/fork_process.c b/src/backend/postmaster/fork_process.c index 5247b9f23c9f5..62d068bc1e2e7 100644 --- a/src/backend/postmaster/fork_process.c +++ b/src/backend/postmaster/fork_process.c @@ -4,7 +4,7 @@ * EXEC_BACKEND case; it might be extended to do so, but it would be * considerably more complex. * - * Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/postmaster/fork_process.c diff --git a/src/backend/postmaster/interrupt.c b/src/backend/postmaster/interrupt.c index ee7dbf924ae62..dd9136a942b6c 100644 --- a/src/backend/postmaster/interrupt.c +++ b/src/backend/postmaster/interrupt.c @@ -3,7 +3,7 @@ * interrupt.c * Interrupt handling routines. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c index ed1b65358df85..edec311f12e56 100644 --- a/src/backend/postmaster/pgarch.c +++ b/src/backend/postmaster/pgarch.c @@ -14,7 +14,7 @@ * * Initial author: Simon Riggs simon@2ndquadrant.com * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index 123369f4faff4..3f24a33ef1da4 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -11,7 +11,7 @@ * - Add a pgstat config column to pg_database, so this * entire thing can be enabled/disabled on a per db basis. * - * Copyright (c) 2001-2020, PostgreSQL Global Development Group + * Copyright (c) 2001-2021, PostgreSQL Global Development Group * * src/backend/postmaster/pgstat.c * ---------- diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index b3ccd18cda6e5..7de27ee4e0171 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -32,7 +32,7 @@ * clients. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/postmaster/startup.c b/src/backend/postmaster/startup.c index 64af7b8707cc6..f781fdc6fcab5 100644 --- a/src/backend/postmaster/startup.c +++ b/src/backend/postmaster/startup.c @@ -9,7 +9,7 @@ * though.) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c index faa82ec48158d..d3bcc4b118e7e 100644 --- a/src/backend/postmaster/syslogger.c +++ b/src/backend/postmaster/syslogger.c @@ -13,7 +13,7 @@ * * Author: Andreas Pflug * - * Copyright (c) 2004-2020, PostgreSQL Global Development Group + * Copyright (c) 2004-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c index a52832fe900aa..4f1a8e356b96f 100644 --- a/src/backend/postmaster/walwriter.c +++ b/src/backend/postmaster/walwriter.c @@ -31,7 +31,7 @@ * should be killed by SIGQUIT and then a recovery cycle started. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/regex/regc_pg_locale.c b/src/backend/regex/regc_pg_locale.c index 3cc2d4d362776..1fff3df1daedc 100644 --- a/src/backend/regex/regc_pg_locale.c +++ b/src/backend/regex/regc_pg_locale.c @@ -6,7 +6,7 @@ * * This file is #included by regcomp.c; it's not meant to compile standalone. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/regex/regexport.c b/src/backend/regex/regexport.c index a925a9f9a003a..d4f940b8c3493 100644 --- a/src/backend/regex/regexport.c +++ b/src/backend/regex/regexport.c @@ -15,7 +15,7 @@ * allows the caller to decide how big is too big to bother with. * * - * Portions Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2013-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1998, 1999 Henry Spencer * * IDENTIFICATION diff --git a/src/backend/regex/regprefix.c b/src/backend/regex/regprefix.c index 991b8689bef48..1d4593ac945c9 100644 --- a/src/backend/regex/regprefix.c +++ b/src/backend/regex/regprefix.c @@ -4,7 +4,7 @@ * Extract a common prefix, if any, from a compiled regex. * * - * Portions Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2012-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1998, 1999 Henry Spencer * * IDENTIFICATION diff --git a/src/backend/replication/backup_manifest.c b/src/backend/replication/backup_manifest.c index c3f339c55631d..8af94610b3989 100644 --- a/src/backend/replication/backup_manifest.c +++ b/src/backend/replication/backup_manifest.c @@ -3,7 +3,7 @@ * backup_manifest.c * code for generating and sending a backup manifest * - * Portions Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/replication/backup_manifest.c diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c index 1d8d1742a73a0..0f54635550b98 100644 --- a/src/backend/replication/basebackup.c +++ b/src/backend/replication/basebackup.c @@ -3,7 +3,7 @@ * basebackup.c * code for taking a base backup and streaming it to a standby * - * Portions Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/replication/basebackup.c diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c index 24f8b3e42ecee..e9582748617f0 100644 --- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c +++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c @@ -6,7 +6,7 @@ * loaded as a dynamic module to avoid linking the main server binary with * libpq. * - * Portions Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c index 3f84ee99b8633..1887ba79440ec 100644 --- a/src/backend/replication/logical/decode.c +++ b/src/backend/replication/logical/decode.c @@ -16,7 +16,7 @@ * contents of records in here except turning them into a more usable * format. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c index bdaf0312d63dc..186514cd9ed43 100644 --- a/src/backend/replication/logical/launcher.c +++ b/src/backend/replication/logical/launcher.c @@ -2,7 +2,7 @@ * launcher.c * PostgreSQL logical replication worker launcher process * - * Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Copyright (c) 2016-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/replication/logical/launcher.c diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c index 6e3de92a67c54..e49b511517517 100644 --- a/src/backend/replication/logical/logical.c +++ b/src/backend/replication/logical/logical.c @@ -2,7 +2,7 @@ * logical.c * PostgreSQL logical decoding coordination * - * Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Copyright (c) 2012-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/replication/logical/logical.c diff --git a/src/backend/replication/logical/logicalfuncs.c b/src/backend/replication/logical/logicalfuncs.c index b99c94e84891a..f7e055874e305 100644 --- a/src/backend/replication/logical/logicalfuncs.c +++ b/src/backend/replication/logical/logicalfuncs.c @@ -6,7 +6,7 @@ * logical replication slots via SQL. * * - * Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Copyright (c) 2012-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/replication/logicalfuncs.c diff --git a/src/backend/replication/logical/message.c b/src/backend/replication/logical/message.c index dfccccf270124..93bd372421a64 100644 --- a/src/backend/replication/logical/message.c +++ b/src/backend/replication/logical/message.c @@ -3,7 +3,7 @@ * message.c * Generic logical messages. * - * Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Copyright (c) 2013-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/replication/logical/message.c diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c index 15ab8e7204b6c..0b01cce44e0c3 100644 --- a/src/backend/replication/logical/origin.c +++ b/src/backend/replication/logical/origin.c @@ -3,7 +3,7 @@ * origin.c * Logical replication progress tracking support. * - * Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Copyright (c) 2013-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/replication/logical/origin.c diff --git a/src/backend/replication/logical/proto.c b/src/backend/replication/logical/proto.c index fdb31182d77f0..62275ebabeaef 100644 --- a/src/backend/replication/logical/proto.c +++ b/src/backend/replication/logical/proto.c @@ -3,7 +3,7 @@ * proto.c * logical replication protocol functions * - * Copyright (c) 2015-2020, PostgreSQL Global Development Group + * Copyright (c) 2015-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/replication/logical/proto.c diff --git a/src/backend/replication/logical/relation.c b/src/backend/replication/logical/relation.c index f4dbbbe2dde4f..e861c0ff8029d 100644 --- a/src/backend/replication/logical/relation.c +++ b/src/backend/replication/logical/relation.c @@ -2,7 +2,7 @@ * relation.c * PostgreSQL logical replication relation mapping cache * - * Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Copyright (c) 2016-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/replication/logical/relation.c diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c index 6b0a59efaf575..df63b90a67a10 100644 --- a/src/backend/replication/logical/reorderbuffer.c +++ b/src/backend/replication/logical/reorderbuffer.c @@ -4,7 +4,7 @@ * PostgreSQL logical replay/reorder buffer management * * - * Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Copyright (c) 2012-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c index 9d5d68f3fa785..6afc25e8d3d82 100644 --- a/src/backend/replication/logical/snapbuild.c +++ b/src/backend/replication/logical/snapbuild.c @@ -107,7 +107,7 @@ * is a convenient point to initialize replication from, which is why we * export a snapshot at that point, which *can* be used to read normal data. * - * Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Copyright (c) 2012-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/replication/snapbuild.c diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c index 6259606537329..863d196fd7c66 100644 --- a/src/backend/replication/logical/tablesync.c +++ b/src/backend/replication/logical/tablesync.c @@ -2,7 +2,7 @@ * tablesync.c * PostgreSQL logical replication: initial table data synchronization * - * Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Copyright (c) 2012-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/replication/logical/tablesync.c diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c index 3874939380079..1b1d70ed68aa5 100644 --- a/src/backend/replication/logical/worker.c +++ b/src/backend/replication/logical/worker.c @@ -2,7 +2,7 @@ * worker.c * PostgreSQL logical replication worker (apply) * - * Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Copyright (c) 2016-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/replication/logical/worker.c diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c index 49d25b02d744b..81dbed33d511c 100644 --- a/src/backend/replication/pgoutput/pgoutput.c +++ b/src/backend/replication/pgoutput/pgoutput.c @@ -3,7 +3,7 @@ * pgoutput.c * Logical Replication output plugin * - * Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Copyright (c) 2012-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/replication/pgoutput/pgoutput.c diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y index f93a0de2187fb..eb283a86327c8 100644 --- a/src/backend/replication/repl_gram.y +++ b/src/backend/replication/repl_gram.y @@ -3,7 +3,7 @@ * * repl_gram.y - Parser for the replication commands * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/replication/repl_scanner.l b/src/backend/replication/repl_scanner.l index 452ad9fc278e8..dcc3c3fc515cb 100644 --- a/src/backend/replication/repl_scanner.l +++ b/src/backend/replication/repl_scanner.l @@ -4,7 +4,7 @@ * repl_scanner.l * a lexical scanner for the replication commands * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c index 9c7cf13d4d9c2..e00c7ffc013b0 100644 --- a/src/backend/replication/slot.c +++ b/src/backend/replication/slot.c @@ -4,7 +4,7 @@ * Replication slot management. * * - * Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Copyright (c) 2012-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c index 1725ad0736fd5..057f41046dd04 100644 --- a/src/backend/replication/slotfuncs.c +++ b/src/backend/replication/slotfuncs.c @@ -3,7 +3,7 @@ * slotfuncs.c * Support functions for replication slots * - * Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Copyright (c) 2012-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/replication/slotfuncs.c diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c index 6e8c76537af0a..1c1bf1605285b 100644 --- a/src/backend/replication/syncrep.c +++ b/src/backend/replication/syncrep.c @@ -63,7 +63,7 @@ * the standbys which are considered as synchronous at that moment * will release waiters from the queue. * - * Portions Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/replication/syncrep.c diff --git a/src/backend/replication/syncrep_gram.y b/src/backend/replication/syncrep_gram.y index 350195eff6451..88d95f2228625 100644 --- a/src/backend/replication/syncrep_gram.y +++ b/src/backend/replication/syncrep_gram.y @@ -3,7 +3,7 @@ * * syncrep_gram.y - Parser for synchronous_standby_names * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/replication/syncrep_scanner.l b/src/backend/replication/syncrep_scanner.l index 6883f60e18ce9..0491590d060b0 100644 --- a/src/backend/replication/syncrep_scanner.l +++ b/src/backend/replication/syncrep_scanner.l @@ -4,7 +4,7 @@ * syncrep_scanner.l * a lexical scanner for synchronous_standby_names * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index 9621c8d0efe2f..723f513d8bcb2 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -39,7 +39,7 @@ * specific parts are in the libpqwalreceiver module. It's loaded * dynamically to avoid linking the server with libpq. * - * Portions Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/replication/walreceiverfuncs.c b/src/backend/replication/walreceiverfuncs.c index c3e317df9ffc9..69b91a7dab8f5 100644 --- a/src/backend/replication/walreceiverfuncs.c +++ b/src/backend/replication/walreceiverfuncs.c @@ -6,7 +6,7 @@ * with the walreceiver process. Functions implementing walreceiver itself * are in walreceiver.c. * - * Portions Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c index d5c9bc31d8e79..fe0d368a35b01 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -37,7 +37,7 @@ * record, wait for it to be replicated to the standby, and then exit. * * - * Portions Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/replication/walsender.c diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c index e7855fa4512c5..ee4ccbbd3823c 100644 --- a/src/backend/rewrite/rewriteDefine.c +++ b/src/backend/rewrite/rewriteDefine.c @@ -3,7 +3,7 @@ * rewriteDefine.c * routines for defining a rewrite rule * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index c25012f325b4c..0c7508a0d8bb6 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -3,7 +3,7 @@ * rewriteHandler.c * Primary module of query rewriter. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c index a727f41bde34a..d4e0b8b4defe7 100644 --- a/src/backend/rewrite/rewriteManip.c +++ b/src/backend/rewrite/rewriteManip.c @@ -2,7 +2,7 @@ * * rewriteManip.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/rewrite/rewriteRemove.c b/src/backend/rewrite/rewriteRemove.c index a24303fd00c67..a48b15e249da7 100644 --- a/src/backend/rewrite/rewriteRemove.c +++ b/src/backend/rewrite/rewriteRemove.c @@ -3,7 +3,7 @@ * rewriteRemove.c * routines for removing rewrite rules * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/rewrite/rewriteSupport.c b/src/backend/rewrite/rewriteSupport.c index fc9a3b1ebf665..85f1ac953ad1f 100644 --- a/src/backend/rewrite/rewriteSupport.c +++ b/src/backend/rewrite/rewriteSupport.c @@ -3,7 +3,7 @@ * rewriteSupport.c * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/rewrite/rowsecurity.c b/src/backend/rewrite/rowsecurity.c index 0fe2f9ca8388a..fc26cb23a21a0 100644 --- a/src/backend/rewrite/rowsecurity.c +++ b/src/backend/rewrite/rowsecurity.c @@ -29,7 +29,7 @@ * in the current environment, but that may change if the row_security GUC or * the current role changes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California */ #include "postgres.h" diff --git a/src/backend/snowball/dict_snowball.c b/src/backend/snowball/dict_snowball.c index 4e1aceee02573..044e20cef85c3 100644 --- a/src/backend/snowball/dict_snowball.c +++ b/src/backend/snowball/dict_snowball.c @@ -3,7 +3,7 @@ * dict_snowball.c * Snowball dictionary * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/snowball/dict_snowball.c diff --git a/src/backend/snowball/snowball.sql.in b/src/backend/snowball/snowball.sql.in index 0d47facd0020b..3397fb1e02c39 100644 --- a/src/backend/snowball/snowball.sql.in +++ b/src/backend/snowball/snowball.sql.in @@ -1,7 +1,7 @@ /* * text search configuration for _LANGNAME_ language * - * Copyright (c) 2007-2020, PostgreSQL Global Development Group + * Copyright (c) 2007-2021, PostgreSQL Global Development Group * * src/backend/snowball/snowball.sql.in * diff --git a/src/backend/snowball/snowball_func.sql.in b/src/backend/snowball/snowball_func.sql.in index 8e2063b7330de..cb1eaca4fb5f5 100644 --- a/src/backend/snowball/snowball_func.sql.in +++ b/src/backend/snowball/snowball_func.sql.in @@ -1,7 +1,7 @@ /* * Create underlying C functions for Snowball stemmers * - * Copyright (c) 2007-2020, PostgreSQL Global Development Group + * Copyright (c) 2007-2021, PostgreSQL Global Development Group * * src/backend/snowball/snowball_func.sql.in * diff --git a/src/backend/statistics/dependencies.c b/src/backend/statistics/dependencies.c index b1abcde96872c..f6e399b192fbd 100644 --- a/src/backend/statistics/dependencies.c +++ b/src/backend/statistics/dependencies.c @@ -3,7 +3,7 @@ * dependencies.c * POSTGRES functional dependencies * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/statistics/extended_stats.c b/src/backend/statistics/extended_stats.c index 6d26de37f4ddf..a030ea3653af5 100644 --- a/src/backend/statistics/extended_stats.c +++ b/src/backend/statistics/extended_stats.c @@ -6,7 +6,7 @@ * Generic code supporting statistics objects created via CREATE STATISTICS. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c index fae792a2ddf11..abbc1f1ba8b91 100644 --- a/src/backend/statistics/mcv.c +++ b/src/backend/statistics/mcv.c @@ -4,7 +4,7 @@ * POSTGRES multivariate MCV lists * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/statistics/mvdistinct.c b/src/backend/statistics/mvdistinct.c index 4b86f0ab2d13f..9ef21debb63bb 100644 --- a/src/backend/statistics/mvdistinct.c +++ b/src/backend/statistics/mvdistinct.c @@ -13,7 +13,7 @@ * estimates are already available in pg_statistic. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c index a8ce6603ed00b..e9e4f35bb5f2f 100644 --- a/src/backend/storage/buffer/buf_init.c +++ b/src/backend/storage/buffer/buf_init.c @@ -3,7 +3,7 @@ * buf_init.c * buffer manager initialization routines * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/buffer/buf_table.c b/src/backend/storage/buffer/buf_table.c index 4953ae9f82449..caa03ae123351 100644 --- a/src/backend/storage/buffer/buf_table.c +++ b/src/backend/storage/buffer/buf_table.c @@ -10,7 +10,7 @@ * before the lock is released (see notes in README). * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index c5e87071517e8..8f2c482bc8433 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -3,7 +3,7 @@ * bufmgr.c * buffer manager interface routines * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c index 942f8d4edd267..6be80476dbd8c 100644 --- a/src/backend/storage/buffer/freelist.c +++ b/src/backend/storage/buffer/freelist.c @@ -4,7 +4,7 @@ * routines for managing the buffer pool's replacement strategy. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c index cd3475e9e1d3f..04b3558ea3350 100644 --- a/src/backend/storage/buffer/localbuf.c +++ b/src/backend/storage/buffer/localbuf.c @@ -4,7 +4,7 @@ * local buffer manager. Fast buffer manager for temporary tables, * which never need to be WAL-logged or checkpointed, etc. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994-5, Regents of the University of California * * diff --git a/src/backend/storage/file/buffile.c b/src/backend/storage/file/buffile.c index d581f96eda985..a4be5fe5135e4 100644 --- a/src/backend/storage/file/buffile.c +++ b/src/backend/storage/file/buffile.c @@ -3,7 +3,7 @@ * buffile.c * Management of large buffered temporary files. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/storage/file/copydir.c b/src/backend/storage/file/copydir.c index 0cf598dd0c641..da8b7cbeca3e4 100644 --- a/src/backend/storage/file/copydir.c +++ b/src/backend/storage/file/copydir.c @@ -3,7 +3,7 @@ * copydir.c * copies a directory * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * While "xcopy /e /i /q" works fine for copying directories, on Windows XP diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c index f07b5325aa5b8..931ed679307b2 100644 --- a/src/backend/storage/file/fd.c +++ b/src/backend/storage/file/fd.c @@ -3,7 +3,7 @@ * fd.c * Virtual file descriptor code. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/storage/file/reinit.c b/src/backend/storage/file/reinit.c index 8700f7f19a4ae..40c758d789ddb 100644 --- a/src/backend/storage/file/reinit.c +++ b/src/backend/storage/file/reinit.c @@ -3,7 +3,7 @@ * reinit.c * Reinitialization of unlogged relations * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/storage/file/sharedfileset.c b/src/backend/storage/file/sharedfileset.c index 859c22e79b621..de422b1ebdf63 100644 --- a/src/backend/storage/file/sharedfileset.c +++ b/src/backend/storage/file/sharedfileset.c @@ -3,7 +3,7 @@ * sharedfileset.c * Shared temporary file management. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/storage/freespace/freespace.c b/src/backend/storage/freespace/freespace.c index 6a96126b0c2ff..8c12dda2380d0 100644 --- a/src/backend/storage/freespace/freespace.c +++ b/src/backend/storage/freespace/freespace.c @@ -4,7 +4,7 @@ * POSTGRES free space map for quickly finding free space in relations * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/storage/freespace/fsmpage.c b/src/backend/storage/freespace/fsmpage.c index 50f0ada756d2d..88ae51e5265fb 100644 --- a/src/backend/storage/freespace/fsmpage.c +++ b/src/backend/storage/freespace/fsmpage.c @@ -4,7 +4,7 @@ * routines to search and manipulate one FSM page. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/storage/freespace/indexfsm.c b/src/backend/storage/freespace/indexfsm.c index d975c3364b486..d66e10b89d292 100644 --- a/src/backend/storage/freespace/indexfsm.c +++ b/src/backend/storage/freespace/indexfsm.c @@ -4,7 +4,7 @@ * POSTGRES free space map for quickly finding free pages in relations * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/storage/ipc/barrier.c b/src/backend/storage/ipc/barrier.c index 69afd58689885..5c05297a2aa7f 100644 --- a/src/backend/storage/ipc/barrier.c +++ b/src/backend/storage/ipc/barrier.c @@ -3,7 +3,7 @@ * barrier.c * Barriers for synchronizing cooperating processes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * From Wikipedia[1]: "In parallel computing, a barrier is a type of diff --git a/src/backend/storage/ipc/dsm.c b/src/backend/storage/ipc/dsm.c index dffbd8e82a2a2..ae82b4bdc0e26 100644 --- a/src/backend/storage/ipc/dsm.c +++ b/src/backend/storage/ipc/dsm.c @@ -14,7 +14,7 @@ * hard postmaster crash, remaining segments will be removed, if they * still exist, at the next postmaster startup. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/ipc/dsm_impl.c b/src/backend/storage/ipc/dsm_impl.c index d4306418dcb24..f7e292981e4de 100644 --- a/src/backend/storage/ipc/dsm_impl.c +++ b/src/backend/storage/ipc/dsm_impl.c @@ -36,7 +36,7 @@ * * As ever, Windows requires its own implementation. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/ipc/ipc.c b/src/backend/storage/ipc/ipc.c index 36a067c9244c8..4045d7d68a0a3 100644 --- a/src/backend/storage/ipc/ipc.c +++ b/src/backend/storage/ipc/ipc.c @@ -8,7 +8,7 @@ * exit-time cleanup for either a postmaster or a backend. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c index 96c2aaabbd65c..f9bbe97b50750 100644 --- a/src/backend/storage/ipc/ipci.c +++ b/src/backend/storage/ipc/ipci.c @@ -3,7 +3,7 @@ * ipci.c * POSTGRES inter-process communication initialization code. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c index 24afc47d5134b..f2d005eea054a 100644 --- a/src/backend/storage/ipc/latch.c +++ b/src/backend/storage/ipc/latch.c @@ -22,7 +22,7 @@ * The Windows implementation uses Windows events that are inherited by all * postmaster child processes. There's no need for the self-pipe trick there. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/storage/ipc/pmsignal.c b/src/backend/storage/ipc/pmsignal.c index 8ef3f6da4a128..280c2395c9ed3 100644 --- a/src/backend/storage/ipc/pmsignal.c +++ b/src/backend/storage/ipc/pmsignal.c @@ -4,7 +4,7 @@ * routines for signaling between the postmaster and its child processes * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index ee912b9d5e40d..2d202b8ebda57 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -34,7 +34,7 @@ * happen, it would tie up KnownAssignedXids indefinitely, so we protect * ourselves by pruning the array when a valid list of running XIDs arrives. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c index ffe67acea1ce1..583efaecff88e 100644 --- a/src/backend/storage/ipc/procsignal.c +++ b/src/backend/storage/ipc/procsignal.c @@ -4,7 +4,7 @@ * Routines for interprocess signaling * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/storage/ipc/shm_mq.c b/src/backend/storage/ipc/shm_mq.c index ac9d23a3403ad..8a46962f939a3 100644 --- a/src/backend/storage/ipc/shm_mq.c +++ b/src/backend/storage/ipc/shm_mq.c @@ -8,7 +8,7 @@ * and only the receiver may receive. This is intended to allow a user * backend to communicate with worker backends that it has registered. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/storage/ipc/shm_mq.c diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c index bdd72c48fb87d..83c7928d88217 100644 --- a/src/backend/storage/ipc/shm_toc.c +++ b/src/backend/storage/ipc/shm_toc.c @@ -3,7 +3,7 @@ * shm_toc.c * shared memory segment table of contents * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/storage/ipc/shm_toc.c diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c index 4ef8b18656d0c..4425e99f1725b 100644 --- a/src/backend/storage/ipc/shmem.c +++ b/src/backend/storage/ipc/shmem.c @@ -3,7 +3,7 @@ * shmem.c * create shared memory and initialize shared memory data structures. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/ipc/shmqueue.c b/src/backend/storage/ipc/shmqueue.c index d52b28f0fa76f..dc3238cecfab6 100644 --- a/src/backend/storage/ipc/shmqueue.c +++ b/src/backend/storage/ipc/shmqueue.c @@ -3,7 +3,7 @@ * shmqueue.c * shared memory linked lists * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/ipc/signalfuncs.c b/src/backend/storage/ipc/signalfuncs.c index d822e82cb98d1..69fe23a2563eb 100644 --- a/src/backend/storage/ipc/signalfuncs.c +++ b/src/backend/storage/ipc/signalfuncs.c @@ -3,7 +3,7 @@ * signalfuncs.c * Functions for signaling backends * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/ipc/sinval.c b/src/backend/storage/ipc/sinval.c index b5640e46be01e..f585d63e5cdbc 100644 --- a/src/backend/storage/ipc/sinval.c +++ b/src/backend/storage/ipc/sinval.c @@ -3,7 +3,7 @@ * sinval.c * POSTGRES shared cache invalidation communication code. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/ipc/sinvaladt.c b/src/backend/storage/ipc/sinvaladt.c index a9477ccb4a304..946bd8e3cb5ca 100644 --- a/src/backend/storage/ipc/sinvaladt.c +++ b/src/backend/storage/ipc/sinvaladt.c @@ -3,7 +3,7 @@ * sinvaladt.c * POSTGRES shared cache invalidation data manager. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c index da8e83a52582f..cd54ae42793fc 100644 --- a/src/backend/storage/ipc/standby.c +++ b/src/backend/storage/ipc/standby.c @@ -7,7 +7,7 @@ * AccessExclusiveLocks and starting snapshots for Hot Standby mode. * Plus conflict recovery processing. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c index 20130e47b76c1..bee234bffc968 100644 --- a/src/backend/storage/large_object/inv_api.c +++ b/src/backend/storage/large_object/inv_api.c @@ -19,7 +19,7 @@ * memory context given to inv_open (for LargeObjectDesc structs). * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/lmgr/condition_variable.c b/src/backend/storage/lmgr/condition_variable.c index 2ec00397b491b..0a61ff0031fef 100644 --- a/src/backend/storage/lmgr/condition_variable.c +++ b/src/backend/storage/lmgr/condition_variable.c @@ -8,7 +8,7 @@ * interrupted, unlike LWLock waits. Condition variables are safe * to use within dynamic shared memory segments. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/storage/lmgr/condition_variable.c diff --git a/src/backend/storage/lmgr/deadlock.c b/src/backend/storage/lmgr/deadlock.c index f7ed6968ca938..67733c0d1a76c 100644 --- a/src/backend/storage/lmgr/deadlock.c +++ b/src/backend/storage/lmgr/deadlock.c @@ -7,7 +7,7 @@ * detection and resolution algorithms. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/lmgr/generate-lwlocknames.pl b/src/backend/storage/lmgr/generate-lwlocknames.pl index 39cb97f5c3d95..8a44946594d42 100644 --- a/src/backend/storage/lmgr/generate-lwlocknames.pl +++ b/src/backend/storage/lmgr/generate-lwlocknames.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl # # Generate lwlocknames.h and lwlocknames.c from lwlocknames.txt -# Copyright (c) 2000-2020, PostgreSQL Global Development Group +# Copyright (c) 2000-2021, PostgreSQL Global Development Group use strict; use warnings; diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c index 7409de9405925..7407672c9d316 100644 --- a/src/backend/storage/lmgr/lmgr.c +++ b/src/backend/storage/lmgr/lmgr.c @@ -3,7 +3,7 @@ * lmgr.c * POSTGRES lock manager code * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c index 53472dd21ec8e..20e50247ea491 100644 --- a/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@ -3,7 +3,7 @@ * lock.c * POSTGRES primary lock mechanism * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c index 26bcce97350e4..db7e59f8b70b6 100644 --- a/src/backend/storage/lmgr/lwlock.c +++ b/src/backend/storage/lmgr/lwlock.c @@ -20,7 +20,7 @@ * appropriate value for a free lock. The meaning of the variable is up to * the caller, the lightweight lock code just assigns and compares it. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c index e42e131543a68..1b262d645b2d1 100644 --- a/src/backend/storage/lmgr/predicate.c +++ b/src/backend/storage/lmgr/predicate.c @@ -135,7 +135,7 @@ * - Protects both PredXact and SerializableXidHash. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 7dc3911590e6e..57717f666d3d8 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -3,7 +3,7 @@ * proc.c * routines to manage per-process shared memory data structure * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/lmgr/s_lock.c b/src/backend/storage/lmgr/s_lock.c index 7fac0703419d0..2dc2d67151072 100644 --- a/src/backend/storage/lmgr/s_lock.c +++ b/src/backend/storage/lmgr/s_lock.c @@ -36,7 +36,7 @@ * the probability of unintended failure) than to fix the total time * spent. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/lmgr/spin.c b/src/backend/storage/lmgr/spin.c index 9f7eae9339223..6fe0c6532c621 100644 --- a/src/backend/storage/lmgr/spin.c +++ b/src/backend/storage/lmgr/spin.c @@ -11,7 +11,7 @@ * is too slow to be very useful :-( * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/page/bufpage.c b/src/backend/storage/page/bufpage.c index ddf18079e2fbf..9ac556b4ae0a7 100644 --- a/src/backend/storage/page/bufpage.c +++ b/src/backend/storage/page/bufpage.c @@ -3,7 +3,7 @@ * bufpage.c * POSTGRES standard buffer page code. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/page/checksum.c b/src/backend/storage/page/checksum.c index e010691c9f2ae..6462ddd812619 100644 --- a/src/backend/storage/page/checksum.c +++ b/src/backend/storage/page/checksum.c @@ -3,7 +3,7 @@ * checksum.c * Checksum implementation for data pages. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/storage/page/itemptr.c b/src/backend/storage/page/itemptr.c index e7806cc60c978..55759c383b616 100644 --- a/src/backend/storage/page/itemptr.c +++ b/src/backend/storage/page/itemptr.c @@ -3,7 +3,7 @@ * itemptr.c * POSTGRES disk item pointer code. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c index 9889ad6ad882f..0643d714fb1c5 100644 --- a/src/backend/storage/smgr/md.c +++ b/src/backend/storage/smgr/md.c @@ -10,7 +10,7 @@ * It doesn't matter whether the bits are on spinning rust or some other * storage technology. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c index 072bdd118fd5d..0f31ff38221f6 100644 --- a/src/backend/storage/smgr/smgr.c +++ b/src/backend/storage/smgr/smgr.c @@ -6,7 +6,7 @@ * All file system operations in POSTGRES dispatch through these * routines. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/storage/sync/sync.c b/src/backend/storage/sync/sync.c index a49588f6b9ed8..fe143151cc524 100644 --- a/src/backend/storage/sync/sync.c +++ b/src/backend/storage/sync/sync.c @@ -3,7 +3,7 @@ * sync.c * File synchronization management code. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/tcop/cmdtag.c b/src/backend/tcop/cmdtag.c index b9fbff612f2a2..e208c7dcfac6a 100644 --- a/src/backend/tcop/cmdtag.c +++ b/src/backend/tcop/cmdtag.c @@ -3,7 +3,7 @@ * cmdtag.c * Data and routines for commandtag names and enumeration. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/tcop/dest.c b/src/backend/tcop/dest.c index 96789f88ef938..4316137a9d3e4 100644 --- a/src/backend/tcop/dest.c +++ b/src/backend/tcop/dest.c @@ -4,7 +4,7 @@ * support for communication destinations * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c index e793984a9f3e0..1b76653caa4c3 100644 --- a/src/backend/tcop/fastpath.c +++ b/src/backend/tcop/fastpath.c @@ -3,7 +3,7 @@ * fastpath.c * routines to handle function requests from the frontend * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 317d1aa57309f..dfa0d685a837a 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3,7 +3,7 @@ * postgres.c * POSTGRES C Backend Interface * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c index 96ea74f118dff..579b37a9c6d0a 100644 --- a/src/backend/tcop/pquery.c +++ b/src/backend/tcop/pquery.c @@ -3,7 +3,7 @@ * pquery.c * POSTGRES process query command code * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index a42ead7d698e7..5825d3d81428e 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -5,7 +5,7 @@ * commands. At one time acted as an interface between the Lisp and C * systems. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/tsearch/Makefile b/src/backend/tsearch/Makefile index 7c669b1abc97f..cdb259eca5811 100644 --- a/src/backend/tsearch/Makefile +++ b/src/backend/tsearch/Makefile @@ -2,7 +2,7 @@ # # Makefile for backend/tsearch # -# Copyright (c) 2006-2020, PostgreSQL Global Development Group +# Copyright (c) 2006-2021, PostgreSQL Global Development Group # # src/backend/tsearch/Makefile # diff --git a/src/backend/tsearch/dict.c b/src/backend/tsearch/dict.c index 835b6721a9f89..1e1ccdac2908b 100644 --- a/src/backend/tsearch/dict.c +++ b/src/backend/tsearch/dict.c @@ -3,7 +3,7 @@ * dict.c * Standard interface to dictionary * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/tsearch/dict_ispell.c b/src/backend/tsearch/dict_ispell.c index ecb15dcffd871..d93f6018cec02 100644 --- a/src/backend/tsearch/dict_ispell.c +++ b/src/backend/tsearch/dict_ispell.c @@ -3,7 +3,7 @@ * dict_ispell.c * Ispell dictionary interface * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/tsearch/dict_simple.c b/src/backend/tsearch/dict_simple.c index 5b74deb02c7d6..9cd4b6bae55e8 100644 --- a/src/backend/tsearch/dict_simple.c +++ b/src/backend/tsearch/dict_simple.c @@ -3,7 +3,7 @@ * dict_simple.c * Simple dictionary: just lowercase and check for stopword * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/tsearch/dict_synonym.c b/src/backend/tsearch/dict_synonym.c index e732e66dace0e..ed885ca5551d5 100644 --- a/src/backend/tsearch/dict_synonym.c +++ b/src/backend/tsearch/dict_synonym.c @@ -3,7 +3,7 @@ * dict_synonym.c * Synonym dictionary: replace word by its synonym * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/tsearch/dict_thesaurus.c b/src/backend/tsearch/dict_thesaurus.c index 64c979086d1eb..a95ed0891dd18 100644 --- a/src/backend/tsearch/dict_thesaurus.c +++ b/src/backend/tsearch/dict_thesaurus.c @@ -3,7 +3,7 @@ * dict_thesaurus.c * Thesaurus dictionary: phrase to phrase substitution * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/tsearch/regis.c b/src/backend/tsearch/regis.c index 2edd4faa8ec06..80017177222d1 100644 --- a/src/backend/tsearch/regis.c +++ b/src/backend/tsearch/regis.c @@ -3,7 +3,7 @@ * regis.c * Fast regex subset * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/tsearch/spell.c b/src/backend/tsearch/spell.c index 05d08cfc0102d..9b9a9afaa89ac 100644 --- a/src/backend/tsearch/spell.c +++ b/src/backend/tsearch/spell.c @@ -3,7 +3,7 @@ * spell.c * Normalizing word with ISpell * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * Ispell dictionary * ----------------- diff --git a/src/backend/tsearch/to_tsany.c b/src/backend/tsearch/to_tsany.c index e7cd6264db275..e4ad661a8baa8 100644 --- a/src/backend/tsearch/to_tsany.c +++ b/src/backend/tsearch/to_tsany.c @@ -3,7 +3,7 @@ * to_tsany.c * to_ts* function definitions * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/tsearch/ts_locale.c b/src/backend/tsearch/ts_locale.c index d362e86d61a26..f918cc8908bb9 100644 --- a/src/backend/tsearch/ts_locale.c +++ b/src/backend/tsearch/ts_locale.c @@ -3,7 +3,7 @@ * ts_locale.c * locale compatibility layer for tsearch * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/tsearch/ts_parse.c b/src/backend/tsearch/ts_parse.c index 1c0f94e79759d..92d95b4bd4971 100644 --- a/src/backend/tsearch/ts_parse.c +++ b/src/backend/tsearch/ts_parse.c @@ -3,7 +3,7 @@ * ts_parse.c * main parse functions for tsearch * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/tsearch/ts_selfuncs.c b/src/backend/tsearch/ts_selfuncs.c index e74b85a6900b3..be2546a86ea4c 100644 --- a/src/backend/tsearch/ts_selfuncs.c +++ b/src/backend/tsearch/ts_selfuncs.c @@ -3,7 +3,7 @@ * ts_selfuncs.c * Selectivity estimation functions for text search operators. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/tsearch/ts_typanalyze.c b/src/backend/tsearch/ts_typanalyze.c index 19e9611a3ae82..33b32ad030919 100644 --- a/src/backend/tsearch/ts_typanalyze.c +++ b/src/backend/tsearch/ts_typanalyze.c @@ -3,7 +3,7 @@ * ts_typanalyze.c * functions for gathering statistics from tsvector columns * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/tsearch/ts_utils.c b/src/backend/tsearch/ts_utils.c index 3bc6b32095fce..ed16a2e25a2a8 100644 --- a/src/backend/tsearch/ts_utils.c +++ b/src/backend/tsearch/ts_utils.c @@ -3,7 +3,7 @@ * ts_utils.c * various support functions * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c index 9c1fc7b10142b..71882dced99a7 100644 --- a/src/backend/tsearch/wparser.c +++ b/src/backend/tsearch/wparser.c @@ -3,7 +3,7 @@ * wparser.c * Standard interface to word parser * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/tsearch/wparser_def.c b/src/backend/tsearch/wparser_def.c index 7b29062a97eaa..559dff635588d 100644 --- a/src/backend/tsearch/wparser_def.c +++ b/src/backend/tsearch/wparser_def.c @@ -3,7 +3,7 @@ * wparser_def.c * Default text search parser * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/utils/Gen_dummy_probes.pl b/src/backend/utils/Gen_dummy_probes.pl index cb0ad5a75cf59..9f3cf6baf18c8 100644 --- a/src/backend/utils/Gen_dummy_probes.pl +++ b/src/backend/utils/Gen_dummy_probes.pl @@ -4,7 +4,7 @@ # Gen_dummy_probes.pl # Perl script that generates probes.h file when dtrace is not available # -# Portions Copyright (c) 2008-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 2008-2021, PostgreSQL Global Development Group # # # IDENTIFICATION diff --git a/src/backend/utils/Gen_dummy_probes.sed b/src/backend/utils/Gen_dummy_probes.sed index 3c9eac6e4f74c..aa3db59cce7c2 100644 --- a/src/backend/utils/Gen_dummy_probes.sed +++ b/src/backend/utils/Gen_dummy_probes.sed @@ -1,7 +1,7 @@ #------------------------------------------------------------------------- # sed script to create dummy probes.h file when dtrace is not available # -# Copyright (c) 2008-2020, PostgreSQL Global Development Group +# Copyright (c) 2008-2021, PostgreSQL Global Development Group # # src/backend/utils/Gen_dummy_probes.sed #------------------------------------------------------------------------- diff --git a/src/backend/utils/Gen_fmgrtab.pl b/src/backend/utils/Gen_fmgrtab.pl index ae8cf5bb64cc5..881568defd7e2 100644 --- a/src/backend/utils/Gen_fmgrtab.pl +++ b/src/backend/utils/Gen_fmgrtab.pl @@ -5,7 +5,7 @@ # Perl script that generates fmgroids.h, fmgrprotos.h, and fmgrtab.c # from pg_proc.dat # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # @@ -109,7 +109,7 @@ * These macros can be used to avoid a catalog lookup when a specific * fmgr-callable function needs to be referenced. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES @@ -140,7 +140,7 @@ * fmgrprotos.h * Prototypes for built-in functions. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES @@ -166,7 +166,7 @@ * fmgrtab.c * The function manager's table of internal functions. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES diff --git a/src/backend/utils/Makefile b/src/backend/utils/Makefile index b91028ddfd6fa..26e07100a5d13 100644 --- a/src/backend/utils/Makefile +++ b/src/backend/utils/Makefile @@ -2,7 +2,7 @@ # # Makefile for backend/utils # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/backend/utils/Makefile diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index fe6c444738aa7..c7f029e2186a1 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -3,7 +3,7 @@ * acl.c * Basic access control list data structures manipulation routines. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/amutils.c b/src/backend/utils/adt/amutils.c index 220cd8fc52fe0..569412fcacf53 100644 --- a/src/backend/utils/adt/amutils.c +++ b/src/backend/utils/adt/amutils.c @@ -3,7 +3,7 @@ * amutils.c * SQL-level APIs related to index access methods. * - * Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Copyright (c) 2016-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/utils/adt/array_expanded.c b/src/backend/utils/adt/array_expanded.c index 18de2dd352f60..60511f639d360 100644 --- a/src/backend/utils/adt/array_expanded.c +++ b/src/backend/utils/adt/array_expanded.c @@ -3,7 +3,7 @@ * array_expanded.c * Basic functions for manipulating expanded arrays. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/array_selfuncs.c b/src/backend/utils/adt/array_selfuncs.c index d97e60a3ab5bd..23de5d9226449 100644 --- a/src/backend/utils/adt/array_selfuncs.c +++ b/src/backend/utils/adt/array_selfuncs.c @@ -3,7 +3,7 @@ * array_selfuncs.c * Functions for selectivity estimation of array operators * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/array_typanalyze.c b/src/backend/utils/adt/array_typanalyze.c index cb2a834193d67..c5008a0c16915 100644 --- a/src/backend/utils/adt/array_typanalyze.c +++ b/src/backend/utils/adt/array_typanalyze.c @@ -3,7 +3,7 @@ * array_typanalyze.c * Functions for gathering statistics from array columns * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c index 9e18bc9cda9a1..a2793bfae32a9 100644 --- a/src/backend/utils/adt/array_userfuncs.c +++ b/src/backend/utils/adt/array_userfuncs.c @@ -3,7 +3,7 @@ * array_userfuncs.c * Misc user-visible array support functions * - * Copyright (c) 2003-2020, PostgreSQL Global Development Group + * Copyright (c) 2003-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/adt/array_userfuncs.c diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 4c8a739bc4392..1b618356606ff 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -3,7 +3,7 @@ * arrayfuncs.c * Support functions for arrays. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/arraysubs.c b/src/backend/utils/adt/arraysubs.c index a081288f42db2..1d910d14dbc95 100644 --- a/src/backend/utils/adt/arraysubs.c +++ b/src/backend/utils/adt/arraysubs.c @@ -3,7 +3,7 @@ * arraysubs.c * Subscripting support functions for arrays. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/arrayutils.c b/src/backend/utils/adt/arrayutils.c index bc4360aaec0c7..2a6a05718f8e4 100644 --- a/src/backend/utils/adt/arrayutils.c +++ b/src/backend/utils/adt/arrayutils.c @@ -3,7 +3,7 @@ * arrayutils.c * This file contains some support routines required for array functions. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/ascii.c b/src/backend/utils/adt/ascii.c index 3aa8a5e7d21b8..9dfff9dbef403 100644 --- a/src/backend/utils/adt/ascii.c +++ b/src/backend/utils/adt/ascii.c @@ -2,7 +2,7 @@ * ascii.c * The PostgreSQL routine for string to ascii conversion. * - * Portions Copyright (c) 1999-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1999-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/adt/ascii.c diff --git a/src/backend/utils/adt/bool.c b/src/backend/utils/adt/bool.c index 340607f93645b..fe11d1ae94639 100644 --- a/src/backend/utils/adt/bool.c +++ b/src/backend/utils/adt/bool.c @@ -3,7 +3,7 @@ * bool.c * Functions for the built-in type "bool". * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/char.c b/src/backend/utils/adt/char.c index 20ea1366d053b..e620d47eb520a 100644 --- a/src/backend/utils/adt/char.c +++ b/src/backend/utils/adt/char.c @@ -4,7 +4,7 @@ * Functions for the built-in type "char" (not to be confused with * bpchar, which is the SQL CHAR(n) type). * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/cryptohashfuncs.c b/src/backend/utils/adt/cryptohashfuncs.c index 47bc0b34828e3..d99485f4c6dd4 100644 --- a/src/backend/utils/adt/cryptohashfuncs.c +++ b/src/backend/utils/adt/cryptohashfuncs.c @@ -3,7 +3,7 @@ * cryptohashfuncs.c * Cryptographic hash functions * - * Portions Copyright (c) 2018-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2018-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c index a470cf890a205..68d99a5099206 100644 --- a/src/backend/utils/adt/date.c +++ b/src/backend/utils/adt/date.c @@ -3,7 +3,7 @@ * date.c * implements DATE and TIME data types specified in SQL standard * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994-5, Regents of the University of California * * diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c index 91fab8cc9cb39..350b0c55eac52 100644 --- a/src/backend/utils/adt/datetime.c +++ b/src/backend/utils/adt/datetime.c @@ -3,7 +3,7 @@ * datetime.c * Support functions for date/time types. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/datum.c b/src/backend/utils/adt/datum.c index 34cdde1bb91bb..6a317fc0a6d0c 100644 --- a/src/backend/utils/adt/datum.c +++ b/src/backend/utils/adt/datum.c @@ -3,7 +3,7 @@ * datum.c * POSTGRES Datum (abstract data type) manipulation routines. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c index 3319e9761e4c0..64cdaa4134b79 100644 --- a/src/backend/utils/adt/dbsize.c +++ b/src/backend/utils/adt/dbsize.c @@ -2,7 +2,7 @@ * dbsize.c * Database object size functions, and related inquiries * - * Copyright (c) 2002-2020, PostgreSQL Global Development Group + * Copyright (c) 2002-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/adt/dbsize.c diff --git a/src/backend/utils/adt/domains.c b/src/backend/utils/adt/domains.c index 41e1a1b610b30..0a36772fc031d 100644 --- a/src/backend/utils/adt/domains.c +++ b/src/backend/utils/adt/domains.c @@ -19,7 +19,7 @@ * to evaluate them in. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/encode.c b/src/backend/utils/adt/encode.c index a6c65b16578ae..4759be25e915c 100644 --- a/src/backend/utils/adt/encode.c +++ b/src/backend/utils/adt/encode.c @@ -3,7 +3,7 @@ * encode.c * Various data encoding/decoding things. * - * Copyright (c) 2001-2020, PostgreSQL Global Development Group + * Copyright (c) 2001-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/utils/adt/enum.c b/src/backend/utils/adt/enum.c index 69faf41df964e..79117c4c904d8 100644 --- a/src/backend/utils/adt/enum.c +++ b/src/backend/utils/adt/enum.c @@ -3,7 +3,7 @@ * enum.c * I/O functions, operators, aggregates etc for enum types * - * Copyright (c) 2006-2020, PostgreSQL Global Development Group + * Copyright (c) 2006-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/utils/adt/expandeddatum.c b/src/backend/utils/adt/expandeddatum.c index 3c35523556002..cb0adfaa21527 100644 --- a/src/backend/utils/adt/expandeddatum.c +++ b/src/backend/utils/adt/expandeddatum.c @@ -3,7 +3,7 @@ * expandeddatum.c * Support functions for "expanded" value representations. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/expandedrecord.c b/src/backend/utils/adt/expandedrecord.c index ec12ec54fc823..e19491ecf7442 100644 --- a/src/backend/utils/adt/expandedrecord.c +++ b/src/backend/utils/adt/expandedrecord.c @@ -7,7 +7,7 @@ * store values of named composite types, domains over named composite types, * and record types (registered or anonymous). * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c index 429c9280c0cf7..098bbb372bfc5 100644 --- a/src/backend/utils/adt/float.c +++ b/src/backend/utils/adt/float.c @@ -3,7 +3,7 @@ * float.c * Functions for the built-in floating-point types. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/format_type.c b/src/backend/utils/adt/format_type.c index 013409aee7d84..0e8e065457585 100644 --- a/src/backend/utils/adt/format_type.c +++ b/src/backend/utils/adt/format_type.c @@ -4,7 +4,7 @@ * Display type names "nicely". * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c index 3bb01cdb65ab1..783c7b5e7acf9 100644 --- a/src/backend/utils/adt/formatting.c +++ b/src/backend/utils/adt/formatting.c @@ -4,7 +4,7 @@ * src/backend/utils/adt/formatting.c * * - * Portions Copyright (c) 1999-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1999-2021, PostgreSQL Global Development Group * * * TO_CHAR(); TO_TIMESTAMP(); TO_DATE(); TO_NUMBER(); diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c index d34182a7b04d2..169ddf8d76813 100644 --- a/src/backend/utils/adt/genfile.c +++ b/src/backend/utils/adt/genfile.c @@ -4,7 +4,7 @@ * Functions for direct access to files * * - * Copyright (c) 2004-2020, PostgreSQL Global Development Group + * Copyright (c) 2004-2021, PostgreSQL Global Development Group * * Author: Andreas Pflug * diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c index c1dc511a1a8c3..9484dbc22737a 100644 --- a/src/backend/utils/adt/geo_ops.c +++ b/src/backend/utils/adt/geo_ops.c @@ -13,7 +13,7 @@ * - circle * - polygon * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/geo_selfuncs.c b/src/backend/utils/adt/geo_selfuncs.c index 89cf8d32e7916..db941244efae3 100644 --- a/src/backend/utils/adt/geo_selfuncs.c +++ b/src/backend/utils/adt/geo_selfuncs.c @@ -4,7 +4,7 @@ * Selectivity routines registered in the operator catalog in the * "oprrest" and "oprjoin" attributes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c index de7e6fa404254..d0ff5522cefb6 100644 --- a/src/backend/utils/adt/geo_spgist.c +++ b/src/backend/utils/adt/geo_spgist.c @@ -62,7 +62,7 @@ * except the root. For the root node, we are setting the boundaries * that we don't yet have as infinity. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/adt/int.c b/src/backend/utils/adt/int.c index 418c13e1b4cdc..e9f108425c5a8 100644 --- a/src/backend/utils/adt/int.c +++ b/src/backend/utils/adt/int.c @@ -3,7 +3,7 @@ * int.c * Functions for the built-in integer types (except int8). * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c index 005f68d85391f..2168080dcce9a 100644 --- a/src/backend/utils/adt/int8.c +++ b/src/backend/utils/adt/int8.c @@ -3,7 +3,7 @@ * int8.c * Internal 64-bit integer operations * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c index 420d3cdcbb9d7..30ca2cf6c81b8 100644 --- a/src/backend/utils/adt/json.c +++ b/src/backend/utils/adt/json.c @@ -3,7 +3,7 @@ * json.c * JSON data type support. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/adt/jsonb.c b/src/backend/utils/adt/jsonb.c index 1e9ca046c6992..8d1e7fbf9108c 100644 --- a/src/backend/utils/adt/jsonb.c +++ b/src/backend/utils/adt/jsonb.c @@ -3,7 +3,7 @@ * jsonb.c * I/O routines for jsonb type * - * Copyright (c) 2014-2020, PostgreSQL Global Development Group + * Copyright (c) 2014-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/adt/jsonb.c diff --git a/src/backend/utils/adt/jsonb_gin.c b/src/backend/utils/adt/jsonb_gin.c index aee3d9d6733ee..37499bc562266 100644 --- a/src/backend/utils/adt/jsonb_gin.c +++ b/src/backend/utils/adt/jsonb_gin.c @@ -3,7 +3,7 @@ * jsonb_gin.c * GIN support functions for jsonb * - * Copyright (c) 2014-2020, PostgreSQL Global Development Group + * Copyright (c) 2014-2021, PostgreSQL Global Development Group * * We provide two opclasses for jsonb indexing: jsonb_ops and jsonb_path_ops. * For their description see json.sgml and comments in jsonb.h. diff --git a/src/backend/utils/adt/jsonb_op.c b/src/backend/utils/adt/jsonb_op.c index dc17e17f9b46b..6e85e5c36b396 100644 --- a/src/backend/utils/adt/jsonb_op.c +++ b/src/backend/utils/adt/jsonb_op.c @@ -3,7 +3,7 @@ * jsonb_op.c * Special operators for jsonb only, used by various index access methods * - * Copyright (c) 2014-2020, PostgreSQL Global Development Group + * Copyright (c) 2014-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/utils/adt/jsonb_util.c b/src/backend/utils/adt/jsonb_util.c index 4eeffa1424346..0ce66411ae139 100644 --- a/src/backend/utils/adt/jsonb_util.c +++ b/src/backend/utils/adt/jsonb_util.c @@ -3,7 +3,7 @@ * jsonb_util.c * converting between Jsonb and JsonbValues, and iterating. * - * Copyright (c) 2014-2020, PostgreSQL Global Development Group + * Copyright (c) 2014-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c index 69100feab7c1c..a794a7df84fb1 100644 --- a/src/backend/utils/adt/jsonfuncs.c +++ b/src/backend/utils/adt/jsonfuncs.c @@ -3,7 +3,7 @@ * jsonfuncs.c * Functions to process JSON data types. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/adt/jsonpath.c b/src/backend/utils/adt/jsonpath.c index 31d9d92d14ed5..fa22546f22d58 100644 --- a/src/backend/utils/adt/jsonpath.c +++ b/src/backend/utils/adt/jsonpath.c @@ -53,7 +53,7 @@ * | |__| |__||________________________||___________________| | * |_______________________________________________________________________| * - * Copyright (c) 2019-2020, PostgreSQL Global Development Group + * Copyright (c) 2019-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/adt/jsonpath.c diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c index 1059f34130aee..4d185c27b47f9 100644 --- a/src/backend/utils/adt/jsonpath_exec.c +++ b/src/backend/utils/adt/jsonpath_exec.c @@ -49,7 +49,7 @@ * we calculate operands first. Then we check that results are numeric * singleton lists, calculate the result and pass it to the next path item. * - * Copyright (c) 2019-2020, PostgreSQL Global Development Group + * Copyright (c) 2019-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/adt/jsonpath_exec.c diff --git a/src/backend/utils/adt/jsonpath_gram.y b/src/backend/utils/adt/jsonpath_gram.y index 01b8d451a709b..de3d97931ef45 100644 --- a/src/backend/utils/adt/jsonpath_gram.y +++ b/src/backend/utils/adt/jsonpath_gram.y @@ -6,7 +6,7 @@ * * Transforms tokenized jsonpath into tree of JsonPathParseItem structs. * - * Copyright (c) 2019-2020, PostgreSQL Global Development Group + * Copyright (c) 2019-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/adt/jsonpath_gram.y diff --git a/src/backend/utils/adt/jsonpath_scan.l b/src/backend/utils/adt/jsonpath_scan.l index f723462a1f75a..72d4c5e946a8c 100644 --- a/src/backend/utils/adt/jsonpath_scan.l +++ b/src/backend/utils/adt/jsonpath_scan.l @@ -7,7 +7,7 @@ * Splits jsonpath string into tokens represented as JsonPathString structs. * Decodes unicode and hex escaped strings. * - * Copyright (c) 2019-2020, PostgreSQL Global Development Group + * Copyright (c) 2019-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/adt/jsonpath_scan.l diff --git a/src/backend/utils/adt/levenshtein.c b/src/backend/utils/adt/levenshtein.c index d11278c505be0..f8979776d0d5c 100644 --- a/src/backend/utils/adt/levenshtein.c +++ b/src/backend/utils/adt/levenshtein.c @@ -16,7 +16,7 @@ * PHP 4.0.6 distribution for inspiration. Configurable penalty costs * extension is introduced by Volkan YAZICI (7/95). * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/adt/like_match.c b/src/backend/utils/adt/like_match.c index ee30170fbb44a..2f32cdaf020a5 100644 --- a/src/backend/utils/adt/like_match.c +++ b/src/backend/utils/adt/like_match.c @@ -16,7 +16,7 @@ * do_like_escape - name of function if wanted - needs CHAREQ and CopyAdvChar * MATCH_LOWER - define for case (4) to specify case folding for 1-byte chars * - * Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/adt/like_match.c diff --git a/src/backend/utils/adt/like_support.c b/src/backend/utils/adt/like_support.c index bcfbaa1c3d184..c746592cbcaa2 100644 --- a/src/backend/utils/adt/like_support.c +++ b/src/backend/utils/adt/like_support.c @@ -23,7 +23,7 @@ * from LIKE to indexscan limits rather harder than one might think ... * but that's the basic idea.) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c index f592292d067b8..9f2c4946c9290 100644 --- a/src/backend/utils/adt/lockfuncs.c +++ b/src/backend/utils/adt/lockfuncs.c @@ -3,7 +3,7 @@ * lockfuncs.c * Functions for SQL access to various lock-manager capabilities. * - * Copyright (c) 2002-2020, PostgreSQL Global Development Group + * Copyright (c) 2002-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/adt/lockfuncs.c diff --git a/src/backend/utils/adt/mac.c b/src/backend/utils/adt/mac.c index 8aeddc686326c..844d8814e67fc 100644 --- a/src/backend/utils/adt/mac.c +++ b/src/backend/utils/adt/mac.c @@ -3,7 +3,7 @@ * mac.c * PostgreSQL type definitions for 6 byte, EUI-48, MAC addresses. * - * Portions Copyright (c) 1998-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1998-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/adt/mac.c diff --git a/src/backend/utils/adt/mac8.c b/src/backend/utils/adt/mac8.c index b7b2968b926c9..41753fac6fd80 100644 --- a/src/backend/utils/adt/mac8.c +++ b/src/backend/utils/adt/mac8.c @@ -11,7 +11,7 @@ * The following code is written with the assumption that the OUI field * size is 24 bits. * - * Portions Copyright (c) 1998-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1998-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/adt/mac8.c diff --git a/src/backend/utils/adt/mcxtfuncs.c b/src/backend/utils/adt/mcxtfuncs.c index 50e1b07ff02c6..c02fa47550a6d 100644 --- a/src/backend/utils/adt/mcxtfuncs.c +++ b/src/backend/utils/adt/mcxtfuncs.c @@ -3,7 +3,7 @@ * mcxtfuncs.c * Functions to show backend memory context. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index b2bf9fa8cbcfd..4096faff9a196 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -3,7 +3,7 @@ * misc.c * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/multirangetypes.c b/src/backend/utils/adt/multirangetypes.c index 63867958cfd96..b3964ea27fdd5 100644 --- a/src/backend/utils/adt/multirangetypes.c +++ b/src/backend/utils/adt/multirangetypes.c @@ -21,7 +21,7 @@ * for a particular range index. Offsets are counted starting from the end of * flags aligned to the bound type. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/multirangetypes_selfuncs.c b/src/backend/utils/adt/multirangetypes_selfuncs.c index 14283e4503a2b..551176bc21377 100644 --- a/src/backend/utils/adt/multirangetypes_selfuncs.c +++ b/src/backend/utils/adt/multirangetypes_selfuncs.c @@ -6,7 +6,7 @@ * Estimates are based on histograms of lower and upper bounds, and the * fraction of empty multiranges. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/name.c b/src/backend/utils/adt/name.c index a3ce3f3d1e182..c93be3350ea72 100644 --- a/src/backend/utils/adt/name.c +++ b/src/backend/utils/adt/name.c @@ -9,7 +9,7 @@ * always use NAMEDATALEN as the symbolic constant! - jolly 8/21/95 * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/network_gist.c b/src/backend/utils/adt/network_gist.c index 9813a1d2b8cae..54e8edcdbd072 100644 --- a/src/backend/utils/adt/network_gist.c +++ b/src/backend/utils/adt/network_gist.c @@ -34,7 +34,7 @@ * twice as fast as for a simpler design in which a single field doubles as * the common prefix length and the minimum ip_bits value. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/network_selfuncs.c b/src/backend/utils/adt/network_selfuncs.c index 955e0ee87f803..dca2c6321236c 100644 --- a/src/backend/utils/adt/network_selfuncs.c +++ b/src/backend/utils/adt/network_selfuncs.c @@ -7,7 +7,7 @@ * operators. Estimates are based on null fraction, most common values, * and histogram of inet/cidr columns. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/network_spgist.c b/src/backend/utils/adt/network_spgist.c index 4a0b0073c7382..e496a470d0ab3 100644 --- a/src/backend/utils/adt/network_spgist.c +++ b/src/backend/utils/adt/network_spgist.c @@ -21,7 +21,7 @@ * the address family, everything goes into node 0 (which will probably * lead to creating an allTheSame tuple). * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index 20c9cac2fa2e0..68d879160a560 100644 --- a/src/backend/utils/adt/numeric.c +++ b/src/backend/utils/adt/numeric.c @@ -11,7 +11,7 @@ * Transactions on Mathematical Software, Vol. 24, No. 4, December 1998, * pages 359-367. * - * Copyright (c) 1998-2020, PostgreSQL Global Development Group + * Copyright (c) 1998-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/adt/numeric.c diff --git a/src/backend/utils/adt/numutils.c b/src/backend/utils/adt/numutils.c index 412ae361d2c0f..b93096f288f38 100644 --- a/src/backend/utils/adt/numutils.c +++ b/src/backend/utils/adt/numutils.c @@ -3,7 +3,7 @@ * numutils.c * utility functions for I/O of built-in numeric types. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/oid.c b/src/backend/utils/adt/oid.c index 4ac691966247f..fd94e0c881829 100644 --- a/src/backend/utils/adt/oid.c +++ b/src/backend/utils/adt/oid.c @@ -3,7 +3,7 @@ * oid.c * Functions for the built-in type Oid ... also oidvector. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/oracle_compat.c b/src/backend/utils/adt/oracle_compat.c index 76e666474e847..99077a90b92ad 100644 --- a/src/backend/utils/adt/oracle_compat.c +++ b/src/backend/utils/adt/oracle_compat.c @@ -2,7 +2,7 @@ * oracle_compat.c * Oracle compatible functions. * - * Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Copyright (c) 1996-2021, PostgreSQL Global Development Group * * Author: Edmund Mergl * Multibyte enhancement: Tatsuo Ishii diff --git a/src/backend/utils/adt/orderedsetaggs.c b/src/backend/utils/adt/orderedsetaggs.c index f9b5d7024b5be..89f1c3b3a0d36 100644 --- a/src/backend/utils/adt/orderedsetaggs.c +++ b/src/backend/utils/adt/orderedsetaggs.c @@ -3,7 +3,7 @@ * orderedsetaggs.c * Ordered-set aggregate functions. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c index c1120403fd989..03660d5db6c76 100644 --- a/src/backend/utils/adt/partitionfuncs.c +++ b/src/backend/utils/adt/partitionfuncs.c @@ -3,7 +3,7 @@ * partitionfuncs.c * Functions for accessing partition-related metadata * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c index 088c1444c3b20..e9c1231f9baea 100644 --- a/src/backend/utils/adt/pg_locale.c +++ b/src/backend/utils/adt/pg_locale.c @@ -2,7 +2,7 @@ * * PostgreSQL locale utilities * - * Portions Copyright (c) 2002-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2002-2021, PostgreSQL Global Development Group * * src/backend/utils/adt/pg_locale.c * diff --git a/src/backend/utils/adt/pg_lsn.c b/src/backend/utils/adt/pg_lsn.c index ad0a7bd869d1e..12ad0c4c31e82 100644 --- a/src/backend/utils/adt/pg_lsn.c +++ b/src/backend/utils/adt/pg_lsn.c @@ -3,7 +3,7 @@ * pg_lsn.c * Operations for the pg_lsn datatype. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/adt/pg_upgrade_support.c b/src/backend/utils/adt/pg_upgrade_support.c index 521ebaaab6d4e..a575c950790ad 100644 --- a/src/backend/utils/adt/pg_upgrade_support.c +++ b/src/backend/utils/adt/pg_upgrade_support.c @@ -5,7 +5,7 @@ * to control oid and relfilenode assignment, and do other special * hacks needed for pg_upgrade. * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * src/backend/utils/adt/pg_upgrade_support.c */ diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index 6afe1b6f56ebc..c9a1d4c56d978 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -3,7 +3,7 @@ * pgstatfuncs.c * Functions for accessing the statistics collector data * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/pseudotypes.c b/src/backend/utils/adt/pseudotypes.c index 99a93271fe1c0..c2f910d606770 100644 --- a/src/backend/utils/adt/pseudotypes.c +++ b/src/backend/utils/adt/pseudotypes.c @@ -11,7 +11,7 @@ * we do better?) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/quote.c b/src/backend/utils/adt/quote.c index 906bf329b8def..8de4eace9eda2 100644 --- a/src/backend/utils/adt/quote.c +++ b/src/backend/utils/adt/quote.c @@ -3,7 +3,7 @@ * quote.c * Functions for quoting identifiers and literals * - * Portions Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2000-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/utils/adt/rangetypes.c b/src/backend/utils/adt/rangetypes.c index 8957cc1984227..815175a654e31 100644 --- a/src/backend/utils/adt/rangetypes.c +++ b/src/backend/utils/adt/rangetypes.c @@ -19,7 +19,7 @@ * value; we must detoast it first. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/rangetypes_gist.c b/src/backend/utils/adt/rangetypes_gist.c index 435b242c8abec..69515b06782e2 100644 --- a/src/backend/utils/adt/rangetypes_gist.c +++ b/src/backend/utils/adt/rangetypes_gist.c @@ -3,7 +3,7 @@ * rangetypes_gist.c * GiST support for range types. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/rangetypes_selfuncs.c b/src/backend/utils/adt/rangetypes_selfuncs.c index 25dd84f4df626..a6c3c450ac9ed 100644 --- a/src/backend/utils/adt/rangetypes_selfuncs.c +++ b/src/backend/utils/adt/rangetypes_selfuncs.c @@ -6,7 +6,7 @@ * Estimates are based on histograms of lower and upper bounds, and the * fraction of empty ranges. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/rangetypes_spgist.c b/src/backend/utils/adt/rangetypes_spgist.c index 9bbef531495c2..f29de6aab4884 100644 --- a/src/backend/utils/adt/rangetypes_spgist.c +++ b/src/backend/utils/adt/rangetypes_spgist.c @@ -25,7 +25,7 @@ * This implementation only uses the comparison function of the range element * datatype, therefore it works for any range type. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/adt/rangetypes_typanalyze.c b/src/backend/utils/adt/rangetypes_typanalyze.c index d5fa36b6ff0d9..2c10f2c867c64 100644 --- a/src/backend/utils/adt/rangetypes_typanalyze.c +++ b/src/backend/utils/adt/rangetypes_typanalyze.c @@ -13,7 +13,7 @@ * come from different tuples. In theory, the standard scalar selectivity * functions could be used with the combined histogram. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/regexp.c b/src/backend/utils/adt/regexp.c index c70c5eeeb37f9..a32c5c82ab437 100644 --- a/src/backend/utils/adt/regexp.c +++ b/src/backend/utils/adt/regexp.c @@ -3,7 +3,7 @@ * regexp.c * Postgres' interface to the regular expression package. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c index 6c1ee9c92df3e..f998fe20763da 100644 --- a/src/backend/utils/adt/regproc.c +++ b/src/backend/utils/adt/regproc.c @@ -8,7 +8,7 @@ * special I/O conversion routines. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index 5ab134a85370d..6e3a41062fcc4 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -14,7 +14,7 @@ * plan --- consider improving this someday. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * src/backend/utils/adt/ri_triggers.c * diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c index 5c4648bccff72..23787a6ae7d71 100644 --- a/src/backend/utils/adt/rowtypes.c +++ b/src/backend/utils/adt/rowtypes.c @@ -3,7 +3,7 @@ * rowtypes.c * I/O and comparison functions for generic composite types. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 7d4443e807d80..db803b4388124 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -4,7 +4,7 @@ * Functions to convert stored expressions/querytrees back to * source text * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 80bd60f8767b7..d5e61664bc614 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -10,7 +10,7 @@ * Index cost functions are located via the index AM's API struct, * which is obtained from the handler function registered in pg_am. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/tid.c b/src/backend/utils/adt/tid.c index 52028603d239d..e9f1fc706f834 100644 --- a/src/backend/utils/adt/tid.c +++ b/src/backend/utils/adt/tid.c @@ -3,7 +3,7 @@ * tid.c * Functions for the built-in type tuple id * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index 2dbd309122236..0b1f95a5b4ecd 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -3,7 +3,7 @@ * timestamp.c * Functions for the built-in SQL types "timestamp" and "interval". * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/trigfuncs.c b/src/backend/utils/adt/trigfuncs.c index 41377270ed27e..cc28cfd186b11 100644 --- a/src/backend/utils/adt/trigfuncs.c +++ b/src/backend/utils/adt/trigfuncs.c @@ -4,7 +4,7 @@ * Builtin functions for useful trigger support. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/utils/adt/trigfuncs.c diff --git a/src/backend/utils/adt/tsginidx.c b/src/backend/utils/adt/tsginidx.c index b3e3ffc577635..6c913baabacd9 100644 --- a/src/backend/utils/adt/tsginidx.c +++ b/src/backend/utils/adt/tsginidx.c @@ -3,7 +3,7 @@ * tsginidx.c * GIN support functions for tsvector_ops * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/utils/adt/tsgistidx.c b/src/backend/utils/adt/tsgistidx.c index a601965bd83e6..c09eefdda2313 100644 --- a/src/backend/utils/adt/tsgistidx.c +++ b/src/backend/utils/adt/tsgistidx.c @@ -3,7 +3,7 @@ * tsgistidx.c * GiST support functions for tsvector_ops * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/utils/adt/tsquery.c b/src/backend/utils/adt/tsquery.c index 092e8a130bfc2..fe4470174f5d1 100644 --- a/src/backend/utils/adt/tsquery.c +++ b/src/backend/utils/adt/tsquery.c @@ -3,7 +3,7 @@ * tsquery.c * I/O functions for tsquery * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/utils/adt/tsquery_cleanup.c b/src/backend/utils/adt/tsquery_cleanup.c index 2481cf8c7bf56..82ae284403a4f 100644 --- a/src/backend/utils/adt/tsquery_cleanup.c +++ b/src/backend/utils/adt/tsquery_cleanup.c @@ -4,7 +4,7 @@ * Cleanup query from NOT values and/or stopword * Utility functions to correct work. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/utils/adt/tsquery_gist.c b/src/backend/utils/adt/tsquery_gist.c index ea18a350188a0..14d7343afa7c6 100644 --- a/src/backend/utils/adt/tsquery_gist.c +++ b/src/backend/utils/adt/tsquery_gist.c @@ -3,7 +3,7 @@ * tsquery_gist.c * GiST index support for tsquery * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/utils/adt/tsquery_op.c b/src/backend/utils/adt/tsquery_op.c index ea40804110c76..0575b55272b3f 100644 --- a/src/backend/utils/adt/tsquery_op.c +++ b/src/backend/utils/adt/tsquery_op.c @@ -3,7 +3,7 @@ * tsquery_op.c * Various operations with tsquery * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/utils/adt/tsquery_rewrite.c b/src/backend/utils/adt/tsquery_rewrite.c index 1be89e833c85b..cf0cc974ae5c2 100644 --- a/src/backend/utils/adt/tsquery_rewrite.c +++ b/src/backend/utils/adt/tsquery_rewrite.c @@ -3,7 +3,7 @@ * tsquery_rewrite.c * Utilities for reconstructing tsquery * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/utils/adt/tsquery_util.c b/src/backend/utils/adt/tsquery_util.c index e5c684e289ea1..7f936427b5fd6 100644 --- a/src/backend/utils/adt/tsquery_util.c +++ b/src/backend/utils/adt/tsquery_util.c @@ -3,7 +3,7 @@ * tsquery_util.c * Utilities for tsquery datatype * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/utils/adt/tsrank.c b/src/backend/utils/adt/tsrank.c index 38b413f6ffff8..977f70047932b 100644 --- a/src/backend/utils/adt/tsrank.c +++ b/src/backend/utils/adt/tsrank.c @@ -3,7 +3,7 @@ * tsrank.c * rank tsvector by tsquery * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/utils/adt/tsvector.c b/src/backend/utils/adt/tsvector.c index cd3bb9b63e313..b02fecc0811ca 100644 --- a/src/backend/utils/adt/tsvector.c +++ b/src/backend/utils/adt/tsvector.c @@ -3,7 +3,7 @@ * tsvector.c * I/O functions for tsvector * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c index 756a48a167ad3..2939fb5c21037 100644 --- a/src/backend/utils/adt/tsvector_op.c +++ b/src/backend/utils/adt/tsvector_op.c @@ -3,7 +3,7 @@ * tsvector_op.c * operations over tsvector * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/utils/adt/tsvector_parser.c b/src/backend/utils/adt/tsvector_parser.c index cfc181c20dfc8..c2df4093e6be3 100644 --- a/src/backend/utils/adt/tsvector_parser.c +++ b/src/backend/utils/adt/tsvector_parser.c @@ -3,7 +3,7 @@ * tsvector_parser.c * Parser for tsvector * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/utils/adt/uuid.c b/src/backend/utils/adt/uuid.c index c906ee789d92f..b02c9fcf984ad 100644 --- a/src/backend/utils/adt/uuid.c +++ b/src/backend/utils/adt/uuid.c @@ -3,7 +3,7 @@ * uuid.c * Functions for the built-in type "uuid". * - * Copyright (c) 2007-2020, PostgreSQL Global Development Group + * Copyright (c) 2007-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/adt/uuid.c diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c index 3c03459f5192d..abbb4d810686e 100644 --- a/src/backend/utils/adt/varbit.c +++ b/src/backend/utils/adt/varbit.c @@ -20,7 +20,7 @@ * * Code originally contributed by Adriaan Joubert. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c index b595ab9569cfd..8fc84649f1954 100644 --- a/src/backend/utils/adt/varchar.c +++ b/src/backend/utils/adt/varchar.c @@ -3,7 +3,7 @@ * varchar.c * Functions for the built-in types char(n) and varchar(n). * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index 9300d19e0c013..ec1fb4d1b90bc 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -3,7 +3,7 @@ * varlena.c * Functions for the variable-length built-in types. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/version.c b/src/backend/utils/adt/version.c index 37915271c7f2d..7e704987da0b1 100644 --- a/src/backend/utils/adt/version.c +++ b/src/backend/utils/adt/version.c @@ -3,7 +3,7 @@ * version.c * Returns the PostgreSQL version string * - * Copyright (c) 1998-2020, PostgreSQL Global Development Group + * Copyright (c) 1998-2021, PostgreSQL Global Development Group * * IDENTIFICATION * diff --git a/src/backend/utils/adt/windowfuncs.c b/src/backend/utils/adt/windowfuncs.c index f0c8ae686dd45..9c127617d1e1e 100644 --- a/src/backend/utils/adt/windowfuncs.c +++ b/src/backend/utils/adt/windowfuncs.c @@ -3,7 +3,7 @@ * windowfuncs.c * Standard window functions defined in SQL spec. * - * Portions Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2000-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/backend/utils/adt/xid.c b/src/backend/utils/adt/xid.c index a4762014ba1fa..24c1c9373265d 100644 --- a/src/backend/utils/adt/xid.c +++ b/src/backend/utils/adt/xid.c @@ -3,7 +3,7 @@ * xid.c * POSTGRES transaction identifier and command identifier datatypes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/adt/xid8funcs.c b/src/backend/utils/adt/xid8funcs.c index c4401f4adf720..cc2b4ac7979a8 100644 --- a/src/backend/utils/adt/xid8funcs.c +++ b/src/backend/utils/adt/xid8funcs.c @@ -15,7 +15,7 @@ * users. The txid_XXX variants should eventually be dropped. * * - * Copyright (c) 2003-2020, PostgreSQL Global Development Group + * Copyright (c) 2003-2021, PostgreSQL Global Development Group * Author: Jan Wieck, Afilias USA INC. * 64-bit txids: Marko Kreen, Skype Technologies * diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index 4c299057a6fb2..ca38f961078c4 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -4,7 +4,7 @@ * XML data type support. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/utils/adt/xml.c diff --git a/src/backend/utils/cache/attoptcache.c b/src/backend/utils/cache/attoptcache.c index 934a84e03f1d0..72d89cb64164a 100644 --- a/src/backend/utils/cache/attoptcache.c +++ b/src/backend/utils/cache/attoptcache.c @@ -6,7 +6,7 @@ * Attribute options are cached separately from the fixed-size portion of * pg_attribute entries, which are handled by the relcache. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c index 3613ae5f44d3d..ba95755867029 100644 --- a/src/backend/utils/cache/catcache.c +++ b/src/backend/utils/cache/catcache.c @@ -3,7 +3,7 @@ * catcache.c * System catalog cache for tuples matching a key. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/cache/evtcache.c b/src/backend/utils/cache/evtcache.c index 0877bc7e0e016..460b720a65121 100644 --- a/src/backend/utils/cache/evtcache.c +++ b/src/backend/utils/cache/evtcache.c @@ -3,7 +3,7 @@ * evtcache.c * Special-purpose cache for event trigger data. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c index e7279d06a3ddd..0837054e7c65c 100644 --- a/src/backend/utils/cache/inval.c +++ b/src/backend/utils/cache/inval.c @@ -89,7 +89,7 @@ * support the decoding of the in-progress transactions. See * CommandEndInvalidationMessages. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index ad92636f7f19d..85c458bc46ee4 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -3,7 +3,7 @@ * lsyscache.c * Convenience routines for common queries in the system catalog cache. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/cache/partcache.c b/src/backend/utils/cache/partcache.c index acf8a44f30fc6..a6388d980ed06 100644 --- a/src/backend/utils/cache/partcache.c +++ b/src/backend/utils/cache/partcache.c @@ -4,7 +4,7 @@ * Support routines for manipulating partition information cached in * relcache * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c index 50d6ad28b4cdb..2d0d7841a7653 100644 --- a/src/backend/utils/cache/plancache.c +++ b/src/backend/utils/cache/plancache.c @@ -44,7 +44,7 @@ * if the old one gets invalidated. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 3bd5e18042522..afc3451a54386 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -3,7 +3,7 @@ * relcache.c * POSTGRES relation descriptor cache code * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/cache/relfilenodemap.c b/src/backend/utils/cache/relfilenodemap.c index 38e6379974c05..56d7c73d3398f 100644 --- a/src/backend/utils/cache/relfilenodemap.c +++ b/src/backend/utils/cache/relfilenodemap.c @@ -3,7 +3,7 @@ * relfilenodemap.c * relfilenode to oid mapping cache. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/cache/relmapper.c b/src/backend/utils/cache/relmapper.c index 73e45eb4846ce..424624cf0dad2 100644 --- a/src/backend/utils/cache/relmapper.c +++ b/src/backend/utils/cache/relmapper.c @@ -28,7 +28,7 @@ * all these files commit in a single map file update rather than being tied * to transaction commit. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/cache/spccache.c b/src/backend/utils/cache/spccache.c index c8387e2541359..5870f436df828 100644 --- a/src/backend/utils/cache/spccache.c +++ b/src/backend/utils/cache/spccache.c @@ -8,7 +8,7 @@ * be a measurable performance gain from doing this, but that might change * in the future as we add more options. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index 89f08a4f43ca4..e4dc4ee34eebf 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -3,7 +3,7 @@ * syscache.c * System cache management routines * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/cache/ts_cache.c b/src/backend/utils/cache/ts_cache.c index a2867fac7de0d..384107b6bac39 100644 --- a/src/backend/utils/cache/ts_cache.c +++ b/src/backend/utils/cache/ts_cache.c @@ -17,7 +17,7 @@ * any database access. * * - * Copyright (c) 2006-2020, PostgreSQL Global Development Group + * Copyright (c) 2006-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/cache/ts_cache.c diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c index 8c97ef3955772..4915ef59349be 100644 --- a/src/backend/utils/cache/typcache.c +++ b/src/backend/utils/cache/typcache.c @@ -31,7 +31,7 @@ * constraint changes are also tracked properly. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/errcodes.txt b/src/backend/utils/errcodes.txt index c79312ed03974..64ca2deec9995 100644 --- a/src/backend/utils/errcodes.txt +++ b/src/backend/utils/errcodes.txt @@ -2,7 +2,7 @@ # errcodes.txt # PostgreSQL error codes # -# Copyright (c) 2003-2020, PostgreSQL Global Development Group +# Copyright (c) 2003-2021, PostgreSQL Global Development Group # # This list serves as the basis for generating source files containing error # codes. It is kept in a common format to make sure all these source files have diff --git a/src/backend/utils/error/assert.c b/src/backend/utils/error/assert.c index a8c0a8ec487c9..70a410a1910f9 100644 --- a/src/backend/utils/error/assert.c +++ b/src/backend/utils/error/assert.c @@ -3,7 +3,7 @@ * assert.c * Assert support code. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index 9a69038b80c7c..7790f6ab25590 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -43,7 +43,7 @@ * overflow.) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c index adb31e109f721..e8c6cdde9728b 100644 --- a/src/backend/utils/fmgr/dfmgr.c +++ b/src/backend/utils/fmgr/dfmgr.c @@ -3,7 +3,7 @@ * dfmgr.c * Dynamic function manager code. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c index fa5f7ac615847..b6835c2c4c1ef 100644 --- a/src/backend/utils/fmgr/fmgr.c +++ b/src/backend/utils/fmgr/fmgr.c @@ -3,7 +3,7 @@ * fmgr.c * The Postgres function manager. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c index f6fa4ab2fb26e..2fd2e41f99b83 100644 --- a/src/backend/utils/fmgr/funcapi.c +++ b/src/backend/utils/fmgr/funcapi.c @@ -4,7 +4,7 @@ * Utility and convenience functions for fmgr functions that return * sets and/or composite types, or deal with VARIADIC inputs. * - * Copyright (c) 2002-2020, PostgreSQL Global Development Group + * Copyright (c) 2002-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/fmgr/funcapi.c diff --git a/src/backend/utils/generate-errcodes.pl b/src/backend/utils/generate-errcodes.pl index 1a071fbb1f43c..c5cdd388138da 100644 --- a/src/backend/utils/generate-errcodes.pl +++ b/src/backend/utils/generate-errcodes.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl # # Generate the errcodes.h header from errcodes.txt -# Copyright (c) 2000-2020, PostgreSQL Global Development Group +# Copyright (c) 2000-2021, PostgreSQL Global Development Group use strict; use warnings; diff --git a/src/backend/utils/hash/dynahash.c b/src/backend/utils/hash/dynahash.c index ce93ca642fad9..6546e3c7c79fe 100644 --- a/src/backend/utils/hash/dynahash.c +++ b/src/backend/utils/hash/dynahash.c @@ -52,7 +52,7 @@ * dynahash has better performance for large entries. * - Guarantees stable pointers to entries. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/hash/pg_crc.c b/src/backend/utils/hash/pg_crc.c index 41e9597fb0091..77e3f6e655316 100644 --- a/src/backend/utils/hash/pg_crc.c +++ b/src/backend/utils/hash/pg_crc.c @@ -7,7 +7,7 @@ * A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS, available from * http://ross.net/crc/download/crc_v3.txt or several other net sites. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c index 6ab8216839891..3d5d6cc033c66 100644 --- a/src/backend/utils/init/globals.c +++ b/src/backend/utils/init/globals.c @@ -3,7 +3,7 @@ * globals.c * global variable declarations * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index ed2ab4b5b29a8..0f67b99cc5534 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -3,7 +3,7 @@ * miscinit.c * miscellaneous initialization support stuff * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index 9723e457ce920..59b3f4b135988 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -3,7 +3,7 @@ * postinit.c * postgres initialization utilities * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/mb/Unicode/Makefile b/src/backend/utils/mb/Unicode/Makefile index da307d8eb95c9..ed6fc07e08802 100644 --- a/src/backend/utils/mb/Unicode/Makefile +++ b/src/backend/utils/mb/Unicode/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/backend/utils/mb/Unicode # -# Copyright (c) 2001-2020, PostgreSQL Global Development Group +# Copyright (c) 2001-2021, PostgreSQL Global Development Group # # src/backend/utils/mb/Unicode/Makefile # diff --git a/src/backend/utils/mb/Unicode/UCS_to_BIG5.pl b/src/backend/utils/mb/Unicode/UCS_to_BIG5.pl index 84c9c5354130a..67b6b432113f4 100755 --- a/src/backend/utils/mb/Unicode/UCS_to_BIG5.pl +++ b/src/backend/utils/mb/Unicode/UCS_to_BIG5.pl @@ -1,6 +1,6 @@ #! /usr/bin/perl # -# Copyright (c) 2001-2020, PostgreSQL Global Development Group +# Copyright (c) 2001-2021, PostgreSQL Global Development Group # # src/backend/utils/mb/Unicode/UCS_to_BIG5.pl # diff --git a/src/backend/utils/mb/Unicode/UCS_to_EUC_CN.pl b/src/backend/utils/mb/Unicode/UCS_to_EUC_CN.pl index 1596b64238f12..88c561b32d0e1 100755 --- a/src/backend/utils/mb/Unicode/UCS_to_EUC_CN.pl +++ b/src/backend/utils/mb/Unicode/UCS_to_EUC_CN.pl @@ -1,6 +1,6 @@ #! /usr/bin/perl # -# Copyright (c) 2007-2020, PostgreSQL Global Development Group +# Copyright (c) 2007-2021, PostgreSQL Global Development Group # # src/backend/utils/mb/Unicode/UCS_to_GB18030.pl # diff --git a/src/backend/utils/mb/Unicode/UCS_to_EUC_JIS_2004.pl b/src/backend/utils/mb/Unicode/UCS_to_EUC_JIS_2004.pl index 6d1681a18a356..ea558dba68b1b 100755 --- a/src/backend/utils/mb/Unicode/UCS_to_EUC_JIS_2004.pl +++ b/src/backend/utils/mb/Unicode/UCS_to_EUC_JIS_2004.pl @@ -1,6 +1,6 @@ #! /usr/bin/perl # -# Copyright (c) 2007-2020, PostgreSQL Global Development Group +# Copyright (c) 2007-2021, PostgreSQL Global Development Group # # src/backend/utils/mb/Unicode/UCS_to_EUC_JIS_2004.pl # diff --git a/src/backend/utils/mb/Unicode/UCS_to_EUC_JP.pl b/src/backend/utils/mb/Unicode/UCS_to_EUC_JP.pl index 3414796ffd356..bd50f63dbaf08 100755 --- a/src/backend/utils/mb/Unicode/UCS_to_EUC_JP.pl +++ b/src/backend/utils/mb/Unicode/UCS_to_EUC_JP.pl @@ -1,6 +1,6 @@ #! /usr/bin/perl # -# Copyright (c) 2001-2020, PostgreSQL Global Development Group +# Copyright (c) 2001-2021, PostgreSQL Global Development Group # # src/backend/utils/mb/Unicode/UCS_to_EUC_JP.pl # diff --git a/src/backend/utils/mb/Unicode/UCS_to_EUC_KR.pl b/src/backend/utils/mb/Unicode/UCS_to_EUC_KR.pl index b560f9f37eaf3..a037493fd16e5 100755 --- a/src/backend/utils/mb/Unicode/UCS_to_EUC_KR.pl +++ b/src/backend/utils/mb/Unicode/UCS_to_EUC_KR.pl @@ -1,6 +1,6 @@ #! /usr/bin/perl # -# Copyright (c) 2001-2020, PostgreSQL Global Development Group +# Copyright (c) 2001-2021, PostgreSQL Global Development Group # # src/backend/utils/mb/Unicode/UCS_to_EUC_KR.pl # diff --git a/src/backend/utils/mb/Unicode/UCS_to_EUC_TW.pl b/src/backend/utils/mb/Unicode/UCS_to_EUC_TW.pl index 0f52183ff5fa5..7f49be8ad1d2e 100755 --- a/src/backend/utils/mb/Unicode/UCS_to_EUC_TW.pl +++ b/src/backend/utils/mb/Unicode/UCS_to_EUC_TW.pl @@ -1,6 +1,6 @@ #! /usr/bin/perl # -# Copyright (c) 2001-2020, PostgreSQL Global Development Group +# Copyright (c) 2001-2021, PostgreSQL Global Development Group # # src/backend/utils/mb/Unicode/UCS_to_EUC_TW.pl # diff --git a/src/backend/utils/mb/Unicode/UCS_to_GB18030.pl b/src/backend/utils/mb/Unicode/UCS_to_GB18030.pl index 57e63b4004a2c..61c47970fc688 100755 --- a/src/backend/utils/mb/Unicode/UCS_to_GB18030.pl +++ b/src/backend/utils/mb/Unicode/UCS_to_GB18030.pl @@ -1,6 +1,6 @@ #! /usr/bin/perl # -# Copyright (c) 2007-2020, PostgreSQL Global Development Group +# Copyright (c) 2007-2021, PostgreSQL Global Development Group # # src/backend/utils/mb/Unicode/UCS_to_GB18030.pl # diff --git a/src/backend/utils/mb/Unicode/UCS_to_JOHAB.pl b/src/backend/utils/mb/Unicode/UCS_to_JOHAB.pl index 0bcea9e0d4f30..0f4bfe8af8993 100755 --- a/src/backend/utils/mb/Unicode/UCS_to_JOHAB.pl +++ b/src/backend/utils/mb/Unicode/UCS_to_JOHAB.pl @@ -1,6 +1,6 @@ #! /usr/bin/perl # -# Copyright (c) 2001-2020, PostgreSQL Global Development Group +# Copyright (c) 2001-2021, PostgreSQL Global Development Group # # src/backend/utils/mb/Unicode/UCS_to_JOHAB.pl # diff --git a/src/backend/utils/mb/Unicode/UCS_to_SHIFT_JIS_2004.pl b/src/backend/utils/mb/Unicode/UCS_to_SHIFT_JIS_2004.pl index b86714dd46dff..710d5ce3c880f 100755 --- a/src/backend/utils/mb/Unicode/UCS_to_SHIFT_JIS_2004.pl +++ b/src/backend/utils/mb/Unicode/UCS_to_SHIFT_JIS_2004.pl @@ -1,6 +1,6 @@ #! /usr/bin/perl # -# Copyright (c) 2007-2020, PostgreSQL Global Development Group +# Copyright (c) 2007-2021, PostgreSQL Global Development Group # # src/backend/utils/mb/Unicode/UCS_to_SHIFT_JIS_2004.pl # diff --git a/src/backend/utils/mb/Unicode/UCS_to_SJIS.pl b/src/backend/utils/mb/Unicode/UCS_to_SJIS.pl index 5f4512ec87ed5..bb1f51c044867 100755 --- a/src/backend/utils/mb/Unicode/UCS_to_SJIS.pl +++ b/src/backend/utils/mb/Unicode/UCS_to_SJIS.pl @@ -1,6 +1,6 @@ #! /usr/bin/perl # -# Copyright (c) 2001-2020, PostgreSQL Global Development Group +# Copyright (c) 2001-2021, PostgreSQL Global Development Group # # src/backend/utils/mb/Unicode/UCS_to_SJIS.pl # diff --git a/src/backend/utils/mb/Unicode/UCS_to_UHC.pl b/src/backend/utils/mb/Unicode/UCS_to_UHC.pl index 3282106d7f07b..cc416bd4bfbec 100755 --- a/src/backend/utils/mb/Unicode/UCS_to_UHC.pl +++ b/src/backend/utils/mb/Unicode/UCS_to_UHC.pl @@ -1,6 +1,6 @@ #! /usr/bin/perl # -# Copyright (c) 2007-2020, PostgreSQL Global Development Group +# Copyright (c) 2007-2021, PostgreSQL Global Development Group # # src/backend/utils/mb/Unicode/UCS_to_GB18030.pl # diff --git a/src/backend/utils/mb/Unicode/UCS_to_most.pl b/src/backend/utils/mb/Unicode/UCS_to_most.pl index 8a7b26a5c5f3c..4f974388d75fb 100755 --- a/src/backend/utils/mb/Unicode/UCS_to_most.pl +++ b/src/backend/utils/mb/Unicode/UCS_to_most.pl @@ -1,6 +1,6 @@ #! /usr/bin/perl # -# Copyright (c) 2001-2020, PostgreSQL Global Development Group +# Copyright (c) 2001-2021, PostgreSQL Global Development Group # # src/backend/utils/mb/Unicode/UCS_to_most.pl # diff --git a/src/backend/utils/mb/Unicode/convutils.pm b/src/backend/utils/mb/Unicode/convutils.pm index 9d97061c6fe60..adfe12b2c298e 100644 --- a/src/backend/utils/mb/Unicode/convutils.pm +++ b/src/backend/utils/mb/Unicode/convutils.pm @@ -1,5 +1,5 @@ # -# Copyright (c) 2001-2020, PostgreSQL Global Development Group +# Copyright (c) 2001-2021, PostgreSQL Global Development Group # # src/backend/utils/mb/Unicode/convutils.pm diff --git a/src/backend/utils/mb/conv.c b/src/backend/utils/mb/conv.c index 54dcf71fb7562..f204f2abf463b 100644 --- a/src/backend/utils/mb/conv.c +++ b/src/backend/utils/mb/conv.c @@ -2,7 +2,7 @@ * * Utility functions for conversion procs. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/Makefile b/src/backend/utils/mb/conversion_procs/Makefile index e6e844af783b9..a2e935e84c451 100644 --- a/src/backend/utils/mb/conversion_procs/Makefile +++ b/src/backend/utils/mb/conversion_procs/Makefile @@ -2,7 +2,7 @@ # # Makefile for backend/utils/mb/conversion_procs # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/backend/utils/mb/conversion_procs/Makefile diff --git a/src/backend/utils/mb/conversion_procs/cyrillic_and_mic/cyrillic_and_mic.c b/src/backend/utils/mb/conversion_procs/cyrillic_and_mic/cyrillic_and_mic.c index 376b48ca611cc..4c5b02654de39 100644 --- a/src/backend/utils/mb/conversion_procs/cyrillic_and_mic/cyrillic_and_mic.c +++ b/src/backend/utils/mb/conversion_procs/cyrillic_and_mic/cyrillic_and_mic.c @@ -2,7 +2,7 @@ * * Cyrillic and MULE_INTERNAL * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/euc2004_sjis2004/euc2004_sjis2004.c b/src/backend/utils/mb/conversion_procs/euc2004_sjis2004/euc2004_sjis2004.c index 9ba6bd3040523..138ae4635fe8e 100644 --- a/src/backend/utils/mb/conversion_procs/euc2004_sjis2004/euc2004_sjis2004.c +++ b/src/backend/utils/mb/conversion_procs/euc2004_sjis2004/euc2004_sjis2004.c @@ -2,7 +2,7 @@ * * EUC_JIS_2004, SHIFT_JIS_2004 * - * Copyright (c) 2007-2020, PostgreSQL Global Development Group + * Copyright (c) 2007-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/mb/conversion_procs/euc2004_sjis2004/euc2004_sjis2004.c diff --git a/src/backend/utils/mb/conversion_procs/euc_cn_and_mic/euc_cn_and_mic.c b/src/backend/utils/mb/conversion_procs/euc_cn_and_mic/euc_cn_and_mic.c index 59c6c3bb12963..e9bb896935f37 100644 --- a/src/backend/utils/mb/conversion_procs/euc_cn_and_mic/euc_cn_and_mic.c +++ b/src/backend/utils/mb/conversion_procs/euc_cn_and_mic/euc_cn_and_mic.c @@ -2,7 +2,7 @@ * * EUC_CN and MULE_INTERNAL * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/euc_jp_and_sjis/euc_jp_and_sjis.c b/src/backend/utils/mb/conversion_procs/euc_jp_and_sjis/euc_jp_and_sjis.c index 4ca8e2126e4a5..e90363b7bfa1a 100644 --- a/src/backend/utils/mb/conversion_procs/euc_jp_and_sjis/euc_jp_and_sjis.c +++ b/src/backend/utils/mb/conversion_procs/euc_jp_and_sjis/euc_jp_and_sjis.c @@ -2,7 +2,7 @@ * * EUC_JP, SJIS and MULE_INTERNAL * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/euc_kr_and_mic/euc_kr_and_mic.c b/src/backend/utils/mb/conversion_procs/euc_kr_and_mic/euc_kr_and_mic.c index 4d7876a666eeb..d868a1ef3910d 100644 --- a/src/backend/utils/mb/conversion_procs/euc_kr_and_mic/euc_kr_and_mic.c +++ b/src/backend/utils/mb/conversion_procs/euc_kr_and_mic/euc_kr_and_mic.c @@ -2,7 +2,7 @@ * * EUC_KR and MULE_INTERNAL * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/euc_tw_and_big5/euc_tw_and_big5.c b/src/backend/utils/mb/conversion_procs/euc_tw_and_big5/euc_tw_and_big5.c index 82a22b9bebf80..64455a5d9eb4f 100644 --- a/src/backend/utils/mb/conversion_procs/euc_tw_and_big5/euc_tw_and_big5.c +++ b/src/backend/utils/mb/conversion_procs/euc_tw_and_big5/euc_tw_and_big5.c @@ -2,7 +2,7 @@ * * EUC_TW, BIG5 and MULE_INTERNAL * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/latin2_and_win1250/latin2_and_win1250.c b/src/backend/utils/mb/conversion_procs/latin2_and_win1250/latin2_and_win1250.c index f424f88145989..2e28e6780a58c 100644 --- a/src/backend/utils/mb/conversion_procs/latin2_and_win1250/latin2_and_win1250.c +++ b/src/backend/utils/mb/conversion_procs/latin2_and_win1250/latin2_and_win1250.c @@ -2,7 +2,7 @@ * * LATIN2 and WIN1250 * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/latin_and_mic/latin_and_mic.c b/src/backend/utils/mb/conversion_procs/latin_and_mic/latin_and_mic.c index a358a707c1131..bc651410f21dd 100644 --- a/src/backend/utils/mb/conversion_procs/latin_and_mic/latin_and_mic.c +++ b/src/backend/utils/mb/conversion_procs/latin_and_mic/latin_and_mic.c @@ -2,7 +2,7 @@ * * LATINn and MULE_INTERNAL * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_big5/utf8_and_big5.c b/src/backend/utils/mb/conversion_procs/utf8_and_big5/utf8_and_big5.c index 75ed49ac54e52..d6067cdc24e96 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_big5/utf8_and_big5.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_big5/utf8_and_big5.c @@ -2,7 +2,7 @@ * * BIG5 <--> UTF8 * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_cyrillic/utf8_and_cyrillic.c b/src/backend/utils/mb/conversion_procs/utf8_and_cyrillic/utf8_and_cyrillic.c index 90ad316111a5b..ed90e8e682e5d 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_cyrillic/utf8_and_cyrillic.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_cyrillic/utf8_and_cyrillic.c @@ -2,7 +2,7 @@ * * UTF8 and Cyrillic * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_euc2004/utf8_and_euc2004.c b/src/backend/utils/mb/conversion_procs/utf8_and_euc2004/utf8_and_euc2004.c index 018312489cbc7..d699affce47f3 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_euc2004/utf8_and_euc2004.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_euc2004/utf8_and_euc2004.c @@ -2,7 +2,7 @@ * * EUC_JIS_2004 <--> UTF8 * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_euc_cn/utf8_and_euc_cn.c b/src/backend/utils/mb/conversion_procs/utf8_and_euc_cn/utf8_and_euc_cn.c index 62182a9ba8b5e..d7c0ba6a58b4d 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_euc_cn/utf8_and_euc_cn.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_euc_cn/utf8_and_euc_cn.c @@ -2,7 +2,7 @@ * * EUC_CN <--> UTF8 * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_euc_jp/utf8_and_euc_jp.c b/src/backend/utils/mb/conversion_procs/utf8_and_euc_jp/utf8_and_euc_jp.c index dc5abb5dfd468..13a3a23e77b8d 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_euc_jp/utf8_and_euc_jp.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_euc_jp/utf8_and_euc_jp.c @@ -2,7 +2,7 @@ * * EUC_JP <--> UTF8 * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_euc_kr/utf8_and_euc_kr.c b/src/backend/utils/mb/conversion_procs/utf8_and_euc_kr/utf8_and_euc_kr.c index 088a38d839079..1bbb8aaef7b8d 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_euc_kr/utf8_and_euc_kr.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_euc_kr/utf8_and_euc_kr.c @@ -2,7 +2,7 @@ * * EUC_KR <--> UTF8 * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_euc_tw/utf8_and_euc_tw.c b/src/backend/utils/mb/conversion_procs/utf8_and_euc_tw/utf8_and_euc_tw.c index a9fe94f88b88f..9830045dccd6a 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_euc_tw/utf8_and_euc_tw.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_euc_tw/utf8_and_euc_tw.c @@ -2,7 +2,7 @@ * * EUC_TW <--> UTF8 * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_gb18030/utf8_and_gb18030.c b/src/backend/utils/mb/conversion_procs/utf8_and_gb18030/utf8_and_gb18030.c index 96909b588592d..f86ecf274241d 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_gb18030/utf8_and_gb18030.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_gb18030/utf8_and_gb18030.c @@ -2,7 +2,7 @@ * * GB18030 <--> UTF8 * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_gbk/utf8_and_gbk.c b/src/backend/utils/mb/conversion_procs/utf8_and_gbk/utf8_and_gbk.c index 78bbcd3ce7dd5..2ab8b16c8a819 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_gbk/utf8_and_gbk.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_gbk/utf8_and_gbk.c @@ -2,7 +2,7 @@ * * GBK <--> UTF8 * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_iso8859/utf8_and_iso8859.c b/src/backend/utils/mb/conversion_procs/utf8_and_iso8859/utf8_and_iso8859.c index 348524f4a2c9c..3e49f67ea2f29 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_iso8859/utf8_and_iso8859.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_iso8859/utf8_and_iso8859.c @@ -2,7 +2,7 @@ * * ISO 8859 2-16 <--> UTF8 * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_iso8859_1/utf8_and_iso8859_1.c b/src/backend/utils/mb/conversion_procs/utf8_and_iso8859_1/utf8_and_iso8859_1.c index 2cdca9f780d86..67e713cca11c3 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_iso8859_1/utf8_and_iso8859_1.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_iso8859_1/utf8_and_iso8859_1.c @@ -2,7 +2,7 @@ * * ISO8859_1 <--> UTF8 * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_johab/utf8_and_johab.c b/src/backend/utils/mb/conversion_procs/utf8_and_johab/utf8_and_johab.c index e09a7c8e41eb1..578f5df4e7f72 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_johab/utf8_and_johab.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_johab/utf8_and_johab.c @@ -2,7 +2,7 @@ * * JOHAB <--> UTF8 * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_sjis/utf8_and_sjis.c b/src/backend/utils/mb/conversion_procs/utf8_and_sjis/utf8_and_sjis.c index c56fa80a4bba6..dd9fc2975ad23 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_sjis/utf8_and_sjis.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_sjis/utf8_and_sjis.c @@ -2,7 +2,7 @@ * * SJIS <--> UTF8 * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_sjis2004/utf8_and_sjis2004.c b/src/backend/utils/mb/conversion_procs/utf8_and_sjis2004/utf8_and_sjis2004.c index 458500998d495..4bcc886d674e3 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_sjis2004/utf8_and_sjis2004.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_sjis2004/utf8_and_sjis2004.c @@ -2,7 +2,7 @@ * * SHIFT_JIS_2004 <--> UTF8 * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_uhc/utf8_and_uhc.c b/src/backend/utils/mb/conversion_procs/utf8_and_uhc/utf8_and_uhc.c index 3226ed032583a..c8e512994a103 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_uhc/utf8_and_uhc.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_uhc/utf8_and_uhc.c @@ -2,7 +2,7 @@ * * UHC <--> UTF8 * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/conversion_procs/utf8_and_win/utf8_and_win.c b/src/backend/utils/mb/conversion_procs/utf8_and_win/utf8_and_win.c index 1a0074d063cc0..0c9493dee564e 100644 --- a/src/backend/utils/mb/conversion_procs/utf8_and_win/utf8_and_win.c +++ b/src/backend/utils/mb/conversion_procs/utf8_and_win/utf8_and_win.c @@ -2,7 +2,7 @@ * * WIN <--> UTF8 * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mb/mbutils.c b/src/backend/utils/mb/mbutils.c index a8e13cacfde29..3b7b13f9486a0 100644 --- a/src/backend/utils/mb/mbutils.c +++ b/src/backend/utils/mb/mbutils.c @@ -23,7 +23,7 @@ * the result is validly encoded according to the destination encoding. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/mb/stringinfo_mb.c b/src/backend/utils/mb/stringinfo_mb.c index 5f51f538c1803..1fd6c63d3d702 100644 --- a/src/backend/utils/mb/stringinfo_mb.c +++ b/src/backend/utils/mb/stringinfo_mb.c @@ -8,7 +8,7 @@ * code. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/misc/guc-file.l b/src/backend/utils/misc/guc-file.l index c98e2202951ce..7885a169bb97f 100644 --- a/src/backend/utils/misc/guc-file.l +++ b/src/backend/utils/misc/guc-file.l @@ -2,7 +2,7 @@ /* * Scanner for the configuration file * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/backend/utils/misc/guc-file.l */ diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 878fcc2236585..2779da8a6936b 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -6,7 +6,7 @@ * See src/backend/utils/misc/README for more information. * * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * Written by Peter Eisentraut . * * IDENTIFICATION diff --git a/src/backend/utils/misc/help_config.c b/src/backend/utils/misc/help_config.c index c0120e1090813..d97243ddc8b15 100644 --- a/src/backend/utils/misc/help_config.c +++ b/src/backend/utils/misc/help_config.c @@ -7,7 +7,7 @@ * or GUC_DISALLOW_IN_FILE are not displayed, unless the user specifically * requests that variable by name * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/misc/help_config.c diff --git a/src/backend/utils/misc/pg_config.c b/src/backend/utils/misc/pg_config.c index 7a79cbff92c9a..34d77db75a145 100644 --- a/src/backend/utils/misc/pg_config.c +++ b/src/backend/utils/misc/pg_config.c @@ -3,7 +3,7 @@ * pg_config.c * Expose same output as pg_config except as an SRF * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c index d50d87a6021c6..209a20a8827d3 100644 --- a/src/backend/utils/misc/pg_controldata.c +++ b/src/backend/utils/misc/pg_controldata.c @@ -5,7 +5,7 @@ * Routines to expose the contents of the control data file via * a set of SQL functions. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/misc/pg_rusage.c b/src/backend/utils/misc/pg_rusage.c index 64a6af3152b04..bb5d9e7c85019 100644 --- a/src/backend/utils/misc/pg_rusage.c +++ b/src/backend/utils/misc/pg_rusage.c @@ -4,7 +4,7 @@ * Resource usage measurement support routines. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/misc/ps_status.c b/src/backend/utils/misc/ps_status.c index 1e8596e664569..5819faaf2d2f8 100644 --- a/src/backend/utils/misc/ps_status.c +++ b/src/backend/utils/misc/ps_status.c @@ -7,7 +7,7 @@ * * src/backend/utils/misc/ps_status.c * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * various details abducted from various places *-------------------------------------------------------------------- */ diff --git a/src/backend/utils/misc/queryenvironment.c b/src/backend/utils/misc/queryenvironment.c index 31de81f353eba..86d61d083bfd4 100644 --- a/src/backend/utils/misc/queryenvironment.c +++ b/src/backend/utils/misc/queryenvironment.c @@ -11,7 +11,7 @@ * on callers, since this is an opaque structure. This is the reason to * require a create function. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/misc/rls.c b/src/backend/utils/misc/rls.c index 016fe511eb7d2..13d25154dbe93 100644 --- a/src/backend/utils/misc/rls.c +++ b/src/backend/utils/misc/rls.c @@ -3,7 +3,7 @@ * rls.c * RLS-related utility functions. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/misc/sampling.c b/src/backend/utils/misc/sampling.c index 361c15614e7cd..0c327e823f715 100644 --- a/src/backend/utils/misc/sampling.c +++ b/src/backend/utils/misc/sampling.c @@ -3,7 +3,7 @@ * sampling.c * Relation block sampling routines. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/misc/superuser.c b/src/backend/utils/misc/superuser.c index 203a146390f60..9ec5a40f7ec27 100644 --- a/src/backend/utils/misc/superuser.c +++ b/src/backend/utils/misc/superuser.c @@ -9,7 +9,7 @@ * the single-user case works. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/misc/timeout.c b/src/backend/utils/misc/timeout.c index f1c9518b0c403..b47e8ba2fb490 100644 --- a/src/backend/utils/misc/timeout.c +++ b/src/backend/utils/misc/timeout.c @@ -3,7 +3,7 @@ * timeout.c * Routines to multiplex SIGALRM interrupts for multiple timeout reasons. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/misc/tzparser.c b/src/backend/utils/misc/tzparser.c index 46b2b0ca98dd2..d2aa5ee87d5da 100644 --- a/src/backend/utils/misc/tzparser.c +++ b/src/backend/utils/misc/tzparser.c @@ -11,7 +11,7 @@ * PG_TRY if necessary. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c index 60a761caba474..ec6c130d0fb2c 100644 --- a/src/backend/utils/mmgr/aset.c +++ b/src/backend/utils/mmgr/aset.c @@ -7,7 +7,7 @@ * type. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mmgr/dsa.c b/src/backend/utils/mmgr/dsa.c index 6e5e412429789..7e2a20b9417ca 100644 --- a/src/backend/utils/mmgr/dsa.c +++ b/src/backend/utils/mmgr/dsa.c @@ -39,7 +39,7 @@ * empty and be returned to the free page manager, and whole segments can * become empty and be returned to the operating system. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mmgr/freepage.c b/src/backend/utils/mmgr/freepage.c index 77f16f9b21bfe..e4ee1aab979e2 100644 --- a/src/backend/utils/mmgr/freepage.c +++ b/src/backend/utils/mmgr/freepage.c @@ -42,7 +42,7 @@ * where memory fragmentation is very severe, only a tiny fraction of * the pages under management are consumed by this btree. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mmgr/generation.c b/src/backend/utils/mmgr/generation.c index af52616e575df..2b90034764580 100644 --- a/src/backend/utils/mmgr/generation.c +++ b/src/backend/utils/mmgr/generation.c @@ -6,7 +6,7 @@ * Generation is a custom MemoryContext implementation designed for cases of * chunks with similar lifespan. * - * Portions Copyright (c) 2017-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2017-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/mmgr/generation.c diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c index dda70ef9f3344..84472b9158e7b 100644 --- a/src/backend/utils/mmgr/mcxt.c +++ b/src/backend/utils/mmgr/mcxt.c @@ -9,7 +9,7 @@ * context's MemoryContextMethods struct. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/mmgr/memdebug.c b/src/backend/utils/mmgr/memdebug.c index 812025b76e228..3644c7f6067a1 100644 --- a/src/backend/utils/mmgr/memdebug.c +++ b/src/backend/utils/mmgr/memdebug.c @@ -5,7 +5,7 @@ * public API of the memory management subsystem. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/utils/mmgr/memdebug.c diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c index 283dfe2d9e492..22c6d2ba5b2fe 100644 --- a/src/backend/utils/mmgr/portalmem.c +++ b/src/backend/utils/mmgr/portalmem.c @@ -8,7 +8,7 @@ * doesn't actually run the executor for them. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/mmgr/slab.c b/src/backend/utils/mmgr/slab.c index f8d801c4196d6..9213be7c9569f 100644 --- a/src/backend/utils/mmgr/slab.c +++ b/src/backend/utils/mmgr/slab.c @@ -7,7 +7,7 @@ * numbers of equally-sized objects are allocated (and freed). * * - * Portions Copyright (c) 2017-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2017-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/mmgr/slab.c diff --git a/src/backend/utils/probes.d b/src/backend/utils/probes.d index a0b0458108936..b0c50a3c7f9f1 100644 --- a/src/backend/utils/probes.d +++ b/src/backend/utils/probes.d @@ -1,7 +1,7 @@ /* ---------- * DTrace probes for PostgreSQL backend * - * Copyright (c) 2006-2020, PostgreSQL Global Development Group + * Copyright (c) 2006-2021, PostgreSQL Global Development Group * * src/backend/utils/probes.d * ---------- diff --git a/src/backend/utils/resowner/resowner.c b/src/backend/utils/resowner/resowner.c index 546ad8d1c5fad..10f15f6a3579a 100644 --- a/src/backend/utils/resowner/resowner.c +++ b/src/backend/utils/resowner/resowner.c @@ -9,7 +9,7 @@ * See utils/resowner/README for more info. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/backend/utils/sort/logtape.c b/src/backend/utils/sort/logtape.c index 28905124f965a..089ba2e106885 100644 --- a/src/backend/utils/sort/logtape.c +++ b/src/backend/utils/sort/logtape.c @@ -67,7 +67,7 @@ * There will always be the same number of runs as input tapes, and the same * number of input tapes as participants (worker Tuplesortstates). * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/sort/sharedtuplestore.c b/src/backend/utils/sort/sharedtuplestore.c index fe298ce92ed5c..57e35db4f8d0a 100644 --- a/src/backend/utils/sort/sharedtuplestore.c +++ b/src/backend/utils/sort/sharedtuplestore.c @@ -10,7 +10,7 @@ * scan where each backend reads an arbitrary subset of the tuples that were * written. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/sort/sortsupport.c b/src/backend/utils/sort/sortsupport.c index c436fbb4ce1e8..6a889ec189fd6 100644 --- a/src/backend/utils/sort/sortsupport.c +++ b/src/backend/utils/sort/sortsupport.c @@ -4,7 +4,7 @@ * Support routines for accelerated sorting. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c index d0cc04a878a14..7d0f96afb7882 100644 --- a/src/backend/utils/sort/tuplesort.c +++ b/src/backend/utils/sort/tuplesort.c @@ -83,7 +83,7 @@ * produce exactly one output run from their partial input. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/sort/tuplestore.c b/src/backend/utils/sort/tuplestore.c index 452a85a423bda..509a91b503e1a 100644 --- a/src/backend/utils/sort/tuplestore.c +++ b/src/backend/utils/sort/tuplestore.c @@ -43,7 +43,7 @@ * before switching to the other state or activating a different read pointer. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/time/combocid.c b/src/backend/utils/time/combocid.c index 9626f9810075b..6d67d38f252fb 100644 --- a/src/backend/utils/time/combocid.c +++ b/src/backend/utils/time/combocid.c @@ -30,7 +30,7 @@ * destroyed at the end of each transaction. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c index 8c41483e87c52..ae16c3ed7d60b 100644 --- a/src/backend/utils/time/snapmgr.c +++ b/src/backend/utils/time/snapmgr.c @@ -35,7 +35,7 @@ * stack is empty. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/bin/Makefile b/src/bin/Makefile index 8b870357a14fe..f7573efcd30f2 100644 --- a/src/bin/Makefile +++ b/src/bin/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/bin (client programs) # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/bin/Makefile diff --git a/src/bin/initdb/Makefile b/src/bin/initdb/Makefile index 7e2375478081c..a620a5bea061b 100644 --- a/src/bin/initdb/Makefile +++ b/src/bin/initdb/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/bin/initdb # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/bin/initdb/Makefile diff --git a/src/bin/initdb/findtimezone.c b/src/bin/initdb/findtimezone.c index 764ead97d34ed..8fe1e910f9688 100644 --- a/src/bin/initdb/findtimezone.c +++ b/src/bin/initdb/findtimezone.c @@ -3,7 +3,7 @@ * findtimezone.c * Functions for determining the default timezone to use. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/bin/initdb/findtimezone.c diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index 0865f73ee0b76..4453aeb0f0ff3 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -38,7 +38,7 @@ * * This code is released under the terms of the PostgreSQL License. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/initdb/initdb.c diff --git a/src/bin/pg_basebackup/Makefile b/src/bin/pg_basebackup/Makefile index 988007c6fdd68..1d861087ad1e7 100644 --- a/src/bin/pg_basebackup/Makefile +++ b/src/bin/pg_basebackup/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/bin/pg_basebackup # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/bin/pg_basebackup/Makefile diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c index 7a5d4562f9461..16d8929b238fd 100644 --- a/src/bin/pg_basebackup/pg_basebackup.c +++ b/src/bin/pg_basebackup/pg_basebackup.c @@ -4,7 +4,7 @@ * * Author: Magnus Hagander * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/bin/pg_basebackup/pg_basebackup.c diff --git a/src/bin/pg_basebackup/pg_receivewal.c b/src/bin/pg_basebackup/pg_receivewal.c index cddc896390da9..4122d840941b1 100644 --- a/src/bin/pg_basebackup/pg_receivewal.c +++ b/src/bin/pg_basebackup/pg_receivewal.c @@ -5,7 +5,7 @@ * * Author: Magnus Hagander * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/bin/pg_basebackup/pg_receivewal.c diff --git a/src/bin/pg_basebackup/pg_recvlogical.c b/src/bin/pg_basebackup/pg_recvlogical.c index a4e0d6aeb29c9..553ba7b8f4d02 100644 --- a/src/bin/pg_basebackup/pg_recvlogical.c +++ b/src/bin/pg_basebackup/pg_recvlogical.c @@ -3,7 +3,7 @@ * pg_recvlogical.c - receive data from a logical decoding slot in a streaming * fashion and write it to a local file. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/bin/pg_basebackup/pg_recvlogical.c diff --git a/src/bin/pg_basebackup/receivelog.c b/src/bin/pg_basebackup/receivelog.c index dc97c7e89c4d6..4fc050f3a1c81 100644 --- a/src/bin/pg_basebackup/receivelog.c +++ b/src/bin/pg_basebackup/receivelog.c @@ -5,7 +5,7 @@ * * Author: Magnus Hagander * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/bin/pg_basebackup/receivelog.c diff --git a/src/bin/pg_basebackup/receivelog.h b/src/bin/pg_basebackup/receivelog.h index efe7620401a3e..e04333bf81d73 100644 --- a/src/bin/pg_basebackup/receivelog.h +++ b/src/bin/pg_basebackup/receivelog.h @@ -2,7 +2,7 @@ * * receivelog.h * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/bin/pg_basebackup/receivelog.h diff --git a/src/bin/pg_basebackup/streamutil.c b/src/bin/pg_basebackup/streamutil.c index da577a7f8f485..99daf0e97278d 100644 --- a/src/bin/pg_basebackup/streamutil.c +++ b/src/bin/pg_basebackup/streamutil.c @@ -5,7 +5,7 @@ * * Author: Magnus Hagander * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/bin/pg_basebackup/streamutil.c diff --git a/src/bin/pg_basebackup/streamutil.h b/src/bin/pg_basebackup/streamutil.h index 57448656e3dfa..10f87ad0c14b3 100644 --- a/src/bin/pg_basebackup/streamutil.h +++ b/src/bin/pg_basebackup/streamutil.h @@ -2,7 +2,7 @@ * * streamutil.h * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/bin/pg_basebackup/streamutil.h diff --git a/src/bin/pg_basebackup/walmethods.c b/src/bin/pg_basebackup/walmethods.c index bd1947d623fef..a15bbb20e7373 100644 --- a/src/bin/pg_basebackup/walmethods.c +++ b/src/bin/pg_basebackup/walmethods.c @@ -5,7 +5,7 @@ * NOTE! The caller must ensure that only one method is instantiated in * any given program, and that it's only instantiated once! * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/bin/pg_basebackup/walmethods.c diff --git a/src/bin/pg_basebackup/walmethods.h b/src/bin/pg_basebackup/walmethods.h index 9a661c673ccdf..fc4bb52cb742c 100644 --- a/src/bin/pg_basebackup/walmethods.h +++ b/src/bin/pg_basebackup/walmethods.h @@ -2,7 +2,7 @@ * * walmethods.h * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/bin/pg_basebackup/walmethods.h diff --git a/src/bin/pg_checksums/Makefile b/src/bin/pg_checksums/Makefile index b1cfa5733d61b..ba62406105d1a 100644 --- a/src/bin/pg_checksums/Makefile +++ b/src/bin/pg_checksums/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/bin/pg_checksums # -# Copyright (c) 1998-2020, PostgreSQL Global Development Group +# Copyright (c) 1998-2021, PostgreSQL Global Development Group # # src/bin/pg_checksums/Makefile # diff --git a/src/bin/pg_checksums/pg_checksums.c b/src/bin/pg_checksums/pg_checksums.c index 28aba92a4c3c5..0223ee440829d 100644 --- a/src/bin/pg_checksums/pg_checksums.c +++ b/src/bin/pg_checksums/pg_checksums.c @@ -4,7 +4,7 @@ * Checks, enables or disables page level checksums for an offline * cluster * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/bin/pg_checksums/pg_checksums.c diff --git a/src/bin/pg_config/Makefile b/src/bin/pg_config/Makefile index d3b5f1fa7591d..fa60d602460bf 100644 --- a/src/bin/pg_config/Makefile +++ b/src/bin/pg_config/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/bin/pg_config # -# Copyright (c) 1998-2020, PostgreSQL Global Development Group +# Copyright (c) 1998-2021, PostgreSQL Global Development Group # # src/bin/pg_config/Makefile # diff --git a/src/bin/pg_config/pg_config.c b/src/bin/pg_config/pg_config.c index f5410f64187a6..c40bb3282e949 100644 --- a/src/bin/pg_config/pg_config.c +++ b/src/bin/pg_config/pg_config.c @@ -15,7 +15,7 @@ * * This code is released under the terms of the PostgreSQL License. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * src/bin/pg_config/pg_config.c * diff --git a/src/bin/pg_controldata/Makefile b/src/bin/pg_controldata/Makefile index 76b330dc1f9ea..c5405b8a080d5 100644 --- a/src/bin/pg_controldata/Makefile +++ b/src/bin/pg_controldata/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/bin/pg_controldata # -# Copyright (c) 1998-2020, PostgreSQL Global Development Group +# Copyright (c) 1998-2021, PostgreSQL Global Development Group # # src/bin/pg_controldata/Makefile # diff --git a/src/bin/pg_ctl/Makefile b/src/bin/pg_ctl/Makefile index 14602c1185129..5d5f5372a3f06 100644 --- a/src/bin/pg_ctl/Makefile +++ b/src/bin/pg_ctl/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/bin/pg_ctl # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/bin/pg_ctl/Makefile diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c index fcdc0213e488c..7985da0a94302 100644 --- a/src/bin/pg_ctl/pg_ctl.c +++ b/src/bin/pg_ctl/pg_ctl.c @@ -2,7 +2,7 @@ * * pg_ctl --- start/stops/restarts the PostgreSQL server * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * src/bin/pg_ctl/pg_ctl.c * diff --git a/src/bin/pg_dump/Makefile b/src/bin/pg_dump/Makefile index 2532d9183a665..38988eccc0da1 100644 --- a/src/bin/pg_dump/Makefile +++ b/src/bin/pg_dump/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/bin/pg_dump # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/bin/pg_dump/Makefile diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c index 634ca86cfb788..f80d2d3ce8a3f 100644 --- a/src/bin/pg_dump/common.c +++ b/src/bin/pg_dump/common.c @@ -4,7 +4,7 @@ * Catalog routines used by pg_dump; long ago these were shared * by another dump tool, but not anymore. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/bin/pg_dump/compress_io.c b/src/bin/pg_dump/compress_io.c index 1417401086a67..808df19495543 100644 --- a/src/bin/pg_dump/compress_io.c +++ b/src/bin/pg_dump/compress_io.c @@ -4,7 +4,7 @@ * Routines for archivers to write an uncompressed or compressed data * stream. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * This file includes two APIs for dealing with compressed data. The first diff --git a/src/bin/pg_dump/compress_io.h b/src/bin/pg_dump/compress_io.h index d2e6e1b85480e..1eafbd8456686 100644 --- a/src/bin/pg_dump/compress_io.h +++ b/src/bin/pg_dump/compress_io.h @@ -3,7 +3,7 @@ * compress_io.h * Interface to compress_io.c routines * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c index 536c9ffec8cde..d6aa048d4204b 100644 --- a/src/bin/pg_dump/dumputils.c +++ b/src/bin/pg_dump/dumputils.c @@ -5,7 +5,7 @@ * Basically this is stuff that is useful in both pg_dump and pg_dumpall. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/pg_dump/dumputils.c diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.h index d35d9d34d28c1..6e97da7487ef1 100644 --- a/src/bin/pg_dump/dumputils.h +++ b/src/bin/pg_dump/dumputils.h @@ -5,7 +5,7 @@ * Basically this is stuff that is useful in both pg_dump and pg_dumpall. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/pg_dump/dumputils.h diff --git a/src/bin/pg_dump/parallel.c b/src/bin/pg_dump/parallel.c index b51cc76c7dc21..c7351a43fde2d 100644 --- a/src/bin/pg_dump/parallel.c +++ b/src/bin/pg_dump/parallel.c @@ -4,7 +4,7 @@ * * Parallel support for pg_dump and pg_restore * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/bin/pg_dump/parallel.h b/src/bin/pg_dump/parallel.h index a2e98cb87bf01..0fbf736c811cc 100644 --- a/src/bin/pg_dump/parallel.h +++ b/src/bin/pg_dump/parallel.h @@ -4,7 +4,7 @@ * * Parallel support for pg_dump and pg_restore * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/bin/pg_dump/pg_backup_directory.c b/src/bin/pg_dump/pg_backup_directory.c index 650b542fce15d..fb8c7713a508a 100644 --- a/src/bin/pg_dump/pg_backup_directory.c +++ b/src/bin/pg_dump/pg_backup_directory.c @@ -17,7 +17,7 @@ * sync. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 2000, Philip Warner * diff --git a/src/bin/pg_dump/pg_backup_utils.c b/src/bin/pg_dump/pg_backup_utils.c index 5729a20a84af3..c709a40e06d5c 100644 --- a/src/bin/pg_dump/pg_backup_utils.c +++ b/src/bin/pg_dump/pg_backup_utils.c @@ -4,7 +4,7 @@ * Utility routines shared by pg_dump and pg_restore * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/pg_dump/pg_backup_utils.c diff --git a/src/bin/pg_dump/pg_backup_utils.h b/src/bin/pg_dump/pg_backup_utils.h index 2bea167a69bc5..306798f9ac979 100644 --- a/src/bin/pg_dump/pg_backup_utils.h +++ b/src/bin/pg_dump/pg_backup_utils.h @@ -4,7 +4,7 @@ * Utility routines shared by pg_dump and pg_restore. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/pg_dump/pg_backup_utils.h diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 1ab98a2286e2a..1f70653c02676 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -4,7 +4,7 @@ * pg_dump is a utility for dumping out a postgres database * into a script file. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * pg_dump will read the system catalogs in a database and dump out a diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index d7f77f1d3e005..b3ce4eefe2fae 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -3,7 +3,7 @@ * pg_dump.h * Common header file for the pg_dump utility * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/pg_dump/pg_dump.h diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c index 654e2ec51417e..f990b86394229 100644 --- a/src/bin/pg_dump/pg_dump_sort.c +++ b/src/bin/pg_dump/pg_dump_sort.c @@ -4,7 +4,7 @@ * Sort the items of a dump into a safe order for dumping * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c index 2fa11745cc330..85d08ad660376 100644 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.c @@ -2,7 +2,7 @@ * * pg_dumpall.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * pg_dumpall forces all pg_dump output to be text, since it also outputs diff --git a/src/bin/pg_resetwal/Makefile b/src/bin/pg_resetwal/Makefile index 464268e9788a8..7dfa80c5e51ff 100644 --- a/src/bin/pg_resetwal/Makefile +++ b/src/bin/pg_resetwal/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/bin/pg_resetwal # -# Copyright (c) 1998-2020, PostgreSQL Global Development Group +# Copyright (c) 1998-2021, PostgreSQL Global Development Group # # src/bin/pg_resetwal/Makefile # diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c index cb6ef1918206a..805dafef072b1 100644 --- a/src/bin/pg_resetwal/pg_resetwal.c +++ b/src/bin/pg_resetwal/pg_resetwal.c @@ -20,7 +20,7 @@ * step 2 ... * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/pg_resetwal/pg_resetwal.c diff --git a/src/bin/pg_rewind/Makefile b/src/bin/pg_rewind/Makefile index 9bfde5c087b26..5514b95e6c1e1 100644 --- a/src/bin/pg_rewind/Makefile +++ b/src/bin/pg_rewind/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/bin/pg_rewind # -# Portions Copyright (c) 2013-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 2013-2021, PostgreSQL Global Development Group # # src/bin/pg_rewind/Makefile # diff --git a/src/bin/pg_rewind/datapagemap.c b/src/bin/pg_rewind/datapagemap.c index 16fa89da943ec..3f8952b8f3be0 100644 --- a/src/bin/pg_rewind/datapagemap.c +++ b/src/bin/pg_rewind/datapagemap.c @@ -5,7 +5,7 @@ * * This is a fairly simple bitmap. * - * Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Copyright (c) 2013-2021, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/bin/pg_rewind/datapagemap.h b/src/bin/pg_rewind/datapagemap.h index b5fac09ea6b27..76e9f20c94124 100644 --- a/src/bin/pg_rewind/datapagemap.h +++ b/src/bin/pg_rewind/datapagemap.h @@ -2,7 +2,7 @@ * * datapagemap.h * - * Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Copyright (c) 2013-2021, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/bin/pg_rewind/file_ops.c b/src/bin/pg_rewind/file_ops.c index 065368a2208ee..c50f283ede41b 100644 --- a/src/bin/pg_rewind/file_ops.c +++ b/src/bin/pg_rewind/file_ops.c @@ -8,7 +8,7 @@ * do nothing if it's enabled. You should avoid accessing the target files * directly but if you do, make sure you honor the --dry-run mode! * - * Portions Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2013-2021, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/bin/pg_rewind/file_ops.h b/src/bin/pg_rewind/file_ops.h index c763085976830..611981f293a12 100644 --- a/src/bin/pg_rewind/file_ops.h +++ b/src/bin/pg_rewind/file_ops.h @@ -3,7 +3,7 @@ * file_ops.h * Helper functions for operating on files * - * Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Copyright (c) 2013-2021, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/bin/pg_rewind/filemap.c b/src/bin/pg_rewind/filemap.c index ba34dbac1468f..2618b4c957b2f 100644 --- a/src/bin/pg_rewind/filemap.c +++ b/src/bin/pg_rewind/filemap.c @@ -16,7 +16,7 @@ * for each file. Finally, it sorts the array to the final order that the * actions should be executed in. * - * Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Copyright (c) 2013-2021, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/bin/pg_rewind/filemap.h b/src/bin/pg_rewind/filemap.h index 6f03447d7ebf5..926463efadc74 100644 --- a/src/bin/pg_rewind/filemap.h +++ b/src/bin/pg_rewind/filemap.h @@ -2,7 +2,7 @@ * * filemap.h * - * Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Copyright (c) 2013-2021, PostgreSQL Global Development Group *------------------------------------------------------------------------- */ #ifndef FILEMAP_H diff --git a/src/bin/pg_rewind/libpq_source.c b/src/bin/pg_rewind/libpq_source.c index 47beba277a4ca..86d2adcaee99f 100644 --- a/src/bin/pg_rewind/libpq_source.c +++ b/src/bin/pg_rewind/libpq_source.c @@ -3,7 +3,7 @@ * libpq_source.c * Functions for fetching files from a remote server via libpq. * - * Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Copyright (c) 2013-2021, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/bin/pg_rewind/local_source.c b/src/bin/pg_rewind/local_source.c index fa1b6e80ec328..9c3491c3fba1b 100644 --- a/src/bin/pg_rewind/local_source.c +++ b/src/bin/pg_rewind/local_source.c @@ -3,7 +3,7 @@ * local_source.c * Functions for using a local data directory as the source. * - * Portions Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2013-2021, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/bin/pg_rewind/parsexlog.c b/src/bin/pg_rewind/parsexlog.c index 9275cba51bd65..7117ae522972d 100644 --- a/src/bin/pg_rewind/parsexlog.c +++ b/src/bin/pg_rewind/parsexlog.c @@ -3,7 +3,7 @@ * parsexlog.c * Functions for reading Write-Ahead-Log * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * *------------------------------------------------------------------------- diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c index d89c08f81da08..359a6a587cb7f 100644 --- a/src/bin/pg_rewind/pg_rewind.c +++ b/src/bin/pg_rewind/pg_rewind.c @@ -3,7 +3,7 @@ * pg_rewind.c * Synchronizes a PostgreSQL data directory to a new timeline * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/bin/pg_rewind/pg_rewind.h b/src/bin/pg_rewind/pg_rewind.h index 0dc3dbd52551c..d38635a73dc8a 100644 --- a/src/bin/pg_rewind/pg_rewind.h +++ b/src/bin/pg_rewind/pg_rewind.h @@ -3,7 +3,7 @@ * pg_rewind.h * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * *------------------------------------------------------------------------- diff --git a/src/bin/pg_rewind/rewind_source.h b/src/bin/pg_rewind/rewind_source.h index e87f239a47a09..2da92dbff9487 100644 --- a/src/bin/pg_rewind/rewind_source.h +++ b/src/bin/pg_rewind/rewind_source.h @@ -8,7 +8,7 @@ * operations to fetch data from the source system, so that the rest of * the code doesn't need to care what kind of a source its dealing with. * - * Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Copyright (c) 2013-2021, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/bin/pg_rewind/timeline.c b/src/bin/pg_rewind/timeline.c index 1ea6607189380..6756c5ddbf79a 100644 --- a/src/bin/pg_rewind/timeline.c +++ b/src/bin/pg_rewind/timeline.c @@ -3,7 +3,7 @@ * timeline.c * timeline-related functions. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/bin/pg_upgrade/check.c b/src/bin/pg_upgrade/check.c index f3afea9d56117..43fc297eb69d5 100644 --- a/src/bin/pg_upgrade/check.c +++ b/src/bin/pg_upgrade/check.c @@ -3,7 +3,7 @@ * * server checks and output routines * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * src/bin/pg_upgrade/check.c */ diff --git a/src/bin/pg_upgrade/controldata.c b/src/bin/pg_upgrade/controldata.c index 7eb56e7a293f5..4f647cdf33474 100644 --- a/src/bin/pg_upgrade/controldata.c +++ b/src/bin/pg_upgrade/controldata.c @@ -3,7 +3,7 @@ * * controldata functions * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * src/bin/pg_upgrade/controldata.c */ diff --git a/src/bin/pg_upgrade/dump.c b/src/bin/pg_upgrade/dump.c index 20e73be361538..33d9591f3743f 100644 --- a/src/bin/pg_upgrade/dump.c +++ b/src/bin/pg_upgrade/dump.c @@ -3,7 +3,7 @@ * * dump functions * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * src/bin/pg_upgrade/dump.c */ diff --git a/src/bin/pg_upgrade/exec.c b/src/bin/pg_upgrade/exec.c index bdff13bb688fe..43a4565c2eff0 100644 --- a/src/bin/pg_upgrade/exec.c +++ b/src/bin/pg_upgrade/exec.c @@ -3,7 +3,7 @@ * * execution functions * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * src/bin/pg_upgrade/exec.c */ diff --git a/src/bin/pg_upgrade/file.c b/src/bin/pg_upgrade/file.c index cc8a675d0095c..9b0cc16e452fc 100644 --- a/src/bin/pg_upgrade/file.c +++ b/src/bin/pg_upgrade/file.c @@ -3,7 +3,7 @@ * * file system operations * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * src/bin/pg_upgrade/file.c */ diff --git a/src/bin/pg_upgrade/function.c b/src/bin/pg_upgrade/function.c index e0bc368e1e168..4952de1de5a9d 100644 --- a/src/bin/pg_upgrade/function.c +++ b/src/bin/pg_upgrade/function.c @@ -3,7 +3,7 @@ * * server-side function support * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * src/bin/pg_upgrade/function.c */ diff --git a/src/bin/pg_upgrade/info.c b/src/bin/pg_upgrade/info.c index 7e524ea19206d..5d9a26cf82290 100644 --- a/src/bin/pg_upgrade/info.c +++ b/src/bin/pg_upgrade/info.c @@ -3,7 +3,7 @@ * * information support functions * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * src/bin/pg_upgrade/info.c */ diff --git a/src/bin/pg_upgrade/option.c b/src/bin/pg_upgrade/option.c index 5b566c14ef4ea..9c9b313e0cf9e 100644 --- a/src/bin/pg_upgrade/option.c +++ b/src/bin/pg_upgrade/option.c @@ -3,7 +3,7 @@ * * options functions * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * src/bin/pg_upgrade/option.c */ diff --git a/src/bin/pg_upgrade/parallel.c b/src/bin/pg_upgrade/parallel.c index 5e8cfbbec909c..d5883e2eba46b 100644 --- a/src/bin/pg_upgrade/parallel.c +++ b/src/bin/pg_upgrade/parallel.c @@ -3,7 +3,7 @@ * * multi-process support * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * src/bin/pg_upgrade/parallel.c */ diff --git a/src/bin/pg_upgrade/pg_upgrade.c b/src/bin/pg_upgrade/pg_upgrade.c index e2253ecd5d068..e23b8ca88d919 100644 --- a/src/bin/pg_upgrade/pg_upgrade.c +++ b/src/bin/pg_upgrade/pg_upgrade.c @@ -3,7 +3,7 @@ * * main source file * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * src/bin/pg_upgrade/pg_upgrade.c */ diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h index 1842556274ffa..919a7849fd042 100644 --- a/src/bin/pg_upgrade/pg_upgrade.h +++ b/src/bin/pg_upgrade/pg_upgrade.h @@ -1,7 +1,7 @@ /* * pg_upgrade.h * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * src/bin/pg_upgrade/pg_upgrade.h */ diff --git a/src/bin/pg_upgrade/relfilenode.c b/src/bin/pg_upgrade/relfilenode.c index f76ddaaf3a161..4deae7d9858ba 100644 --- a/src/bin/pg_upgrade/relfilenode.c +++ b/src/bin/pg_upgrade/relfilenode.c @@ -3,7 +3,7 @@ * * relfilenode functions * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * src/bin/pg_upgrade/relfilenode.c */ diff --git a/src/bin/pg_upgrade/server.c b/src/bin/pg_upgrade/server.c index 713509f54062a..31b1425202915 100644 --- a/src/bin/pg_upgrade/server.c +++ b/src/bin/pg_upgrade/server.c @@ -3,7 +3,7 @@ * * database server functions * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * src/bin/pg_upgrade/server.c */ diff --git a/src/bin/pg_upgrade/tablespace.c b/src/bin/pg_upgrade/tablespace.c index 11a242973818c..bd49d300db111 100644 --- a/src/bin/pg_upgrade/tablespace.c +++ b/src/bin/pg_upgrade/tablespace.c @@ -3,7 +3,7 @@ * * tablespace functions * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * src/bin/pg_upgrade/tablespace.c */ diff --git a/src/bin/pg_upgrade/test.sh b/src/bin/pg_upgrade/test.sh index 47c96df5c303c..ca923ba01bc4d 100644 --- a/src/bin/pg_upgrade/test.sh +++ b/src/bin/pg_upgrade/test.sh @@ -6,7 +6,7 @@ # runs the regression tests (to put in some data), runs pg_dumpall, # runs pg_upgrade, runs pg_dumpall again, compares the dumps. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California set -e diff --git a/src/bin/pg_upgrade/util.c b/src/bin/pg_upgrade/util.c index 9c9ba29124e31..fc20472fe7b8c 100644 --- a/src/bin/pg_upgrade/util.c +++ b/src/bin/pg_upgrade/util.c @@ -3,7 +3,7 @@ * * utility functions * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * src/bin/pg_upgrade/util.c */ diff --git a/src/bin/pg_upgrade/version.c b/src/bin/pg_upgrade/version.c index db1934124ee35..a41247b33d2f6 100644 --- a/src/bin/pg_upgrade/version.c +++ b/src/bin/pg_upgrade/version.c @@ -3,7 +3,7 @@ * * Postgres-version-specific routines * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * src/bin/pg_upgrade/version.c */ diff --git a/src/bin/pg_verifybackup/parse_manifest.c b/src/bin/pg_verifybackup/parse_manifest.c index 5b4ce28837149..db2fa90cfec1f 100644 --- a/src/bin/pg_verifybackup/parse_manifest.c +++ b/src/bin/pg_verifybackup/parse_manifest.c @@ -3,7 +3,7 @@ * parse_manifest.c * Parse a backup manifest in JSON format. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/pg_verifybackup/parse_manifest.c diff --git a/src/bin/pg_verifybackup/parse_manifest.h b/src/bin/pg_verifybackup/parse_manifest.h index cbb7ca1397e6d..b0745a0a5928a 100644 --- a/src/bin/pg_verifybackup/parse_manifest.h +++ b/src/bin/pg_verifybackup/parse_manifest.h @@ -3,7 +3,7 @@ * parse_manifest.h * Parse a backup manifest in JSON format. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/pg_verifybackup/parse_manifest.h diff --git a/src/bin/pg_verifybackup/pg_verifybackup.c b/src/bin/pg_verifybackup/pg_verifybackup.c index bf388de79fa5d..bb3f2783d0c2e 100644 --- a/src/bin/pg_verifybackup/pg_verifybackup.c +++ b/src/bin/pg_verifybackup/pg_verifybackup.c @@ -3,7 +3,7 @@ * pg_verifybackup.c * Verify a backup against a backup manifest. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/pg_verifybackup/pg_verifybackup.c diff --git a/src/bin/pg_waldump/compat.c b/src/bin/pg_waldump/compat.c index 7cb0539e749c0..08bd62743dd27 100644 --- a/src/bin/pg_waldump/compat.c +++ b/src/bin/pg_waldump/compat.c @@ -3,7 +3,7 @@ * compat.c * Reimplementations of various backend functions. * - * Portions Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2013-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/bin/pg_waldump/compat.c diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c index 31e99c2a6da5d..164868d16efc1 100644 --- a/src/bin/pg_waldump/pg_waldump.c +++ b/src/bin/pg_waldump/pg_waldump.c @@ -2,7 +2,7 @@ * * pg_waldump.c - decode and display WAL * - * Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Copyright (c) 2013-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/bin/pg_waldump/pg_waldump.c diff --git a/src/bin/pgbench/exprparse.y b/src/bin/pgbench/exprparse.y index 85d61caa9f10d..4d529ea550010 100644 --- a/src/bin/pgbench/exprparse.y +++ b/src/bin/pgbench/exprparse.y @@ -4,7 +4,7 @@ * exprparse.y * bison grammar for a simple expression syntax * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/pgbench/exprparse.y diff --git a/src/bin/pgbench/exprscan.l b/src/bin/pgbench/exprscan.l index 430bff38a617d..75432cedc6530 100644 --- a/src/bin/pgbench/exprscan.l +++ b/src/bin/pgbench/exprscan.l @@ -15,7 +15,7 @@ * * Note that this lexer operates within the framework created by psqlscan.l, * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/pgbench/exprscan.l diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index 3057665bbec56..99b06a5e05038 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -5,7 +5,7 @@ * Originally written by Tatsuo Ishii and enhanced by many contributors. * * src/bin/pgbench/pgbench.c - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * ALL RIGHTS RESERVED; * * Permission to use, copy, modify, and distribute this software and its diff --git a/src/bin/pgbench/pgbench.h b/src/bin/pgbench/pgbench.h index fb2c34f512fb2..3a9d89e6f1509 100644 --- a/src/bin/pgbench/pgbench.h +++ b/src/bin/pgbench/pgbench.h @@ -2,7 +2,7 @@ * * pgbench.h * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * *------------------------------------------------------------------------- diff --git a/src/bin/pgevent/Makefile b/src/bin/pgevent/Makefile index 28c3078b01c0a..da69e91839d5a 100644 --- a/src/bin/pgevent/Makefile +++ b/src/bin/pgevent/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/bin/pgevent # -# Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Copyright (c) 1996-2021, PostgreSQL Global Development Group # #------------------------------------------------------------------------- diff --git a/src/bin/psql/Makefile b/src/bin/psql/Makefile index 2305d93e39cf7..d00881163c023 100644 --- a/src/bin/psql/Makefile +++ b/src/bin/psql/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/bin/psql # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/bin/psql/Makefile diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index c545341cddd01..303e7c3ad8b38 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/command.c */ diff --git a/src/bin/psql/command.h b/src/bin/psql/command.h index 006832f1022a9..0ff5b768db1a0 100644 --- a/src/bin/psql/command.h +++ b/src/bin/psql/command.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/command.h */ diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c index dfbc22970f831..6f507104f464f 100644 --- a/src/bin/psql/common.c +++ b/src/bin/psql/common.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/common.c */ diff --git a/src/bin/psql/common.h b/src/bin/psql/common.h index ec4e83c9fdf8a..041b2ac068a74 100644 --- a/src/bin/psql/common.h +++ b/src/bin/psql/common.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/common.h */ diff --git a/src/bin/psql/copy.c b/src/bin/psql/copy.c index f59db8d7bd080..78f0dc5a507af 100644 --- a/src/bin/psql/copy.c +++ b/src/bin/psql/copy.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/copy.c */ diff --git a/src/bin/psql/copy.h b/src/bin/psql/copy.h index b2daf91851282..5923da8698433 100644 --- a/src/bin/psql/copy.h +++ b/src/bin/psql/copy.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/copy.h */ diff --git a/src/bin/psql/create_help.pl b/src/bin/psql/create_help.pl index 60e093bad4902..83324239740b0 100644 --- a/src/bin/psql/create_help.pl +++ b/src/bin/psql/create_help.pl @@ -3,7 +3,7 @@ ################################################################# # create_help.pl -- converts SGML docs to internal psql help # -# Copyright (c) 2000-2020, PostgreSQL Global Development Group +# Copyright (c) 2000-2021, PostgreSQL Global Development Group # # src/bin/psql/create_help.pl ################################################################# diff --git a/src/bin/psql/crosstabview.c b/src/bin/psql/crosstabview.c index f06cb068c90b5..97515f0d4a0bf 100644 --- a/src/bin/psql/crosstabview.c +++ b/src/bin/psql/crosstabview.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/crosstabview.c */ diff --git a/src/bin/psql/crosstabview.h b/src/bin/psql/crosstabview.h index 096e76b622491..53d0e4182ba95 100644 --- a/src/bin/psql/crosstabview.h +++ b/src/bin/psql/crosstabview.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/crosstabview.h */ diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index 14150d05a988d..52c6de51b62d5 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -6,7 +6,7 @@ * with servers of versions 7.4 and up. It's okay to omit irrelevant * information for an old server, but not to fail outright. * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/describe.c */ diff --git a/src/bin/psql/describe.h b/src/bin/psql/describe.h index f0e3ec957c055..6044e3a08284a 100644 --- a/src/bin/psql/describe.h +++ b/src/bin/psql/describe.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/describe.h */ diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index af829282e6031..9ec1c4e810c74 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/help.c */ @@ -671,7 +671,7 @@ print_copyright(void) { puts("PostgreSQL Database Management System\n" "(formerly known as Postgres, then as Postgres95)\n\n" - "Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group\n\n" + "Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group\n\n" "Portions Copyright (c) 1994, The Regents of the University of California\n\n" "Permission to use, copy, modify, and distribute this software and its\n" "documentation for any purpose, without fee, and without a written agreement\n" diff --git a/src/bin/psql/help.h b/src/bin/psql/help.h index 2e2666d3d0e8d..d4f91e0be2bf6 100644 --- a/src/bin/psql/help.h +++ b/src/bin/psql/help.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/help.h */ diff --git a/src/bin/psql/input.c b/src/bin/psql/input.c index 788ff1f9b7b07..f926bc98dc208 100644 --- a/src/bin/psql/input.c +++ b/src/bin/psql/input.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/input.c */ diff --git a/src/bin/psql/input.h b/src/bin/psql/input.h index cfa03f59ea731..1a5a1be999e19 100644 --- a/src/bin/psql/input.h +++ b/src/bin/psql/input.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/input.h */ diff --git a/src/bin/psql/large_obj.c b/src/bin/psql/large_obj.c index cae81c0f15222..c15fcc08851d5 100644 --- a/src/bin/psql/large_obj.c +++ b/src/bin/psql/large_obj.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/large_obj.c */ diff --git a/src/bin/psql/large_obj.h b/src/bin/psql/large_obj.h index 755b9e70f0dff..003acbf52c9d8 100644 --- a/src/bin/psql/large_obj.h +++ b/src/bin/psql/large_obj.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/large_obj.h */ diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c index 7abe016e40382..e49ed022938b1 100644 --- a/src/bin/psql/mainloop.c +++ b/src/bin/psql/mainloop.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/mainloop.c */ diff --git a/src/bin/psql/mainloop.h b/src/bin/psql/mainloop.h index d9680d45b18df..dd7a1889dee46 100644 --- a/src/bin/psql/mainloop.h +++ b/src/bin/psql/mainloop.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/mainloop.h */ diff --git a/src/bin/psql/prompt.c b/src/bin/psql/prompt.c index f42c3dfc7488d..9f236049f000a 100644 --- a/src/bin/psql/prompt.c +++ b/src/bin/psql/prompt.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/prompt.c */ diff --git a/src/bin/psql/prompt.h b/src/bin/psql/prompt.h index 3c8666918cdc7..ad6646d99b68c 100644 --- a/src/bin/psql/prompt.h +++ b/src/bin/psql/prompt.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/prompt.h */ diff --git a/src/bin/psql/psqlscanslash.h b/src/bin/psql/psqlscanslash.h index 7210e49240795..074e961e18c41 100644 --- a/src/bin/psql/psqlscanslash.h +++ b/src/bin/psql/psqlscanslash.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/psqlscanslash.h */ diff --git a/src/bin/psql/psqlscanslash.l b/src/bin/psql/psqlscanslash.l index 4dff84d6271a8..4bb18f132f4f4 100644 --- a/src/bin/psql/psqlscanslash.l +++ b/src/bin/psql/psqlscanslash.l @@ -8,7 +8,7 @@ * * See fe_utils/psqlscan_int.h for additional commentary. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h index 9601f6e90ce89..d65990059d978 100644 --- a/src/bin/psql/settings.h +++ b/src/bin/psql/settings.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/settings.h */ diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c index 586fcb33661cd..780479c8d7698 100644 --- a/src/bin/psql/startup.c +++ b/src/bin/psql/startup.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/startup.c */ diff --git a/src/bin/psql/stringutils.c b/src/bin/psql/stringutils.c index c521749661c30..0acc53801cb4a 100644 --- a/src/bin/psql/stringutils.c +++ b/src/bin/psql/stringutils.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/stringutils.c */ diff --git a/src/bin/psql/stringutils.h b/src/bin/psql/stringutils.h index 4be172e031f9c..b47425e8644c3 100644 --- a/src/bin/psql/stringutils.h +++ b/src/bin/psql/stringutils.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/stringutils.h */ diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 3a43c09bf6807..9dcab0d2fa415 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/tab-complete.c */ diff --git a/src/bin/psql/tab-complete.h b/src/bin/psql/tab-complete.h index 7083186525cab..4c308cfabdde1 100644 --- a/src/bin/psql/tab-complete.h +++ b/src/bin/psql/tab-complete.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/tab-complete.h */ diff --git a/src/bin/psql/variables.c b/src/bin/psql/variables.c index 84349fc753f02..92a34f870fd22 100644 --- a/src/bin/psql/variables.c +++ b/src/bin/psql/variables.c @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/bin/psql/variables.c */ diff --git a/src/bin/psql/variables.h b/src/bin/psql/variables.h index b932472021a74..12ae3c02f92f0 100644 --- a/src/bin/psql/variables.h +++ b/src/bin/psql/variables.h @@ -1,7 +1,7 @@ /* * psql - the PostgreSQL interactive terminal * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * This implements a sort of variable repository. One could also think of it * as a cheap version of an associative array. Each variable has a string diff --git a/src/bin/scripts/Makefile b/src/bin/scripts/Makefile index 42bfe475b2ebb..a02e4e430c87b 100644 --- a/src/bin/scripts/Makefile +++ b/src/bin/scripts/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/bin/scripts # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/bin/scripts/Makefile diff --git a/src/bin/scripts/clusterdb.c b/src/bin/scripts/clusterdb.c index 2f786e61037be..7d25bb31d4e35 100644 --- a/src/bin/scripts/clusterdb.c +++ b/src/bin/scripts/clusterdb.c @@ -2,7 +2,7 @@ * * clusterdb * - * Portions Copyright (c) 2002-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2002-2021, PostgreSQL Global Development Group * * src/bin/scripts/clusterdb.c * diff --git a/src/bin/scripts/common.c b/src/bin/scripts/common.c index 3362221a31149..13ac531695064 100644 --- a/src/bin/scripts/common.c +++ b/src/bin/scripts/common.c @@ -4,7 +4,7 @@ * Common support routines for bin/scripts/ * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/scripts/common.c diff --git a/src/bin/scripts/common.h b/src/bin/scripts/common.h index 9ec57cdd87c0e..5630975712416 100644 --- a/src/bin/scripts/common.h +++ b/src/bin/scripts/common.h @@ -2,7 +2,7 @@ * common.h * Common support routines for bin/scripts/ * - * Copyright (c) 2003-2020, PostgreSQL Global Development Group + * Copyright (c) 2003-2021, PostgreSQL Global Development Group * * src/bin/scripts/common.h */ diff --git a/src/bin/scripts/createdb.c b/src/bin/scripts/createdb.c index 91e6e2194bd77..abf21d4942867 100644 --- a/src/bin/scripts/createdb.c +++ b/src/bin/scripts/createdb.c @@ -2,7 +2,7 @@ * * createdb * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/scripts/createdb.c diff --git a/src/bin/scripts/createuser.c b/src/bin/scripts/createuser.c index d6b56f15c3b66..47b0e28bc6755 100644 --- a/src/bin/scripts/createuser.c +++ b/src/bin/scripts/createuser.c @@ -2,7 +2,7 @@ * * createuser * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/scripts/createuser.c diff --git a/src/bin/scripts/dropdb.c b/src/bin/scripts/dropdb.c index ccbf78e91a864..ba0dcdecb95f5 100644 --- a/src/bin/scripts/dropdb.c +++ b/src/bin/scripts/dropdb.c @@ -2,7 +2,7 @@ * * dropdb * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/scripts/dropdb.c diff --git a/src/bin/scripts/dropuser.c b/src/bin/scripts/dropuser.c index 73d7328a88d58..ff5b455ae5119 100644 --- a/src/bin/scripts/dropuser.c +++ b/src/bin/scripts/dropuser.c @@ -2,7 +2,7 @@ * * dropuser * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/scripts/dropuser.c diff --git a/src/bin/scripts/pg_isready.c b/src/bin/scripts/pg_isready.c index f397112906468..ceb8a09b4c5b4 100644 --- a/src/bin/scripts/pg_isready.c +++ b/src/bin/scripts/pg_isready.c @@ -2,7 +2,7 @@ * * pg_isready --- checks the status of the PostgreSQL server * - * Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Copyright (c) 2013-2021, PostgreSQL Global Development Group * * src/bin/scripts/pg_isready.c * diff --git a/src/bin/scripts/reindexdb.c b/src/bin/scripts/reindexdb.c index b32a7746baf42..dece8200fa2d2 100644 --- a/src/bin/scripts/reindexdb.c +++ b/src/bin/scripts/reindexdb.c @@ -2,7 +2,7 @@ * * reindexdb * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * src/bin/scripts/reindexdb.c * diff --git a/src/bin/scripts/scripts_parallel.c b/src/bin/scripts/scripts_parallel.c index ec264a269a7d7..1f863a1bb4616 100644 --- a/src/bin/scripts/scripts_parallel.c +++ b/src/bin/scripts/scripts_parallel.c @@ -4,7 +4,7 @@ * Parallel support for bin/scripts/ * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/scripts/scripts_parallel.c diff --git a/src/bin/scripts/scripts_parallel.h b/src/bin/scripts/scripts_parallel.h index c9d9f0623e949..f62692510a8a4 100644 --- a/src/bin/scripts/scripts_parallel.h +++ b/src/bin/scripts/scripts_parallel.h @@ -3,7 +3,7 @@ * scripts_parallel.h * Parallel support for bin/scripts/ * - * Copyright (c) 2003-2020, PostgreSQL Global Development Group + * Copyright (c) 2003-2021, PostgreSQL Global Development Group * * src/bin/scripts/scripts_parallel.h * diff --git a/src/bin/scripts/vacuumdb.c b/src/bin/scripts/vacuumdb.c index 8c2eade1d5d2e..82463277702aa 100644 --- a/src/bin/scripts/vacuumdb.c +++ b/src/bin/scripts/vacuumdb.c @@ -2,7 +2,7 @@ * * vacuumdb * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/bin/scripts/vacuumdb.c diff --git a/src/common/archive.c b/src/common/archive.c index a94e4d0a5eb33..d733212cc4f63 100644 --- a/src/common/archive.c +++ b/src/common/archive.c @@ -3,7 +3,7 @@ * archive.c * Common WAL archive routines * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/common/base64.c b/src/common/base64.c index 5ba59375d531f..b3ade2a5a5d7d 100644 --- a/src/common/base64.c +++ b/src/common/base64.c @@ -3,7 +3,7 @@ * base64.c * Encoding and decoding routines for base64 without whitespace. * - * Copyright (c) 2001-2020, PostgreSQL Global Development Group + * Copyright (c) 2001-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/common/checksum_helper.c b/src/common/checksum_helper.c index 8e06524cd3c7a..f6b49de405e5e 100644 --- a/src/common/checksum_helper.c +++ b/src/common/checksum_helper.c @@ -3,7 +3,7 @@ * checksum_helper.c * Compute a checksum of any of various types using common routines * - * Portions Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2016-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/common/checksum_helper.c diff --git a/src/common/config_info.c b/src/common/config_info.c index 8a5dc64ec361a..e72e7292a0a87 100644 --- a/src/common/config_info.c +++ b/src/common/config_info.c @@ -4,7 +4,7 @@ * Common code for pg_config output * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/common/controldata_utils.c b/src/common/controldata_utils.c index 3d53b6ac0781d..7d4af7881ea50 100644 --- a/src/common/controldata_utils.c +++ b/src/common/controldata_utils.c @@ -4,7 +4,7 @@ * Common code for control data file output. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/common/cryptohash.c b/src/common/cryptohash.c index cf4588bad72ae..1921a33b34e41 100644 --- a/src/common/cryptohash.c +++ b/src/common/cryptohash.c @@ -6,7 +6,7 @@ * This is the set of in-core functions used when there are no other * alternative options like OpenSSL. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/common/cryptohash_openssl.c b/src/common/cryptohash_openssl.c index 118651c4153b1..0fd6622576446 100644 --- a/src/common/cryptohash_openssl.c +++ b/src/common/cryptohash_openssl.c @@ -6,7 +6,7 @@ * * This should only be used if code is compiled with OpenSSL support. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/common/d2s.c b/src/common/d2s.c index 8b0b7cee2f8be..70e3112adb9d3 100644 --- a/src/common/d2s.c +++ b/src/common/d2s.c @@ -2,7 +2,7 @@ * * Ryu floating-point output for double precision. * - * Portions Copyright (c) 2018-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2018-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/common/d2s.c diff --git a/src/common/d2s_full_table.h b/src/common/d2s_full_table.h index 23fd71553df9a..70b4419f0542f 100644 --- a/src/common/d2s_full_table.h +++ b/src/common/d2s_full_table.h @@ -2,7 +2,7 @@ * * Ryu floating-point output for double precision. * - * Portions Copyright (c) 2018-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2018-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/common/d2s_full_table.h diff --git a/src/common/d2s_intrinsics.h b/src/common/d2s_intrinsics.h index b1f31ca400daa..3be23271988e3 100644 --- a/src/common/d2s_intrinsics.h +++ b/src/common/d2s_intrinsics.h @@ -2,7 +2,7 @@ * * Ryu floating-point output for double precision. * - * Portions Copyright (c) 2018-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2018-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/common/d2s_intrinsics.h diff --git a/src/common/encnames.c b/src/common/encnames.c index 14cf1b39e9866..f2aaeb4a8e5c8 100644 --- a/src/common/encnames.c +++ b/src/common/encnames.c @@ -3,7 +3,7 @@ * encnames.c * Encoding names and routines for working with them. * - * Portions Copyright (c) 2001-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2001-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/common/encnames.c diff --git a/src/common/exec.c b/src/common/exec.c index 773afd080c05a..6cbc8200421c8 100644 --- a/src/common/exec.c +++ b/src/common/exec.c @@ -4,7 +4,7 @@ * Functions for finding and validating executable files * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/common/f2s.c b/src/common/f2s.c index 463d19237846f..6a9949eb0877d 100644 --- a/src/common/f2s.c +++ b/src/common/f2s.c @@ -2,7 +2,7 @@ * * Ryu floating-point output for single precision. * - * Portions Copyright (c) 2018-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2018-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/common/f2s.c diff --git a/src/common/fe_memutils.c b/src/common/fe_memutils.c index b027a025d1574..ec64172a59ccb 100644 --- a/src/common/fe_memutils.c +++ b/src/common/fe_memutils.c @@ -3,7 +3,7 @@ * fe_memutils.c * memory management support for frontend code * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/common/file_perm.c b/src/common/file_perm.c index 96b44dcc4d339..ab85765a0bfb5 100644 --- a/src/common/file_perm.c +++ b/src/common/file_perm.c @@ -3,7 +3,7 @@ * File and directory permission routines * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/common/file_perm.c diff --git a/src/common/file_utils.c b/src/common/file_utils.c index 12474730905ca..40b73bbe1abb0 100644 --- a/src/common/file_utils.c +++ b/src/common/file_utils.c @@ -5,7 +5,7 @@ * Assorted utility functions to work on files. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/common/file_utils.c diff --git a/src/common/hashfn.c b/src/common/hashfn.c index 990f18e610b8c..902a6ad25e887 100644 --- a/src/common/hashfn.c +++ b/src/common/hashfn.c @@ -5,7 +5,7 @@ * hashtables * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/common/hex_decode.c b/src/common/hex_decode.c index 3ecdc73b5cd4f..dbc0e1c30aa6a 100644 --- a/src/common/hex_decode.c +++ b/src/common/hex_decode.c @@ -4,7 +4,7 @@ * hex decoding * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/common/ip.c b/src/common/ip.c index bcc779e00c313..9b611d86cd4e5 100644 --- a/src/common/ip.c +++ b/src/common/ip.c @@ -3,7 +3,7 @@ * ip.c * IPv6-aware network access. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/common/jsonapi.c b/src/common/jsonapi.c index 9326f805366dd..831a44a2da632 100644 --- a/src/common/jsonapi.c +++ b/src/common/jsonapi.c @@ -3,7 +3,7 @@ * jsonapi.c * JSON parser and lexer interfaces * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/common/keywords.c b/src/common/keywords.c index 2de0c717a8912..d8497f7c172b2 100644 --- a/src/common/keywords.c +++ b/src/common/keywords.c @@ -4,7 +4,7 @@ * PostgreSQL's list of SQL keywords * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/common/kwlookup.c b/src/common/kwlookup.c index 11c49a127575c..19a4f52c79fb1 100644 --- a/src/common/kwlookup.c +++ b/src/common/kwlookup.c @@ -4,7 +4,7 @@ * Key word lookup for PostgreSQL * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/common/link-canary.c b/src/common/link-canary.c index 28c6ae73f8a3a..5933b8e5cd613 100644 --- a/src/common/link-canary.c +++ b/src/common/link-canary.c @@ -2,7 +2,7 @@ * link-canary.c * Detect whether src/common functions came from frontend or backend. * - * Copyright (c) 2018-2020, PostgreSQL Global Development Group + * Copyright (c) 2018-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/common/link-canary.c diff --git a/src/common/logging.c b/src/common/logging.c index d9632fffc8ad1..fb1a9b1f878fd 100644 --- a/src/common/logging.c +++ b/src/common/logging.c @@ -1,7 +1,7 @@ /*------------------------------------------------------------------------- * Logging framework for frontend programs * - * Copyright (c) 2018-2020, PostgreSQL Global Development Group + * Copyright (c) 2018-2021, PostgreSQL Global Development Group * * src/common/logging.c * diff --git a/src/common/md5.c b/src/common/md5.c index ab761560944f4..7d3b639f29d95 100644 --- a/src/common/md5.c +++ b/src/common/md5.c @@ -7,7 +7,7 @@ * implementation is a simple one, in that it needs every input byte * to be buffered before doing any calculations. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/common/md5_common.c b/src/common/md5_common.c index abf79e5918f76..b01c95ebb6e53 100644 --- a/src/common/md5_common.c +++ b/src/common/md5_common.c @@ -6,7 +6,7 @@ * * Sverre H. Huseby * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/common/md5_int.h b/src/common/md5_int.h index b5b71e2582f1a..4ce7f7dea412e 100644 --- a/src/common/md5_int.h +++ b/src/common/md5_int.h @@ -3,7 +3,7 @@ * md5_int.h * Internal headers for fallback implementation of MD5 * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/common/pg_get_line.c b/src/common/pg_get_line.c index 9eb1a33bbb366..a80d196156d6f 100644 --- a/src/common/pg_get_line.c +++ b/src/common/pg_get_line.c @@ -3,7 +3,7 @@ * pg_get_line.c * fgets() with an expansible result buffer * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/common/pg_lzcompress.c b/src/common/pg_lzcompress.c index f9c29820e30bd..fdd527f757aba 100644 --- a/src/common/pg_lzcompress.c +++ b/src/common/pg_lzcompress.c @@ -172,7 +172,7 @@ * * Jan Wieck * - * Copyright (c) 1999-2020, PostgreSQL Global Development Group + * Copyright (c) 1999-2021, PostgreSQL Global Development Group * * src/common/pg_lzcompress.c * ---------- diff --git a/src/common/pgfnames.c b/src/common/pgfnames.c index c12f25697d16e..395927c94d9fd 100644 --- a/src/common/pgfnames.c +++ b/src/common/pgfnames.c @@ -3,7 +3,7 @@ * pgfnames.c * directory handling functions * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/common/protocol_openssl.c b/src/common/protocol_openssl.c index bf6c62410dad7..92a0a22ecfb00 100644 --- a/src/common/protocol_openssl.c +++ b/src/common/protocol_openssl.c @@ -5,7 +5,7 @@ * * This should only be used if code is compiled with OpenSSL support. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/common/psprintf.c b/src/common/psprintf.c index 4d9d15e6ad039..52223c38a450a 100644 --- a/src/common/psprintf.c +++ b/src/common/psprintf.c @@ -4,7 +4,7 @@ * sprintf into an allocated-on-demand buffer * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/common/relpath.c b/src/common/relpath.c index ad733d1363559..1f5c426ec0b90 100644 --- a/src/common/relpath.c +++ b/src/common/relpath.c @@ -4,7 +4,7 @@ * * This module also contains some logic associated with fork names. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/common/restricted_token.c b/src/common/restricted_token.c index 9058c5ad252ea..667040d734c3a 100644 --- a/src/common/restricted_token.c +++ b/src/common/restricted_token.c @@ -4,7 +4,7 @@ * helper routine to ensure restricted token on Windows * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/common/rmtree.c b/src/common/rmtree.c index 9e8eb9e73602a..e090a85f135a6 100644 --- a/src/common/rmtree.c +++ b/src/common/rmtree.c @@ -2,7 +2,7 @@ * * rmtree.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/common/ryu_common.h b/src/common/ryu_common.h index 2e3213d1a10bb..34b1e36ec64e5 100644 --- a/src/common/ryu_common.h +++ b/src/common/ryu_common.h @@ -2,7 +2,7 @@ * * Common routines for Ryu floating-point output. * - * Portions Copyright (c) 2018-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2018-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/common/ryu_common.h diff --git a/src/common/saslprep.c b/src/common/saslprep.c index 48eb1ee9bb987..8945050ad251f 100644 --- a/src/common/saslprep.c +++ b/src/common/saslprep.c @@ -12,7 +12,7 @@ * http://www.ietf.org/rfc/rfc4013.txt * * - * Portions Copyright (c) 2017-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2017-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/common/saslprep.c diff --git a/src/common/scram-common.c b/src/common/scram-common.c index caab68926d292..3f406d4e4dc65 100644 --- a/src/common/scram-common.c +++ b/src/common/scram-common.c @@ -6,7 +6,7 @@ * backend, for implement the Salted Challenge Response Authentication * Mechanism (SCRAM), per IETF's RFC 5802. * - * Portions Copyright (c) 2017-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2017-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/common/scram-common.c diff --git a/src/common/sha2.c b/src/common/sha2.c index 1a462accc51f8..ae4936b1a8a06 100644 --- a/src/common/sha2.c +++ b/src/common/sha2.c @@ -6,7 +6,7 @@ * This includes the fallback implementation for SHA2 cryptographic * hashes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/common/sha2_int.h b/src/common/sha2_int.h index 96db773f969b8..c6d56423d98b9 100644 --- a/src/common/sha2_int.h +++ b/src/common/sha2_int.h @@ -3,7 +3,7 @@ * sha2_int.h * Internal headers for fallback implementation of SHA{224,256,384,512} * - * Portions Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2016-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/common/sha2_int.h diff --git a/src/common/sprompt.c b/src/common/sprompt.c index 0ec75da5bfe68..f3a891a260ba3 100644 --- a/src/common/sprompt.c +++ b/src/common/sprompt.c @@ -3,7 +3,7 @@ * sprompt.c * simple_prompt() routine * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/common/string.c b/src/common/string.c index 3e76e2c59fb84..3aa378c05194d 100644 --- a/src/common/string.c +++ b/src/common/string.c @@ -4,7 +4,7 @@ * string handling helpers * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/common/stringinfo.c b/src/common/stringinfo.c index 0badc465545c7..445f7222be0a2 100644 --- a/src/common/stringinfo.c +++ b/src/common/stringinfo.c @@ -7,7 +7,7 @@ * (null-terminated text) or arbitrary binary data. All storage is allocated * with palloc() (falling back to malloc in frontend code). * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/common/stringinfo.c diff --git a/src/common/unicode/generate-norm_test_table.pl b/src/common/unicode/generate-norm_test_table.pl index acc67967b7bd9..844ff0848b383 100644 --- a/src/common/unicode/generate-norm_test_table.pl +++ b/src/common/unicode/generate-norm_test_table.pl @@ -5,7 +5,7 @@ # # NormalizationTest.txt is part of the Unicode Character Database. # -# Copyright (c) 2000-2020, PostgreSQL Global Development Group +# Copyright (c) 2000-2021, PostgreSQL Global Development Group use strict; use warnings; @@ -30,7 +30,7 @@ * norm_test_table.h * Test strings for Unicode normalization. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/common/unicode/norm_test_table.h diff --git a/src/common/unicode/generate-unicode_combining_table.pl b/src/common/unicode/generate-unicode_combining_table.pl index c0fc3cc225950..86aed7890708b 100644 --- a/src/common/unicode/generate-unicode_combining_table.pl +++ b/src/common/unicode/generate-unicode_combining_table.pl @@ -4,7 +4,7 @@ # characters, using Unicode data files as input. Pass UnicodeData.txt # as argument. The output is on stdout. # -# Copyright (c) 2019, PostgreSQL Global Development Group +# Copyright (c) 2019-2021, PostgreSQL Global Development Group use strict; use warnings; diff --git a/src/common/unicode/generate-unicode_norm_table.pl b/src/common/unicode/generate-unicode_norm_table.pl index 8213532ab9dd3..114ab30d3f1db 100644 --- a/src/common/unicode/generate-unicode_norm_table.pl +++ b/src/common/unicode/generate-unicode_norm_table.pl @@ -6,7 +6,7 @@ # Input: UnicodeData.txt and CompositionExclusions.txt # Output: unicode_norm_table.h and unicode_norm_hashfunc.h # -# Copyright (c) 2000-2020, PostgreSQL Global Development Group +# Copyright (c) 2000-2021, PostgreSQL Global Development Group use strict; use warnings; @@ -82,7 +82,7 @@ * unicode_norm_table.h * Composition table used for Unicode normalization * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/common/unicode_norm_table.h @@ -125,7 +125,7 @@ * unicode_norm_hashfunc.h * Perfect hash functions used for Unicode normalization * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/common/unicode_norm_hashfunc.h diff --git a/src/common/unicode/generate-unicode_normprops_table.pl b/src/common/unicode/generate-unicode_normprops_table.pl index d652b95965dc7..c7795d17b0cca 100644 --- a/src/common/unicode/generate-unicode_normprops_table.pl +++ b/src/common/unicode/generate-unicode_normprops_table.pl @@ -4,7 +4,7 @@ # (see UAX #15). Pass DerivedNormalizationProps.txt as argument. The # output is on stdout. # -# Copyright (c) 2020, PostgreSQL Global Development Group +# Copyright (c) 2020-2021, PostgreSQL Global Development Group use strict; use warnings; diff --git a/src/common/unicode/norm_test.c b/src/common/unicode/norm_test.c index dde5d24349f9f..cd2cb297b0a4e 100644 --- a/src/common/unicode/norm_test.c +++ b/src/common/unicode/norm_test.c @@ -2,7 +2,7 @@ * norm_test.c * Program to test Unicode normalization functions. * - * Portions Copyright (c) 2017-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2017-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/common/unicode/norm_test.c diff --git a/src/common/unicode_norm.c b/src/common/unicode_norm.c index fd7bdef29280f..36ff2aab218ea 100644 --- a/src/common/unicode_norm.c +++ b/src/common/unicode_norm.c @@ -5,7 +5,7 @@ * This implements Unicode normalization, per the documentation at * https://www.unicode.org/reports/tr15/. * - * Portions Copyright (c) 2017-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2017-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/common/unicode_norm.c diff --git a/src/common/username.c b/src/common/username.c index 5d47774c4f115..669b8ab3b278f 100644 --- a/src/common/username.c +++ b/src/common/username.c @@ -3,7 +3,7 @@ * username.c * get user name * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/common/wait_error.c b/src/common/wait_error.c index 2026280584502..9f860eef3801a 100644 --- a/src/common/wait_error.c +++ b/src/common/wait_error.c @@ -4,7 +4,7 @@ * Convert a wait/waitpid(2) result code to a human-readable string * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/common/wchar.c b/src/common/wchar.c index efaf1c155bbde..0d6d071658d59 100644 --- a/src/common/wchar.c +++ b/src/common/wchar.c @@ -3,7 +3,7 @@ * wchar.c * Functions for working with multibyte characters in various encodings. * - * Portions Copyright (c) 1998-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1998-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/common/wchar.c diff --git a/src/fe_utils/Makefile b/src/fe_utils/Makefile index dd2066360474b..10d6838cf96a1 100644 --- a/src/fe_utils/Makefile +++ b/src/fe_utils/Makefile @@ -5,7 +5,7 @@ # This makefile generates a static library, libpgfeutils.a, # for use by client applications # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # IDENTIFICATION diff --git a/src/fe_utils/archive.c b/src/fe_utils/archive.c index 252dc0fb6a5d8..8baef5f078ce0 100644 --- a/src/fe_utils/archive.c +++ b/src/fe_utils/archive.c @@ -3,7 +3,7 @@ * archive.c * Routines to access WAL archives from frontend * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/fe_utils/cancel.c b/src/fe_utils/cancel.c index 0a385647df89a..14f939105ac84 100644 --- a/src/fe_utils/cancel.c +++ b/src/fe_utils/cancel.c @@ -6,7 +6,7 @@ * handler for SIGINT. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/fe-utils/cancel.c diff --git a/src/fe_utils/conditional.c b/src/fe_utils/conditional.c index 4df72d4f4d1f4..a562e28846b2a 100644 --- a/src/fe_utils/conditional.c +++ b/src/fe_utils/conditional.c @@ -1,7 +1,7 @@ /*------------------------------------------------------------------------- * A stack of automaton states to handle nested conditionals. * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/fe_utils/conditional.c * diff --git a/src/fe_utils/mbprint.c b/src/fe_utils/mbprint.c index 5f79cbf1c9823..fe3faba46f290 100644 --- a/src/fe_utils/mbprint.c +++ b/src/fe_utils/mbprint.c @@ -3,7 +3,7 @@ * Multibyte character printing support for frontend code * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/fe_utils/mbprint.c diff --git a/src/fe_utils/print.c b/src/fe_utils/print.c index d542792230f88..e8772a278c306 100644 --- a/src/fe_utils/print.c +++ b/src/fe_utils/print.c @@ -8,7 +8,7 @@ * pager open/close functions, all that stuff came with it. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/fe_utils/print.c diff --git a/src/fe_utils/psqlscan.l b/src/fe_utils/psqlscan.l index 08dffde1ba0f2..216ff30993f70 100644 --- a/src/fe_utils/psqlscan.l +++ b/src/fe_utils/psqlscan.l @@ -24,7 +24,7 @@ * See psqlscan_int.h for additional commentary. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/fe_utils/recovery_gen.c b/src/fe_utils/recovery_gen.c index 46ca20e20b80b..2643ecd6f3f91 100644 --- a/src/fe_utils/recovery_gen.c +++ b/src/fe_utils/recovery_gen.c @@ -3,7 +3,7 @@ * recovery_gen.c * Generator for recovery configuration * - * Portions Copyright (c) 2011-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2011-2021, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/fe_utils/simple_list.c b/src/fe_utils/simple_list.c index 5294fba8bb341..5c0ca00438639 100644 --- a/src/fe_utils/simple_list.c +++ b/src/fe_utils/simple_list.c @@ -7,7 +7,7 @@ * it's all we need in, eg, pg_dump. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/fe_utils/simple_list.c diff --git a/src/fe_utils/string_utils.c b/src/fe_utils/string_utils.c index b4bba26934bdb..a1a9d691d5b27 100644 --- a/src/fe_utils/string_utils.c +++ b/src/fe_utils/string_utils.c @@ -6,7 +6,7 @@ * and interpreting backend output. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/fe_utils/string_utils.c diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h index 85b4766016f89..de758cab0bde4 100644 --- a/src/include/access/amapi.h +++ b/src/include/access/amapi.h @@ -3,7 +3,7 @@ * amapi.h * API for Postgres index access methods. * - * Copyright (c) 2015-2020, PostgreSQL Global Development Group + * Copyright (c) 2015-2021, PostgreSQL Global Development Group * * src/include/access/amapi.h * diff --git a/src/include/access/amvalidate.h b/src/include/access/amvalidate.h index 149fc75f85698..df02fbac2382c 100644 --- a/src/include/access/amvalidate.h +++ b/src/include/access/amvalidate.h @@ -4,7 +4,7 @@ * Support routines for index access methods' amvalidate and * amadjustmembers functions. * - * Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Copyright (c) 2016-2021, PostgreSQL Global Development Group * * src/include/access/amvalidate.h * diff --git a/src/include/access/attmap.h b/src/include/access/attmap.h index 64bc7158a9717..778fa27fd163b 100644 --- a/src/include/access/attmap.h +++ b/src/include/access/attmap.h @@ -4,7 +4,7 @@ * Definitions for PostgreSQL attribute mappings * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/attmap.h diff --git a/src/include/access/attnum.h b/src/include/access/attnum.h index 87b208e0d7a87..0c43e26c2d619 100644 --- a/src/include/access/attnum.h +++ b/src/include/access/attnum.h @@ -4,7 +4,7 @@ * POSTGRES attribute number definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/attnum.h diff --git a/src/include/access/brin.h b/src/include/access/brin.h index 0987878dd2a6b..4e2be13cd6165 100644 --- a/src/include/access/brin.h +++ b/src/include/access/brin.h @@ -1,7 +1,7 @@ /* * AM-callable functions for BRIN indexes * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/access/brin_internal.h b/src/include/access/brin_internal.h index 9ffc9100c0b70..85c612e4902c5 100644 --- a/src/include/access/brin_internal.h +++ b/src/include/access/brin_internal.h @@ -2,7 +2,7 @@ * brin_internal.h * internal declarations for BRIN indexes * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/access/brin_page.h b/src/include/access/brin_page.h index 77c2ac7f95495..75de538ed870f 100644 --- a/src/include/access/brin_page.h +++ b/src/include/access/brin_page.h @@ -2,7 +2,7 @@ * brin_page.h * Prototypes and definitions for BRIN page layouts * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/access/brin_pageops.h b/src/include/access/brin_pageops.h index f2029880392ad..c2e8a2a6c267c 100644 --- a/src/include/access/brin_pageops.h +++ b/src/include/access/brin_pageops.h @@ -2,7 +2,7 @@ * brin_pageops.h * Prototypes for operating on BRIN pages. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/access/brin_revmap.h b/src/include/access/brin_revmap.h index 4a31d43636002..4259fe81fe989 100644 --- a/src/include/access/brin_revmap.h +++ b/src/include/access/brin_revmap.h @@ -2,7 +2,7 @@ * brin_revmap.h * Prototypes for BRIN reverse range maps * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/access/brin_tuple.h b/src/include/access/brin_tuple.h index a9ccc3995b44a..5715bd58df74c 100644 --- a/src/include/access/brin_tuple.h +++ b/src/include/access/brin_tuple.h @@ -2,7 +2,7 @@ * brin_tuple.h * Declarations for dealing with BRIN-specific tuples. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/access/brin_xlog.h b/src/include/access/brin_xlog.h index ecccebdbe7680..ace8aa0dcdcf5 100644 --- a/src/include/access/brin_xlog.h +++ b/src/include/access/brin_xlog.h @@ -4,7 +4,7 @@ * POSTGRES BRIN access XLOG definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/brin_xlog.h diff --git a/src/include/access/bufmask.h b/src/include/access/bufmask.h index d86064c7c98d6..add6c9a39cf6c 100644 --- a/src/include/access/bufmask.h +++ b/src/include/access/bufmask.h @@ -7,7 +7,7 @@ * individual rmgr, but we make things easier by providing some * common routines to handle cases which occur in multiple rmgrs. * - * Portions Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2016-2021, PostgreSQL Global Development Group * * src/include/access/bufmask.h * diff --git a/src/include/access/clog.h b/src/include/access/clog.h index 6c840cbf299b3..e3329de10b977 100644 --- a/src/include/access/clog.h +++ b/src/include/access/clog.h @@ -3,7 +3,7 @@ * * PostgreSQL transaction-commit-log manager * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/clog.h diff --git a/src/include/access/commit_ts.h b/src/include/access/commit_ts.h index 2d1724952257a..61f1c9aa2fd0d 100644 --- a/src/include/access/commit_ts.h +++ b/src/include/access/commit_ts.h @@ -3,7 +3,7 @@ * * PostgreSQL commit timestamp manager * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/commit_ts.h diff --git a/src/include/access/detoast.h b/src/include/access/detoast.h index 86bad7e78c765..0adf53c77bec0 100644 --- a/src/include/access/detoast.h +++ b/src/include/access/detoast.h @@ -3,7 +3,7 @@ * detoast.h * Access to compressed and external varlena values. * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/include/access/detoast.h * diff --git a/src/include/access/genam.h b/src/include/access/genam.h index 68d90f5141d61..aa8ff360daac4 100644 --- a/src/include/access/genam.h +++ b/src/include/access/genam.h @@ -4,7 +4,7 @@ * POSTGRES generalized index access method definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/genam.h diff --git a/src/include/access/generic_xlog.h b/src/include/access/generic_xlog.h index e0d460555ff96..6e0a2757ba2c9 100644 --- a/src/include/access/generic_xlog.h +++ b/src/include/access/generic_xlog.h @@ -4,7 +4,7 @@ * Generic xlog API definition. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/generic_xlog.h diff --git a/src/include/access/gin.h b/src/include/access/gin.h index 990e8b3e4fa95..266cb07236426 100644 --- a/src/include/access/gin.h +++ b/src/include/access/gin.h @@ -2,7 +2,7 @@ * gin.h * Public header file for Generalized Inverted Index access method. * - * Copyright (c) 2006-2020, PostgreSQL Global Development Group + * Copyright (c) 2006-2021, PostgreSQL Global Development Group * * src/include/access/gin.h *-------------------------------------------------------------------------- diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h index 5cb2f72e4cf80..a7a71ae1b4c49 100644 --- a/src/include/access/gin_private.h +++ b/src/include/access/gin_private.h @@ -2,7 +2,7 @@ * gin_private.h * header file for postgres inverted index access method implementation. * - * Copyright (c) 2006-2020, PostgreSQL Global Development Group + * Copyright (c) 2006-2021, PostgreSQL Global Development Group * * src/include/access/gin_private.h *-------------------------------------------------------------------------- diff --git a/src/include/access/ginblock.h b/src/include/access/ginblock.h index fe66a95226b99..37d650ac2a0e6 100644 --- a/src/include/access/ginblock.h +++ b/src/include/access/ginblock.h @@ -2,7 +2,7 @@ * ginblock.h * details of structures stored in GIN index blocks * - * Copyright (c) 2006-2020, PostgreSQL Global Development Group + * Copyright (c) 2006-2021, PostgreSQL Global Development Group * * src/include/access/ginblock.h *-------------------------------------------------------------------------- diff --git a/src/include/access/ginxlog.h b/src/include/access/ginxlog.h index a7edf8395f724..8a2507b79ddd1 100644 --- a/src/include/access/ginxlog.h +++ b/src/include/access/ginxlog.h @@ -2,7 +2,7 @@ * ginxlog.h * header file for postgres inverted index xlog implementation. * - * Copyright (c) 2006-2020, PostgreSQL Global Development Group + * Copyright (c) 2006-2021, PostgreSQL Global Development Group * * src/include/access/ginxlog.h *-------------------------------------------------------------------------- diff --git a/src/include/access/gist.h b/src/include/access/gist.h index 14b1190cd7e71..00c6b4f2bb93e 100644 --- a/src/include/access/gist.h +++ b/src/include/access/gist.h @@ -6,7 +6,7 @@ * changes should be made with care. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/gist.h diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index b68c01a5f246a..e899e817496b4 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -4,7 +4,7 @@ * private declarations for GiST -- declarations related to the * internal implementation of GiST, not the public API * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/gist_private.h diff --git a/src/include/access/gistscan.h b/src/include/access/gistscan.h index deeb4d08f7b2d..54451b5f77004 100644 --- a/src/include/access/gistscan.h +++ b/src/include/access/gistscan.h @@ -4,7 +4,7 @@ * routines defined in access/gist/gistscan.c * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/gistscan.h diff --git a/src/include/access/gistxlog.h b/src/include/access/gistxlog.h index 673afee1e1ef8..fd5144f25885b 100644 --- a/src/include/access/gistxlog.h +++ b/src/include/access/gistxlog.h @@ -3,7 +3,7 @@ * gistxlog.h * gist xlog routines * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/gistxlog.h diff --git a/src/include/access/hash.h b/src/include/access/hash.h index bab4d9f1b05cb..22a99e70837da 100644 --- a/src/include/access/hash.h +++ b/src/include/access/hash.h @@ -4,7 +4,7 @@ * header file for postgres hash access method implementation * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/hash.h diff --git a/src/include/access/hash_xlog.h b/src/include/access/hash_xlog.h index d1aa6daa40010..4353a32dbbaee 100644 --- a/src/include/access/hash_xlog.h +++ b/src/include/access/hash_xlog.h @@ -4,7 +4,7 @@ * header file for Postgres hash AM implementation * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/hash_xlog.h diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h index 54b2eb73785a1..95cb1e346b2d6 100644 --- a/src/include/access/heapam.h +++ b/src/include/access/heapam.h @@ -4,7 +4,7 @@ * POSTGRES heap access method definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/heapam.h diff --git a/src/include/access/heapam_xlog.h b/src/include/access/heapam_xlog.h index 15251941128a4..51586b883d373 100644 --- a/src/include/access/heapam_xlog.h +++ b/src/include/access/heapam_xlog.h @@ -4,7 +4,7 @@ * POSTGRES heap access XLOG definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/heapam_xlog.h diff --git a/src/include/access/heaptoast.h b/src/include/access/heaptoast.h index 26358319102c8..8b29f1a986299 100644 --- a/src/include/access/heaptoast.h +++ b/src/include/access/heaptoast.h @@ -4,7 +4,7 @@ * Heap-specific definitions for external and compressed storage * of variable size attributes. * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/include/access/heaptoast.h * diff --git a/src/include/access/hio.h b/src/include/access/hio.h index f69a92521bad1..1d611287c0840 100644 --- a/src/include/access/hio.h +++ b/src/include/access/hio.h @@ -4,7 +4,7 @@ * POSTGRES heap access method input/output definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/hio.h diff --git a/src/include/access/htup.h b/src/include/access/htup.h index 791883c4a7c7f..cf0bbd70455d2 100644 --- a/src/include/access/htup.h +++ b/src/include/access/htup.h @@ -4,7 +4,7 @@ * POSTGRES heap tuple definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/htup.h diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h index aebb1082ca445..7c62852e7fa3c 100644 --- a/src/include/access/htup_details.h +++ b/src/include/access/htup_details.h @@ -4,7 +4,7 @@ * POSTGRES heap tuple header definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/htup_details.h diff --git a/src/include/access/itup.h b/src/include/access/itup.h index b9c41d34553e0..b6813707d0b7a 100644 --- a/src/include/access/itup.h +++ b/src/include/access/itup.h @@ -4,7 +4,7 @@ * POSTGRES index tuple definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/itup.h diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h index 9a303809019a5..b5bb170e322b1 100644 --- a/src/include/access/multixact.h +++ b/src/include/access/multixact.h @@ -3,7 +3,7 @@ * * PostgreSQL multi-transaction-log manager * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/multixact.h diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h index e8fecc6026f3d..b793dab9fa66c 100644 --- a/src/include/access/nbtree.h +++ b/src/include/access/nbtree.h @@ -4,7 +4,7 @@ * header file for postgres btree access method implementation. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/nbtree.h diff --git a/src/include/access/nbtxlog.h b/src/include/access/nbtxlog.h index 5c014bdc66487..f5d3e9f5e09c0 100644 --- a/src/include/access/nbtxlog.h +++ b/src/include/access/nbtxlog.h @@ -3,7 +3,7 @@ * nbtxlog.h * header file for postgres btree xlog routines * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/nbtxlog.h diff --git a/src/include/access/parallel.h b/src/include/access/parallel.h index fc6a5603bb660..93d88ac60e192 100644 --- a/src/include/access/parallel.h +++ b/src/include/access/parallel.h @@ -3,7 +3,7 @@ * parallel.h * Infrastructure for launching parallel workers * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/parallel.h diff --git a/src/include/access/printsimple.h b/src/include/access/printsimple.h index 3f8a66849bb6c..67a995014fe8b 100644 --- a/src/include/access/printsimple.h +++ b/src/include/access/printsimple.h @@ -3,7 +3,7 @@ * printsimple.h * print simple tuples without catalog access * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/printsimple.h diff --git a/src/include/access/printtup.h b/src/include/access/printtup.h index c367825b9d5e9..c9b37538a0be5 100644 --- a/src/include/access/printtup.h +++ b/src/include/access/printtup.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/printtup.h diff --git a/src/include/access/relation.h b/src/include/access/relation.h index 2ed0f8ea625b3..fd77a133cb2d5 100644 --- a/src/include/access/relation.h +++ b/src/include/access/relation.h @@ -4,7 +4,7 @@ * Generic relation related routines. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/relation.h diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 5964438cb0c5a..7c5fbeb517a3a 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -9,7 +9,7 @@ * into a lot of low-level code. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/reloptions.h diff --git a/src/include/access/relscan.h b/src/include/access/relscan.h index 56459769519b3..005f3fdd2b827 100644 --- a/src/include/access/relscan.h +++ b/src/include/access/relscan.h @@ -4,7 +4,7 @@ * POSTGRES relation scan descriptor definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/relscan.h diff --git a/src/include/access/rewriteheap.h b/src/include/access/rewriteheap.h index e6d7fa1e654b9..121f5524051db 100644 --- a/src/include/access/rewriteheap.h +++ b/src/include/access/rewriteheap.h @@ -3,7 +3,7 @@ * rewriteheap.h * Declarations for heap rewrite support functions * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994-5, Regents of the University of California * * src/include/access/rewriteheap.h diff --git a/src/include/access/rmgrlist.h b/src/include/access/rmgrlist.h index 6c15df7e70702..f582cf535f62f 100644 --- a/src/include/access/rmgrlist.h +++ b/src/include/access/rmgrlist.h @@ -6,7 +6,7 @@ * by the PG_RMGR macro, which is not defined in this file; it can be * defined by the caller for special purposes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/rmgrlist.h diff --git a/src/include/access/sdir.h b/src/include/access/sdir.h index 23feb909863a7..8154adf3b822c 100644 --- a/src/include/access/sdir.h +++ b/src/include/access/sdir.h @@ -4,7 +4,7 @@ * POSTGRES scan direction definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/sdir.h diff --git a/src/include/access/session.h b/src/include/access/session.h index 4c1f6ffd405df..82cee5aff573f 100644 --- a/src/include/access/session.h +++ b/src/include/access/session.h @@ -3,7 +3,7 @@ * session.h * Encapsulation of user session. * - * Copyright (c) 2017-2020, PostgreSQL Global Development Group + * Copyright (c) 2017-2021, PostgreSQL Global Development Group * * src/include/access/session.h * diff --git a/src/include/access/skey.h b/src/include/access/skey.h index 7d2df1bac33bd..92b7d09fa450c 100644 --- a/src/include/access/skey.h +++ b/src/include/access/skey.h @@ -4,7 +4,7 @@ * POSTGRES scan key definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/skey.h diff --git a/src/include/access/slru.h b/src/include/access/slru.h index b39b43504d80c..34964675d20f6 100644 --- a/src/include/access/slru.h +++ b/src/include/access/slru.h @@ -3,7 +3,7 @@ * slru.h * Simple LRU buffering for transaction status logfiles * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/slru.h diff --git a/src/include/access/spgist.h b/src/include/access/spgist.h index 9f2ccc1730f99..38a5902202bfe 100644 --- a/src/include/access/spgist.h +++ b/src/include/access/spgist.h @@ -4,7 +4,7 @@ * Public header file for SP-GiST access method. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/spgist.h diff --git a/src/include/access/spgist_private.h b/src/include/access/spgist_private.h index 00b98ec6a023b..a81bab24ea415 100644 --- a/src/include/access/spgist_private.h +++ b/src/include/access/spgist_private.h @@ -4,7 +4,7 @@ * Private declarations for SP-GiST access method. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/spgist_private.h diff --git a/src/include/access/spgxlog.h b/src/include/access/spgxlog.h index 63d3c63db2db8..69405b5750021 100644 --- a/src/include/access/spgxlog.h +++ b/src/include/access/spgxlog.h @@ -3,7 +3,7 @@ * spgxlog.h * xlog declarations for SP-GiST access method. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/spgxlog.h diff --git a/src/include/access/stratnum.h b/src/include/access/stratnum.h index 415e1f7e88fec..fad4b6991c6f3 100644 --- a/src/include/access/stratnum.h +++ b/src/include/access/stratnum.h @@ -4,7 +4,7 @@ * POSTGRES strategy number definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/stratnum.h diff --git a/src/include/access/subtrans.h b/src/include/access/subtrans.h index 2bab8e2097dc2..5ccb52b5f679a 100644 --- a/src/include/access/subtrans.h +++ b/src/include/access/subtrans.h @@ -3,7 +3,7 @@ * * PostgreSQL subtransaction-log manager * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/subtrans.h diff --git a/src/include/access/syncscan.h b/src/include/access/syncscan.h index 7cbf63c399fe5..7947f3c3f6cf5 100644 --- a/src/include/access/syncscan.h +++ b/src/include/access/syncscan.h @@ -4,7 +4,7 @@ * POSTGRES synchronous scan support functions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/syncscan.h diff --git a/src/include/access/sysattr.h b/src/include/access/sysattr.h index 734976d5a7895..968257bd8b298 100644 --- a/src/include/access/sysattr.h +++ b/src/include/access/sysattr.h @@ -4,7 +4,7 @@ * POSTGRES system attribute definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/sysattr.h diff --git a/src/include/access/table.h b/src/include/access/table.h index 68dc4d62c03f2..5e4d9dd32fff4 100644 --- a/src/include/access/table.h +++ b/src/include/access/table.h @@ -4,7 +4,7 @@ * Generic routines for table related code. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/table.h diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h index 387eb34a61a36..c2357a72e4864 100644 --- a/src/include/access/tableam.h +++ b/src/include/access/tableam.h @@ -4,7 +4,7 @@ * POSTGRES table access method definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/tableam.h diff --git a/src/include/access/timeline.h b/src/include/access/timeline.h index 2878f6d669b4e..ce3586c39d7b5 100644 --- a/src/include/access/timeline.h +++ b/src/include/access/timeline.h @@ -3,7 +3,7 @@ * * Functions for reading and writing timeline history files. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/timeline.h diff --git a/src/include/access/toast_helper.h b/src/include/access/toast_helper.h index 0e92acc546e5c..a9a6d644bc398 100644 --- a/src/include/access/toast_helper.h +++ b/src/include/access/toast_helper.h @@ -4,7 +4,7 @@ * Helper functions for table AMs implementing compressed or * out-of-line storage of varlena attributes. * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/include/access/toast_helper.h * diff --git a/src/include/access/toast_internals.h b/src/include/access/toast_internals.h index 71e3ca2ef26a8..cedfb890d8e84 100644 --- a/src/include/access/toast_internals.h +++ b/src/include/access/toast_internals.h @@ -3,7 +3,7 @@ * toast_internals.h * Internal definitions for the TOAST system. * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/include/access/toast_internals.h * diff --git a/src/include/access/transam.h b/src/include/access/transam.h index 2f1f144db4d06..e07dd83550f40 100644 --- a/src/include/access/transam.h +++ b/src/include/access/transam.h @@ -4,7 +4,7 @@ * postgres transaction access method support code * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/transam.h diff --git a/src/include/access/tsmapi.h b/src/include/access/tsmapi.h index ffc64bcda97a8..2dc848ca78913 100644 --- a/src/include/access/tsmapi.h +++ b/src/include/access/tsmapi.h @@ -3,7 +3,7 @@ * tsmapi.h * API for tablesample methods * - * Copyright (c) 2015-2020, PostgreSQL Global Development Group + * Copyright (c) 2015-2021, PostgreSQL Global Development Group * * src/include/access/tsmapi.h * diff --git a/src/include/access/tupconvert.h b/src/include/access/tupconvert.h index afd5801e6abab..b25e28221ea72 100644 --- a/src/include/access/tupconvert.h +++ b/src/include/access/tupconvert.h @@ -4,7 +4,7 @@ * Tuple conversion support. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/tupconvert.h diff --git a/src/include/access/tupdesc.h b/src/include/access/tupdesc.h index d17af13ee31e0..f45d47aab7a7a 100644 --- a/src/include/access/tupdesc.h +++ b/src/include/access/tupdesc.h @@ -4,7 +4,7 @@ * POSTGRES tuple descriptor definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/tupdesc.h diff --git a/src/include/access/tupdesc_details.h b/src/include/access/tupdesc_details.h index 01c4a119a2d02..d0d2c992a0081 100644 --- a/src/include/access/tupdesc_details.h +++ b/src/include/access/tupdesc_details.h @@ -4,7 +4,7 @@ * POSTGRES tuple descriptor definitions we can't include everywhere * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/tupdesc_details.h diff --git a/src/include/access/tupmacs.h b/src/include/access/tupmacs.h index c262265b95138..65ac1ef3fc834 100644 --- a/src/include/access/tupmacs.h +++ b/src/include/access/tupmacs.h @@ -4,7 +4,7 @@ * Tuple macros used by both index tuples and heap tuples. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/tupmacs.h diff --git a/src/include/access/twophase.h b/src/include/access/twophase.h index 2ca71c3445246..91786da784273 100644 --- a/src/include/access/twophase.h +++ b/src/include/access/twophase.h @@ -4,7 +4,7 @@ * Two-phase-commit related declarations. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/twophase.h diff --git a/src/include/access/twophase_rmgr.h b/src/include/access/twophase_rmgr.h index 65986a6dfa63f..2709d72d8feb1 100644 --- a/src/include/access/twophase_rmgr.h +++ b/src/include/access/twophase_rmgr.h @@ -4,7 +4,7 @@ * Two-phase-commit resource managers definition * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/twophase_rmgr.h diff --git a/src/include/access/valid.h b/src/include/access/valid.h index 443d4da9d6cc1..a462113a0c57d 100644 --- a/src/include/access/valid.h +++ b/src/include/access/valid.h @@ -4,7 +4,7 @@ * POSTGRES tuple qualification validity definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/valid.h diff --git a/src/include/access/visibilitymap.h b/src/include/access/visibilitymap.h index b462e90ee8f82..57362c368761f 100644 --- a/src/include/access/visibilitymap.h +++ b/src/include/access/visibilitymap.h @@ -4,7 +4,7 @@ * visibility map interface * * - * Portions Copyright (c) 2007-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2007-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/visibilitymap.h diff --git a/src/include/access/xact.h b/src/include/access/xact.h index 7320de345c995..f49a57b35e15d 100644 --- a/src/include/access/xact.h +++ b/src/include/access/xact.h @@ -4,7 +4,7 @@ * postgres transaction system definitions * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/xact.h diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index 221af87e715b8..75ec1073bd029 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -3,7 +3,7 @@ * * PostgreSQL write-ahead log manager * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/xlog.h diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h index 4146753d4765d..9585ad17b3cfb 100644 --- a/src/include/access/xlog_internal.h +++ b/src/include/access/xlog_internal.h @@ -11,7 +11,7 @@ * Note: This file must be includable in both frontend and backend contexts, * to allow stand-alone tools like pg_receivewal to deal with WAL files. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/xlog_internal.h diff --git a/src/include/access/xlogarchive.h b/src/include/access/xlogarchive.h index 1c67de2ede680..3edd1a976c1b4 100644 --- a/src/include/access/xlogarchive.h +++ b/src/include/access/xlogarchive.h @@ -3,7 +3,7 @@ * xlogarchive.h * Prototypes for WAL archives in the backend * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/access/xlogdefs.h b/src/include/access/xlogdefs.h index e1f58122131a3..65836d5bc65b2 100644 --- a/src/include/access/xlogdefs.h +++ b/src/include/access/xlogdefs.h @@ -4,7 +4,7 @@ * Postgres write-ahead log manager record pointer and * timeline number definitions * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/xlogdefs.h diff --git a/src/include/access/xloginsert.h b/src/include/access/xloginsert.h index 4ba2c56be60be..f1d8c39edf148 100644 --- a/src/include/access/xloginsert.h +++ b/src/include/access/xloginsert.h @@ -3,7 +3,7 @@ * * Functions for generating WAL records * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/xloginsert.h diff --git a/src/include/access/xlogreader.h b/src/include/access/xlogreader.h index 0b6d00dd7dfa3..21d200d3df6f3 100644 --- a/src/include/access/xlogreader.h +++ b/src/include/access/xlogreader.h @@ -3,7 +3,7 @@ * xlogreader.h * Definitions for the generic XLog reading facility * - * Portions Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2013-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/include/access/xlogreader.h diff --git a/src/include/access/xlogrecord.h b/src/include/access/xlogrecord.h index 2f0c8bf58966c..80c92a2498a32 100644 --- a/src/include/access/xlogrecord.h +++ b/src/include/access/xlogrecord.h @@ -3,7 +3,7 @@ * * Definitions for the WAL record format. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/xlogrecord.h diff --git a/src/include/access/xlogutils.h b/src/include/access/xlogutils.h index e59b6cf3a9f3f..9ac602b674d1a 100644 --- a/src/include/access/xlogutils.h +++ b/src/include/access/xlogutils.h @@ -3,7 +3,7 @@ * * Utilities for replaying WAL records. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/xlogutils.h diff --git a/src/include/bootstrap/bootstrap.h b/src/include/bootstrap/bootstrap.h index b67fa9acc1abd..8290d4c6c490c 100644 --- a/src/include/bootstrap/bootstrap.h +++ b/src/include/bootstrap/bootstrap.h @@ -4,7 +4,7 @@ * include file for the bootstrapping code * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/bootstrap/bootstrap.h diff --git a/src/include/c.h b/src/include/c.h index 7bc4b8a001b0b..ae978830dafba 100644 --- a/src/include/c.h +++ b/src/include/c.h @@ -9,7 +9,7 @@ * polluting the namespace with lots of stuff... * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/c.h diff --git a/src/include/catalog/Makefile b/src/include/catalog/Makefile index 67f02a0d208dc..81b7b1896c391 100644 --- a/src/include/catalog/Makefile +++ b/src/include/catalog/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/include/catalog # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/Makefile diff --git a/src/include/catalog/binary_upgrade.h b/src/include/catalog/binary_upgrade.h index 1ff62e9f8e632..f6e82e7ac50ac 100644 --- a/src/include/catalog/binary_upgrade.h +++ b/src/include/catalog/binary_upgrade.h @@ -4,7 +4,7 @@ * variables used for binary upgrades * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/binary_upgrade.h diff --git a/src/include/catalog/catalog.h b/src/include/catalog/catalog.h index 7824a123c2983..f247be50b4d33 100644 --- a/src/include/catalog/catalog.h +++ b/src/include/catalog/catalog.h @@ -4,7 +4,7 @@ * prototypes for functions in backend/catalog/catalog.c * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/catalog.h diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index db4814e57afa5..a6e39b3139a51 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -34,7 +34,7 @@ * database contents or layout, such as altering tuple headers. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/catversion.h diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index 1fcc4a39ec491..6d6c23d8462aa 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -4,7 +4,7 @@ * Routines to support inter-object dependencies. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/dependency.h diff --git a/src/include/catalog/duplicate_oids b/src/include/catalog/duplicate_oids index c46b663256794..ed60e962c8ea9 100755 --- a/src/include/catalog/duplicate_oids +++ b/src/include/catalog/duplicate_oids @@ -9,7 +9,7 @@ # the same catalog, our project policy is that manually assigned OIDs # should be globally unique, to avoid confusion. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/duplicate_oids diff --git a/src/include/catalog/genbki.h b/src/include/catalog/genbki.h index 92eea9d345ddd..e26bde6d09b2c 100644 --- a/src/include/catalog/genbki.h +++ b/src/include/catalog/genbki.h @@ -9,7 +9,7 @@ * bootstrap file from these header files.) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/genbki.h diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h index f94defff3ce80..6ce480b49c1b6 100644 --- a/src/include/catalog/heap.h +++ b/src/include/catalog/heap.h @@ -4,7 +4,7 @@ * prototypes for functions in backend/catalog/heap.c * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/heap.h diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h index c0416280499d4..9904a76387a55 100644 --- a/src/include/catalog/index.h +++ b/src/include/catalog/index.h @@ -4,7 +4,7 @@ * prototypes for catalog/index.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/index.h diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h index 8261cbbde62d7..758ec42e50104 100644 --- a/src/include/catalog/indexing.h +++ b/src/include/catalog/indexing.h @@ -5,7 +5,7 @@ * on system catalogs * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/indexing.h diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h index 2456c08bf781b..aa2774e2d4ec7 100644 --- a/src/include/catalog/namespace.h +++ b/src/include/catalog/namespace.h @@ -4,7 +4,7 @@ * prototypes for functions in backend/catalog/namespace.c * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/namespace.h diff --git a/src/include/catalog/objectaccess.h b/src/include/catalog/objectaccess.h index fef383692f8bd..896c3a0fdc5b0 100644 --- a/src/include/catalog/objectaccess.h +++ b/src/include/catalog/objectaccess.h @@ -3,7 +3,7 @@ * * Object access hooks. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California */ diff --git a/src/include/catalog/objectaddress.h b/src/include/catalog/objectaddress.h index b876617c9d788..2b4e104bb9d64 100644 --- a/src/include/catalog/objectaddress.h +++ b/src/include/catalog/objectaddress.h @@ -3,7 +3,7 @@ * objectaddress.h * functions for working with object addresses * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/objectaddress.h diff --git a/src/include/catalog/partition.h b/src/include/catalog/partition.h index 27873aff6e2f8..fe3f66befaf06 100644 --- a/src/include/catalog/partition.h +++ b/src/include/catalog/partition.h @@ -4,7 +4,7 @@ * Header file for structures and utility functions related to * partitioning * - * Copyright (c) 2007-2020, PostgreSQL Global Development Group + * Copyright (c) 2007-2021, PostgreSQL Global Development Group * * src/include/catalog/partition.h * diff --git a/src/include/catalog/pg_aggregate.dat b/src/include/catalog/pg_aggregate.dat index 03bab74253d1e..40c6616f8fb32 100644 --- a/src/include/catalog/pg_aggregate.dat +++ b/src/include/catalog/pg_aggregate.dat @@ -3,7 +3,7 @@ # pg_aggregate.dat # Initial contents of the pg_aggregate system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_aggregate.dat diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h index 7e94d604b9f49..e90c3f847e1ff 100644 --- a/src/include/catalog/pg_aggregate.h +++ b/src/include/catalog/pg_aggregate.h @@ -4,7 +4,7 @@ * definition of the "aggregate" system catalog (pg_aggregate) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_aggregate.h diff --git a/src/include/catalog/pg_am.dat b/src/include/catalog/pg_am.dat index 0f051277a6a13..6082f0e6a8f5f 100644 --- a/src/include/catalog/pg_am.dat +++ b/src/include/catalog/pg_am.dat @@ -3,7 +3,7 @@ # pg_am.dat # Initial contents of the pg_am system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_am.dat diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h index bc73e88a1a030..358f5aac8fc42 100644 --- a/src/include/catalog/pg_am.h +++ b/src/include/catalog/pg_am.h @@ -4,7 +4,7 @@ * definition of the "access method" system catalog (pg_am) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_am.h diff --git a/src/include/catalog/pg_amop.dat b/src/include/catalog/pg_amop.dat index bbe1a6ddf8e64..9339971e77c6a 100644 --- a/src/include/catalog/pg_amop.dat +++ b/src/include/catalog/pg_amop.dat @@ -3,7 +3,7 @@ # pg_amop.dat # Initial contents of the pg_amop system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_amop.dat diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h index c5215cdaafc8e..3ccd75f67b587 100644 --- a/src/include/catalog/pg_amop.h +++ b/src/include/catalog/pg_amop.h @@ -29,7 +29,7 @@ * intentional denormalization of the catalogs to buy lookup speed. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_amop.h diff --git a/src/include/catalog/pg_amproc.dat b/src/include/catalog/pg_amproc.dat index 68d72ec732a44..9b90f4d806d7e 100644 --- a/src/include/catalog/pg_amproc.dat +++ b/src/include/catalog/pg_amproc.dat @@ -3,7 +3,7 @@ # pg_amproc.dat # Initial contents of the pg_amproc system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_amproc.dat diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h index cd422d5ad7872..86f1f25d17f90 100644 --- a/src/include/catalog/pg_amproc.h +++ b/src/include/catalog/pg_amproc.h @@ -18,7 +18,7 @@ * some don't pay attention to non-default functions at all. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_amproc.h diff --git a/src/include/catalog/pg_attrdef.h b/src/include/catalog/pg_attrdef.h index 9d5426be97274..fe3aa289927f8 100644 --- a/src/include/catalog/pg_attrdef.h +++ b/src/include/catalog/pg_attrdef.h @@ -4,7 +4,7 @@ * definition of the "attribute defaults" system catalog (pg_attrdef) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_attrdef.h diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h index cdf75a2380520..059dec3647dad 100644 --- a/src/include/catalog/pg_attribute.h +++ b/src/include/catalog/pg_attribute.h @@ -8,7 +8,7 @@ * relations need be included. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_attribute.h diff --git a/src/include/catalog/pg_auth_members.h b/src/include/catalog/pg_auth_members.h index d1f609da50020..fc5a2dced7b5d 100644 --- a/src/include/catalog/pg_auth_members.h +++ b/src/include/catalog/pg_auth_members.h @@ -5,7 +5,7 @@ * (pg_auth_members). * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_auth_members.h diff --git a/src/include/catalog/pg_authid.dat b/src/include/catalog/pg_authid.dat index 7c08851550a2b..a643a09588abd 100644 --- a/src/include/catalog/pg_authid.dat +++ b/src/include/catalog/pg_authid.dat @@ -3,7 +3,7 @@ # pg_authid.dat # Initial contents of the pg_authid system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_authid.dat diff --git a/src/include/catalog/pg_authid.h b/src/include/catalog/pg_authid.h index 664b3910f5f27..4063072cc915c 100644 --- a/src/include/catalog/pg_authid.h +++ b/src/include/catalog/pg_authid.h @@ -6,7 +6,7 @@ * pg_shadow and pg_group are now publicly accessible views on pg_authid. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_authid.h diff --git a/src/include/catalog/pg_cast.dat b/src/include/catalog/pg_cast.dat index d6ca624addc99..b807a34355ff3 100644 --- a/src/include/catalog/pg_cast.dat +++ b/src/include/catalog/pg_cast.dat @@ -3,7 +3,7 @@ # pg_cast.dat # Initial contents of the pg_cast system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_cast.dat diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h index 0a38ec00bc517..03ad900a49900 100644 --- a/src/include/catalog/pg_cast.h +++ b/src/include/catalog/pg_cast.h @@ -6,7 +6,7 @@ * As of Postgres 8.0, pg_cast describes not only type coercion functions * but also length coercion functions. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_cast.h diff --git a/src/include/catalog/pg_class.dat b/src/include/catalog/pg_class.dat index b28bba7cc3f7e..601abb98e43aa 100644 --- a/src/include/catalog/pg_class.dat +++ b/src/include/catalog/pg_class.dat @@ -3,7 +3,7 @@ # pg_class.dat # Initial contents of the pg_class system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_class.dat diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h index bb5e72ca43238..e8dcd15a55fbd 100644 --- a/src/include/catalog/pg_class.h +++ b/src/include/catalog/pg_class.h @@ -4,7 +4,7 @@ * definition of the "relation" system catalog (pg_class) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_class.h diff --git a/src/include/catalog/pg_collation.dat b/src/include/catalog/pg_collation.dat index 45301ccdd7d18..7905fc4833659 100644 --- a/src/include/catalog/pg_collation.dat +++ b/src/include/catalog/pg_collation.dat @@ -3,7 +3,7 @@ # pg_collation.dat # Initial contents of the pg_collation system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_collation.dat diff --git a/src/include/catalog/pg_collation.h b/src/include/catalog/pg_collation.h index e59b1484aa834..251c2b9adae86 100644 --- a/src/include/catalog/pg_collation.h +++ b/src/include/catalog/pg_collation.h @@ -4,7 +4,7 @@ * definition of the "collation" system catalog (pg_collation) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_collation.h diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h index 8580887519e71..f3c3df390fee9 100644 --- a/src/include/catalog/pg_constraint.h +++ b/src/include/catalog/pg_constraint.h @@ -4,7 +4,7 @@ * definition of the "constraint" system catalog (pg_constraint) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_constraint.h diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h index 06bed90c5e9e5..e3f48158ce7a4 100644 --- a/src/include/catalog/pg_control.h +++ b/src/include/catalog/pg_control.h @@ -5,7 +5,7 @@ * However, we define it here so that the format is documented. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_control.h diff --git a/src/include/catalog/pg_conversion.dat b/src/include/catalog/pg_conversion.dat index d7120f2fb0e90..d8ba3a6c5230f 100644 --- a/src/include/catalog/pg_conversion.dat +++ b/src/include/catalog/pg_conversion.dat @@ -3,7 +3,7 @@ # pg_conversion.dat # Initial contents of the pg_conversion system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_conversion.dat diff --git a/src/include/catalog/pg_conversion.h b/src/include/catalog/pg_conversion.h index 0536c4a544677..93dcc35840ce6 100644 --- a/src/include/catalog/pg_conversion.h +++ b/src/include/catalog/pg_conversion.h @@ -3,7 +3,7 @@ * pg_conversion.h * definition of the "conversion" system catalog (pg_conversion) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_conversion.h diff --git a/src/include/catalog/pg_database.dat b/src/include/catalog/pg_database.dat index 21cd6604f3ea1..b8aa1364a0d59 100644 --- a/src/include/catalog/pg_database.dat +++ b/src/include/catalog/pg_database.dat @@ -3,7 +3,7 @@ # pg_database.dat # Initial contents of the pg_database system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_database.dat diff --git a/src/include/catalog/pg_database.h b/src/include/catalog/pg_database.h index 47bcf403463db..97691127bf539 100644 --- a/src/include/catalog/pg_database.h +++ b/src/include/catalog/pg_database.h @@ -4,7 +4,7 @@ * definition of the "database" system catalog (pg_database) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_database.h diff --git a/src/include/catalog/pg_db_role_setting.h b/src/include/catalog/pg_db_role_setting.h index 6f8ea02485c18..d3c006d7544d8 100644 --- a/src/include/catalog/pg_db_role_setting.h +++ b/src/include/catalog/pg_db_role_setting.h @@ -5,7 +5,7 @@ * configuration settings (pg_db_role_setting) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_db_role_setting.h diff --git a/src/include/catalog/pg_default_acl.h b/src/include/catalog/pg_default_acl.h index a8771dfaa9293..0f3974c32cbe3 100644 --- a/src/include/catalog/pg_default_acl.h +++ b/src/include/catalog/pg_default_acl.h @@ -5,7 +5,7 @@ * (pg_default_acl) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_default_acl.h diff --git a/src/include/catalog/pg_depend.h b/src/include/catalog/pg_depend.h index 4d5e360803d80..b0837901806f3 100644 --- a/src/include/catalog/pg_depend.h +++ b/src/include/catalog/pg_depend.h @@ -16,7 +16,7 @@ * convenient to find from the contents of other catalogs. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_depend.h diff --git a/src/include/catalog/pg_description.h b/src/include/catalog/pg_description.h index 0686ff7ada309..0002643a76c21 100644 --- a/src/include/catalog/pg_description.h +++ b/src/include/catalog/pg_description.h @@ -23,7 +23,7 @@ * for example). * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_description.h diff --git a/src/include/catalog/pg_enum.h b/src/include/catalog/pg_enum.h index 39e47fd1a0f94..4cc4610589a7b 100644 --- a/src/include/catalog/pg_enum.h +++ b/src/include/catalog/pg_enum.h @@ -4,7 +4,7 @@ * definition of the "enum" system catalog (pg_enum) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_enum.h diff --git a/src/include/catalog/pg_event_trigger.h b/src/include/catalog/pg_event_trigger.h index dda54a86496c0..4011654969c0b 100644 --- a/src/include/catalog/pg_event_trigger.h +++ b/src/include/catalog/pg_event_trigger.h @@ -4,7 +4,7 @@ * definition of the "event trigger" system catalog (pg_event_trigger) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_event_trigger.h diff --git a/src/include/catalog/pg_extension.h b/src/include/catalog/pg_extension.h index dc23fd59d023d..f7d640fac6fbb 100644 --- a/src/include/catalog/pg_extension.h +++ b/src/include/catalog/pg_extension.h @@ -4,7 +4,7 @@ * definition of the "extension" system catalog (pg_extension) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_extension.h diff --git a/src/include/catalog/pg_foreign_data_wrapper.h b/src/include/catalog/pg_foreign_data_wrapper.h index 0506a254610ce..ca73dc280cabd 100644 --- a/src/include/catalog/pg_foreign_data_wrapper.h +++ b/src/include/catalog/pg_foreign_data_wrapper.h @@ -4,7 +4,7 @@ * definition of the "foreign-data wrapper" system catalog (pg_foreign_data_wrapper) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_foreign_data_wrapper.h diff --git a/src/include/catalog/pg_foreign_server.h b/src/include/catalog/pg_foreign_server.h index b076d4c2bed96..3a68f444e706b 100644 --- a/src/include/catalog/pg_foreign_server.h +++ b/src/include/catalog/pg_foreign_server.h @@ -3,7 +3,7 @@ * pg_foreign_server.h * definition of the "foreign server" system catalog (pg_foreign_server) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_foreign_server.h diff --git a/src/include/catalog/pg_foreign_table.h b/src/include/catalog/pg_foreign_table.h index ff01cc6c149c0..c761852bb938a 100644 --- a/src/include/catalog/pg_foreign_table.h +++ b/src/include/catalog/pg_foreign_table.h @@ -3,7 +3,7 @@ * pg_foreign_table.h * definition of the "foreign table" system catalog (pg_foreign_table) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_foreign_table.h diff --git a/src/include/catalog/pg_index.h b/src/include/catalog/pg_index.h index 0af6617b133be..b6d7ebec55960 100644 --- a/src/include/catalog/pg_index.h +++ b/src/include/catalog/pg_index.h @@ -4,7 +4,7 @@ * definition of the "index" system catalog (pg_index) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_index.h diff --git a/src/include/catalog/pg_inherits.h b/src/include/catalog/pg_inherits.h index 63ee9a75e87a5..a0f2ec4e0bd30 100644 --- a/src/include/catalog/pg_inherits.h +++ b/src/include/catalog/pg_inherits.h @@ -4,7 +4,7 @@ * definition of the "inherits" system catalog (pg_inherits) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_inherits.h diff --git a/src/include/catalog/pg_init_privs.h b/src/include/catalog/pg_init_privs.h index 048556418ab4a..da1fa5b279afe 100644 --- a/src/include/catalog/pg_init_privs.h +++ b/src/include/catalog/pg_init_privs.h @@ -21,7 +21,7 @@ * are loaded near the end of initdb. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_init_privs.h diff --git a/src/include/catalog/pg_language.dat b/src/include/catalog/pg_language.dat index 2e44a2730dfc7..a584679927a46 100644 --- a/src/include/catalog/pg_language.dat +++ b/src/include/catalog/pg_language.dat @@ -3,7 +3,7 @@ # pg_language.dat # Initial contents of the pg_language system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_language.dat diff --git a/src/include/catalog/pg_language.h b/src/include/catalog/pg_language.h index df17d332d279f..ffab93eb6a33f 100644 --- a/src/include/catalog/pg_language.h +++ b/src/include/catalog/pg_language.h @@ -4,7 +4,7 @@ * definition of the "language" system catalog (pg_language) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_language.h diff --git a/src/include/catalog/pg_largeobject.h b/src/include/catalog/pg_largeobject.h index 064b2468ac90a..80b1cbae83106 100644 --- a/src/include/catalog/pg_largeobject.h +++ b/src/include/catalog/pg_largeobject.h @@ -4,7 +4,7 @@ * definition of the "large object" system catalog (pg_largeobject) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_largeobject.h diff --git a/src/include/catalog/pg_largeobject_metadata.h b/src/include/catalog/pg_largeobject_metadata.h index 0d33f5bd193b4..b1504a22fa34b 100644 --- a/src/include/catalog/pg_largeobject_metadata.h +++ b/src/include/catalog/pg_largeobject_metadata.h @@ -5,7 +5,7 @@ * (pg_largeobject_metadata) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_largeobject_metadata.h diff --git a/src/include/catalog/pg_namespace.dat b/src/include/catalog/pg_namespace.dat index 63a61022ce36d..76257e98fcc91 100644 --- a/src/include/catalog/pg_namespace.dat +++ b/src/include/catalog/pg_namespace.dat @@ -3,7 +3,7 @@ # pg_namespace.dat # Initial contents of the pg_namespace system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_namespace.dat diff --git a/src/include/catalog/pg_namespace.h b/src/include/catalog/pg_namespace.h index 9c3d126644679..5710c37d78c81 100644 --- a/src/include/catalog/pg_namespace.h +++ b/src/include/catalog/pg_namespace.h @@ -4,7 +4,7 @@ * definition of the "namespace" system catalog (pg_namespace) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_namespace.h diff --git a/src/include/catalog/pg_opclass.dat b/src/include/catalog/pg_opclass.dat index 12cad6941866f..5128d6eded87b 100644 --- a/src/include/catalog/pg_opclass.dat +++ b/src/include/catalog/pg_opclass.dat @@ -3,7 +3,7 @@ # pg_opclass.dat # Initial contents of the pg_opclass system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_opclass.dat diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h index 446ae52c2ec2a..7836d56c3f35a 100644 --- a/src/include/catalog/pg_opclass.h +++ b/src/include/catalog/pg_opclass.h @@ -24,7 +24,7 @@ * AMs support this. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_opclass.h diff --git a/src/include/catalog/pg_operator.dat b/src/include/catalog/pg_operator.dat index 9c6bf6c9d115d..a7a2a94692cf9 100644 --- a/src/include/catalog/pg_operator.dat +++ b/src/include/catalog/pg_operator.dat @@ -3,7 +3,7 @@ # pg_operator.dat # Initial contents of the pg_operator system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_operator.dat diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h index bdcd7fcde88e7..05a3fe1815756 100644 --- a/src/include/catalog/pg_operator.h +++ b/src/include/catalog/pg_operator.h @@ -4,7 +4,7 @@ * definition of the "operator" system catalog (pg_operator) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_operator.h diff --git a/src/include/catalog/pg_opfamily.dat b/src/include/catalog/pg_opfamily.dat index ac8338f34b120..57e5aa0d8b965 100644 --- a/src/include/catalog/pg_opfamily.dat +++ b/src/include/catalog/pg_opfamily.dat @@ -3,7 +3,7 @@ # pg_opfamily.dat # Initial contents of the pg_opfamily system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_opfamily.dat diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h index 56fd5d0e6b5b6..c00eda0785328 100644 --- a/src/include/catalog/pg_opfamily.h +++ b/src/include/catalog/pg_opfamily.h @@ -4,7 +4,7 @@ * definition of the "operator family" system catalog (pg_opfamily) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_opfamily.h diff --git a/src/include/catalog/pg_partitioned_table.h b/src/include/catalog/pg_partitioned_table.h index 45d613d4ecf7e..f51d7e16bf991 100644 --- a/src/include/catalog/pg_partitioned_table.h +++ b/src/include/catalog/pg_partitioned_table.h @@ -5,7 +5,7 @@ * (pg_partitioned_table) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_partitioned_table.h diff --git a/src/include/catalog/pg_policy.h b/src/include/catalog/pg_policy.h index b06580a1551f1..a5af6eb352ba9 100644 --- a/src/include/catalog/pg_policy.h +++ b/src/include/catalog/pg_policy.h @@ -4,7 +4,7 @@ * definition of the "policy" system catalog (pg_policy) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_policy.h diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 139f4a08bd5b7..d7b55f57ea77f 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -3,7 +3,7 @@ # pg_proc.dat # Initial contents of the pg_proc system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_proc.dat diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index f8e6dea22d09e..1c2551c932732 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -3,7 +3,7 @@ * pg_proc.h * definition of the "procedure" system catalog (pg_proc) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_proc.h diff --git a/src/include/catalog/pg_publication.h b/src/include/catalog/pg_publication.h index 309d102d7dc45..0dd50fe428fe7 100644 --- a/src/include/catalog/pg_publication.h +++ b/src/include/catalog/pg_publication.h @@ -3,7 +3,7 @@ * pg_publication.h * definition of the "publication" system catalog (pg_publication) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_publication.h diff --git a/src/include/catalog/pg_publication_rel.h b/src/include/catalog/pg_publication_rel.h index 652cbcd6cb924..6e6ec6444d174 100644 --- a/src/include/catalog/pg_publication_rel.h +++ b/src/include/catalog/pg_publication_rel.h @@ -4,7 +4,7 @@ * definition of the system catalog for mappings between relations and * publications (pg_publication_rel) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_publication_rel.h diff --git a/src/include/catalog/pg_range.dat b/src/include/catalog/pg_range.dat index 10060255c95c0..5ba23aa21dc37 100644 --- a/src/include/catalog/pg_range.dat +++ b/src/include/catalog/pg_range.dat @@ -3,7 +3,7 @@ # pg_range.dat # Initial contents of the pg_range system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_range.dat diff --git a/src/include/catalog/pg_range.h b/src/include/catalog/pg_range.h index 76ad4000bf794..f0c3897184480 100644 --- a/src/include/catalog/pg_range.h +++ b/src/include/catalog/pg_range.h @@ -4,7 +4,7 @@ * definition of the "range type" system catalog (pg_range) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_range.h diff --git a/src/include/catalog/pg_replication_origin.h b/src/include/catalog/pg_replication_origin.h index 4c7d9a1765a2f..bd44968f88676 100644 --- a/src/include/catalog/pg_replication_origin.h +++ b/src/include/catalog/pg_replication_origin.h @@ -4,7 +4,7 @@ * definition of the "replication origin" system catalog * (pg_replication_origin) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_replication_origin.h diff --git a/src/include/catalog/pg_rewrite.h b/src/include/catalog/pg_rewrite.h index 9b1d8a375adaa..61615cea21026 100644 --- a/src/include/catalog/pg_rewrite.h +++ b/src/include/catalog/pg_rewrite.h @@ -7,7 +7,7 @@ * --- ie, rule names are only unique among the rules of a given table. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_rewrite.h diff --git a/src/include/catalog/pg_seclabel.h b/src/include/catalog/pg_seclabel.h index 946f2b5bfaa5f..caf67ab760601 100644 --- a/src/include/catalog/pg_seclabel.h +++ b/src/include/catalog/pg_seclabel.h @@ -3,7 +3,7 @@ * pg_seclabel.h * definition of the "security label" system catalog (pg_seclabel) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_seclabel.h diff --git a/src/include/catalog/pg_sequence.h b/src/include/catalog/pg_sequence.h index 4ee91cd7e3e27..61fe5a1930ce3 100644 --- a/src/include/catalog/pg_sequence.h +++ b/src/include/catalog/pg_sequence.h @@ -3,7 +3,7 @@ * pg_sequence.h * definition of the "sequence" system catalog (pg_sequence) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_sequence.h diff --git a/src/include/catalog/pg_shdepend.h b/src/include/catalog/pg_shdepend.h index d0faa51ca9eed..f5863954e9fbf 100644 --- a/src/include/catalog/pg_shdepend.h +++ b/src/include/catalog/pg_shdepend.h @@ -12,7 +12,7 @@ * from a relation to its database. Currently, only dependencies on roles * are explicitly stored in pg_shdepend. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_shdepend.h diff --git a/src/include/catalog/pg_shdescription.h b/src/include/catalog/pg_shdescription.h index 81abd8debf140..5ecb95c00cf25 100644 --- a/src/include/catalog/pg_shdescription.h +++ b/src/include/catalog/pg_shdescription.h @@ -16,7 +16,7 @@ * across tables. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_shdescription.h diff --git a/src/include/catalog/pg_shseclabel.h b/src/include/catalog/pg_shseclabel.h index 592ae72356560..dd8900316913f 100644 --- a/src/include/catalog/pg_shseclabel.h +++ b/src/include/catalog/pg_shseclabel.h @@ -3,7 +3,7 @@ * pg_shseclabel.h * definition of the "shared security label" system catalog (pg_shseclabel) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_shseclabel.h diff --git a/src/include/catalog/pg_statistic.h b/src/include/catalog/pg_statistic.h index fb819734a1c0d..3f1534c29a26f 100644 --- a/src/include/catalog/pg_statistic.h +++ b/src/include/catalog/pg_statistic.h @@ -4,7 +4,7 @@ * definition of the "statistics" system catalog (pg_statistic) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_statistic.h diff --git a/src/include/catalog/pg_statistic_ext.h b/src/include/catalog/pg_statistic_ext.h index 61d402c600e0a..99f6cea0a5349 100644 --- a/src/include/catalog/pg_statistic_ext.h +++ b/src/include/catalog/pg_statistic_ext.h @@ -8,7 +8,7 @@ * objects, created by CREATE STATISTICS, but not the actual statistical data, * created by running ANALYZE. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_statistic_ext.h diff --git a/src/include/catalog/pg_statistic_ext_data.h b/src/include/catalog/pg_statistic_ext_data.h index c9515df117a41..e0aa152f7b648 100644 --- a/src/include/catalog/pg_statistic_ext_data.h +++ b/src/include/catalog/pg_statistic_ext_data.h @@ -6,7 +6,7 @@ * * This catalog stores the statistical data for extended statistics objects. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_statistic_ext_data.h diff --git a/src/include/catalog/pg_subscription.h b/src/include/catalog/pg_subscription.h index 3fa02af7038b6..e3618028f7eed 100644 --- a/src/include/catalog/pg_subscription.h +++ b/src/include/catalog/pg_subscription.h @@ -3,7 +3,7 @@ * pg_subscription.h * definition of the "subscription" system catalog (pg_subscription) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_subscription.h diff --git a/src/include/catalog/pg_subscription_rel.h b/src/include/catalog/pg_subscription_rel.h index acc29265b2428..06663b9f16cd1 100644 --- a/src/include/catalog/pg_subscription_rel.h +++ b/src/include/catalog/pg_subscription_rel.h @@ -4,7 +4,7 @@ * definition of the system catalog containing the state for each * replicated table in each subscription (pg_subscription_rel) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_subscription_rel.h diff --git a/src/include/catalog/pg_tablespace.dat b/src/include/catalog/pg_tablespace.dat index bb0dec08ef224..212a0ad07fb5f 100644 --- a/src/include/catalog/pg_tablespace.dat +++ b/src/include/catalog/pg_tablespace.dat @@ -3,7 +3,7 @@ # pg_tablespace.dat # Initial contents of the pg_tablespace system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_tablespace.dat diff --git a/src/include/catalog/pg_tablespace.h b/src/include/catalog/pg_tablespace.h index 9787c759861c9..ff92e20c5bfe3 100644 --- a/src/include/catalog/pg_tablespace.h +++ b/src/include/catalog/pg_tablespace.h @@ -4,7 +4,7 @@ * definition of the "tablespace" system catalog (pg_tablespace) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_tablespace.h diff --git a/src/include/catalog/pg_transform.h b/src/include/catalog/pg_transform.h index 8efba2f7e26f5..474baf35473fb 100644 --- a/src/include/catalog/pg_transform.h +++ b/src/include/catalog/pg_transform.h @@ -4,7 +4,7 @@ * definition of the "transform" system catalog (pg_transform) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_transform.h diff --git a/src/include/catalog/pg_trigger.h b/src/include/catalog/pg_trigger.h index abd4bee75fdce..9afea78900d9e 100644 --- a/src/include/catalog/pg_trigger.h +++ b/src/include/catalog/pg_trigger.h @@ -4,7 +4,7 @@ * definition of the "trigger" system catalog (pg_trigger) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_trigger.h diff --git a/src/include/catalog/pg_ts_config.dat b/src/include/catalog/pg_ts_config.dat index 44281675db784..f88d8991993e0 100644 --- a/src/include/catalog/pg_ts_config.dat +++ b/src/include/catalog/pg_ts_config.dat @@ -3,7 +3,7 @@ # pg_ts_config.dat # Initial contents of the pg_ts_config system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_ts_config.dat diff --git a/src/include/catalog/pg_ts_config.h b/src/include/catalog/pg_ts_config.h index 3d83de2e0cdb1..aef7da0f76f6f 100644 --- a/src/include/catalog/pg_ts_config.h +++ b/src/include/catalog/pg_ts_config.h @@ -5,7 +5,7 @@ * (pg_ts_config) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_ts_config.h diff --git a/src/include/catalog/pg_ts_config_map.dat b/src/include/catalog/pg_ts_config_map.dat index f3a593326eef2..cacfd125cf226 100644 --- a/src/include/catalog/pg_ts_config_map.dat +++ b/src/include/catalog/pg_ts_config_map.dat @@ -3,7 +3,7 @@ # pg_ts_config_map.dat # Initial contents of the pg_ts_config_map system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_ts_config_map.dat diff --git a/src/include/catalog/pg_ts_config_map.h b/src/include/catalog/pg_ts_config_map.h index caa45710951ba..95901a94067d0 100644 --- a/src/include/catalog/pg_ts_config_map.h +++ b/src/include/catalog/pg_ts_config_map.h @@ -5,7 +5,7 @@ * (pg_ts_config_map) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_ts_config_map.h diff --git a/src/include/catalog/pg_ts_dict.dat b/src/include/catalog/pg_ts_dict.dat index abeec0ccaee94..4d39bb8c36f1c 100644 --- a/src/include/catalog/pg_ts_dict.dat +++ b/src/include/catalog/pg_ts_dict.dat @@ -3,7 +3,7 @@ # pg_ts_dict.dat # Initial contents of the pg_ts_dict system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_ts_dict.dat diff --git a/src/include/catalog/pg_ts_dict.h b/src/include/catalog/pg_ts_dict.h index 9af090f4bda91..814d0d4407a36 100644 --- a/src/include/catalog/pg_ts_dict.h +++ b/src/include/catalog/pg_ts_dict.h @@ -4,7 +4,7 @@ * definition of the "text search dictionary" system catalog (pg_ts_dict) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_ts_dict.h diff --git a/src/include/catalog/pg_ts_parser.dat b/src/include/catalog/pg_ts_parser.dat index f23aa8c5411ed..a2b7cf10a621e 100644 --- a/src/include/catalog/pg_ts_parser.dat +++ b/src/include/catalog/pg_ts_parser.dat @@ -3,7 +3,7 @@ # pg_ts_parser.dat # Initial contents of the pg_ts_parser system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_ts_parser.dat diff --git a/src/include/catalog/pg_ts_parser.h b/src/include/catalog/pg_ts_parser.h index 54e57c0db654d..57480ebfaf25a 100644 --- a/src/include/catalog/pg_ts_parser.h +++ b/src/include/catalog/pg_ts_parser.h @@ -4,7 +4,7 @@ * definition of the "text search parser" system catalog (pg_ts_parser) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_ts_parser.h diff --git a/src/include/catalog/pg_ts_template.dat b/src/include/catalog/pg_ts_template.dat index 297a8b38fc9b2..0bdbcac7b25d4 100644 --- a/src/include/catalog/pg_ts_template.dat +++ b/src/include/catalog/pg_ts_template.dat @@ -3,7 +3,7 @@ # pg_ts_template.dat # Initial contents of the pg_ts_template system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_ts_template.dat diff --git a/src/include/catalog/pg_ts_template.h b/src/include/catalog/pg_ts_template.h index 548e4c2088f90..c1c7fedbe704f 100644 --- a/src/include/catalog/pg_ts_template.h +++ b/src/include/catalog/pg_ts_template.h @@ -4,7 +4,7 @@ * definition of the "text search template" system catalog (pg_ts_template) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_ts_template.h diff --git a/src/include/catalog/pg_type.dat b/src/include/catalog/pg_type.dat index 62018f063a839..49dc3e18e011f 100644 --- a/src/include/catalog/pg_type.dat +++ b/src/include/catalog/pg_type.dat @@ -3,7 +3,7 @@ # pg_type.dat # Initial contents of the pg_type system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_type.dat diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index 545b789608a03..37345bec00e9e 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -4,7 +4,7 @@ * definition of the "type" system catalog (pg_type) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_type.h diff --git a/src/include/catalog/pg_user_mapping.h b/src/include/catalog/pg_user_mapping.h index c71d8cdd2a3e1..3589125015041 100644 --- a/src/include/catalog/pg_user_mapping.h +++ b/src/include/catalog/pg_user_mapping.h @@ -3,7 +3,7 @@ * pg_user_mapping.h * definition of the "user mapping" system catalog (pg_user_mapping) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_user_mapping.h diff --git a/src/include/catalog/reformat_dat_file.pl b/src/include/catalog/reformat_dat_file.pl index 1cadbfd9f4659..c2631b1afcde3 100755 --- a/src/include/catalog/reformat_dat_file.pl +++ b/src/include/catalog/reformat_dat_file.pl @@ -10,7 +10,7 @@ # in the same order as the columns of the corresponding catalog. # Comments and blank lines are preserved. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/reformat_dat_file.pl diff --git a/src/include/catalog/renumber_oids.pl b/src/include/catalog/renumber_oids.pl index bd99426c92f01..52c32dc961024 100755 --- a/src/include/catalog/renumber_oids.pl +++ b/src/include/catalog/renumber_oids.pl @@ -8,7 +8,7 @@ # Note: This does not reformat the .dat files, so you may want # to run reformat_dat_file.pl afterwards. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/renumber_oids.pl diff --git a/src/include/catalog/storage.h b/src/include/catalog/storage.h index 30c38e0ca6a43..0ab32b44e9107 100644 --- a/src/include/catalog/storage.h +++ b/src/include/catalog/storage.h @@ -4,7 +4,7 @@ * prototypes for functions in backend/catalog/storage.c * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/storage.h diff --git a/src/include/catalog/storage_xlog.h b/src/include/catalog/storage_xlog.h index 7b21cab2e0a06..f0814f14581bf 100644 --- a/src/include/catalog/storage_xlog.h +++ b/src/include/catalog/storage_xlog.h @@ -4,7 +4,7 @@ * prototypes for XLog support for backend/catalog/storage.c * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/storage_xlog.h diff --git a/src/include/catalog/toasting.h b/src/include/catalog/toasting.h index a80c620c5b191..f3fa85f64e547 100644 --- a/src/include/catalog/toasting.h +++ b/src/include/catalog/toasting.h @@ -4,7 +4,7 @@ * This file provides some definitions to support creation of toast tables * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/toasting.h diff --git a/src/include/catalog/unused_oids b/src/include/catalog/unused_oids index 80fff55078ab3..5b7ce5f5bebdd 100755 --- a/src/include/catalog/unused_oids +++ b/src/include/catalog/unused_oids @@ -11,7 +11,7 @@ # to take over what was intended as expansion space for something # else. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/unused_oids diff --git a/src/include/commands/alter.h b/src/include/commands/alter.h index f9d6ba13c9248..7b12e9adf6393 100644 --- a/src/include/commands/alter.h +++ b/src/include/commands/alter.h @@ -4,7 +4,7 @@ * prototypes for commands/alter.c * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/alter.h diff --git a/src/include/commands/async.h b/src/include/commands/async.h index 4c35394f818c4..9217f66b91e79 100644 --- a/src/include/commands/async.h +++ b/src/include/commands/async.h @@ -3,7 +3,7 @@ * async.h * Asynchronous notification: NOTIFY, LISTEN, UNLISTEN * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/async.h diff --git a/src/include/commands/cluster.h b/src/include/commands/cluster.h index 7cfb37c9b2be5..401a0827aecff 100644 --- a/src/include/commands/cluster.h +++ b/src/include/commands/cluster.h @@ -3,7 +3,7 @@ * cluster.h * header file for postgres cluster command stuff * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994-5, Regents of the University of California * * src/include/commands/cluster.h diff --git a/src/include/commands/collationcmds.h b/src/include/commands/collationcmds.h index 3e1c16ac7f056..4e690458805de 100644 --- a/src/include/commands/collationcmds.h +++ b/src/include/commands/collationcmds.h @@ -4,7 +4,7 @@ * prototypes for collationcmds.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/collationcmds.h diff --git a/src/include/commands/comment.h b/src/include/commands/comment.h index 840936eefa999..3a5f725637261 100644 --- a/src/include/commands/comment.h +++ b/src/include/commands/comment.h @@ -7,7 +7,7 @@ * * Prototypes for functions in commands/comment.c * - * Copyright (c) 1999-2020, PostgreSQL Global Development Group + * Copyright (c) 1999-2021, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/include/commands/conversioncmds.h b/src/include/commands/conversioncmds.h index 543d87470427f..04385381e8198 100644 --- a/src/include/commands/conversioncmds.h +++ b/src/include/commands/conversioncmds.h @@ -4,7 +4,7 @@ * prototypes for conversioncmds.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/conversioncmds.h diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h index 127a3c61e2835..8c4748e33d6f7 100644 --- a/src/include/commands/copy.h +++ b/src/include/commands/copy.h @@ -4,7 +4,7 @@ * Definitions for using the POSTGRES copy command. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/copy.h diff --git a/src/include/commands/copyfrom_internal.h b/src/include/commands/copyfrom_internal.h index c15ea803c329f..5401a966d2707 100644 --- a/src/include/commands/copyfrom_internal.h +++ b/src/include/commands/copyfrom_internal.h @@ -4,7 +4,7 @@ * Internal definitions for COPY FROM command. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/copyfrom_internal.h diff --git a/src/include/commands/createas.h b/src/include/commands/createas.h index d8cfb625228fc..ad5054d116b4c 100644 --- a/src/include/commands/createas.h +++ b/src/include/commands/createas.h @@ -4,7 +4,7 @@ * prototypes for createas.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/createas.h diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h index fb8ccfdbf53d7..29b6206f1b097 100644 --- a/src/include/commands/dbcommands.h +++ b/src/include/commands/dbcommands.h @@ -4,7 +4,7 @@ * Database management commands (create/drop database). * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/dbcommands.h diff --git a/src/include/commands/dbcommands_xlog.h b/src/include/commands/dbcommands_xlog.h index 7438d55ae7f52..f5ed76267780c 100644 --- a/src/include/commands/dbcommands_xlog.h +++ b/src/include/commands/dbcommands_xlog.h @@ -4,7 +4,7 @@ * Database resource manager XLOG definitions (create/drop database). * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/dbcommands_xlog.h diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index 1133ae1143716..e2d2a77ca49d5 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -4,7 +4,7 @@ * POSTGRES define and remove utility definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/defrem.h diff --git a/src/include/commands/discard.h b/src/include/commands/discard.h index a4b0c642df9d1..54b9dbba070e8 100644 --- a/src/include/commands/discard.h +++ b/src/include/commands/discard.h @@ -4,7 +4,7 @@ * prototypes for discard.c. * * - * Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Copyright (c) 1996-2021, PostgreSQL Global Development Group * * src/include/commands/discard.h * diff --git a/src/include/commands/event_trigger.h b/src/include/commands/event_trigger.h index 407fd6a97868d..c11bf2d781094 100644 --- a/src/include/commands/event_trigger.h +++ b/src/include/commands/event_trigger.h @@ -3,7 +3,7 @@ * event_trigger.h * Declarations for command trigger handling. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/event_trigger.h diff --git a/src/include/commands/explain.h b/src/include/commands/explain.h index ba661d32a6309..e94d9e49cf6be 100644 --- a/src/include/commands/explain.h +++ b/src/include/commands/explain.h @@ -3,7 +3,7 @@ * explain.h * prototypes for explain.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994-5, Regents of the University of California * * src/include/commands/explain.h diff --git a/src/include/commands/extension.h b/src/include/commands/extension.h index 8b06df02a7209..24dbf86e9702b 100644 --- a/src/include/commands/extension.h +++ b/src/include/commands/extension.h @@ -4,7 +4,7 @@ * Extension management commands (create/drop extension). * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/extension.h diff --git a/src/include/commands/lockcmds.h b/src/include/commands/lockcmds.h index 552ff78e63c89..c005dee7ed51f 100644 --- a/src/include/commands/lockcmds.h +++ b/src/include/commands/lockcmds.h @@ -4,7 +4,7 @@ * prototypes for lockcmds.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/lockcmds.h diff --git a/src/include/commands/matview.h b/src/include/commands/matview.h index 3ea4f5c80b963..214b1c1df6fef 100644 --- a/src/include/commands/matview.h +++ b/src/include/commands/matview.h @@ -4,7 +4,7 @@ * prototypes for matview.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/matview.h diff --git a/src/include/commands/policy.h b/src/include/commands/policy.h index 946ce802a4d46..116af689bd6d3 100644 --- a/src/include/commands/policy.h +++ b/src/include/commands/policy.h @@ -4,7 +4,7 @@ * prototypes for policy.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/policy.h diff --git a/src/include/commands/portalcmds.h b/src/include/commands/portalcmds.h index 5f64b0a674f1a..5d5e7666d209c 100644 --- a/src/include/commands/portalcmds.h +++ b/src/include/commands/portalcmds.h @@ -4,7 +4,7 @@ * prototypes for portalcmds.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/portalcmds.h diff --git a/src/include/commands/prepare.h b/src/include/commands/prepare.h index 4fcf2406c1806..93525815164f3 100644 --- a/src/include/commands/prepare.h +++ b/src/include/commands/prepare.h @@ -4,7 +4,7 @@ * PREPARE, EXECUTE and DEALLOCATE commands, and prepared-stmt storage * * - * Copyright (c) 2002-2020, PostgreSQL Global Development Group + * Copyright (c) 2002-2021, PostgreSQL Global Development Group * * src/include/commands/prepare.h * diff --git a/src/include/commands/proclang.h b/src/include/commands/proclang.h index d566a121f0ec7..16e857fd9029b 100644 --- a/src/include/commands/proclang.h +++ b/src/include/commands/proclang.h @@ -3,7 +3,7 @@ * proclang.h * prototypes for proclang.c. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/proclang.h diff --git a/src/include/commands/progress.h b/src/include/commands/progress.h index 36b073e67757b..49a158aabbf92 100644 --- a/src/include/commands/progress.h +++ b/src/include/commands/progress.h @@ -7,7 +7,7 @@ * constants, you probably also need to update the views based on them * in system_views.sql. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/progress.h diff --git a/src/include/commands/publicationcmds.h b/src/include/commands/publicationcmds.h index c6b286245f4ab..00e2e626e6ce3 100644 --- a/src/include/commands/publicationcmds.h +++ b/src/include/commands/publicationcmds.h @@ -4,7 +4,7 @@ * prototypes for publicationcmds.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/publicationcmds.h diff --git a/src/include/commands/schemacmds.h b/src/include/commands/schemacmds.h index e0139a8ea627b..25f4876f99820 100644 --- a/src/include/commands/schemacmds.h +++ b/src/include/commands/schemacmds.h @@ -4,7 +4,7 @@ * prototypes for schemacmds.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/schemacmds.h diff --git a/src/include/commands/seclabel.h b/src/include/commands/seclabel.h index 42fe4c06b478c..40e284e8fcfa8 100644 --- a/src/include/commands/seclabel.h +++ b/src/include/commands/seclabel.h @@ -3,7 +3,7 @@ * * Prototypes for functions in commands/seclabel.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California */ #ifndef SECLABEL_H diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h index e2638abf0ee8a..40544dd4c705f 100644 --- a/src/include/commands/sequence.h +++ b/src/include/commands/sequence.h @@ -3,7 +3,7 @@ * sequence.h * prototypes for sequence.c. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/sequence.h diff --git a/src/include/commands/subscriptioncmds.h b/src/include/commands/subscriptioncmds.h index 804e47b2cbd6b..a81865079d1c7 100644 --- a/src/include/commands/subscriptioncmds.h +++ b/src/include/commands/subscriptioncmds.h @@ -4,7 +4,7 @@ * prototypes for subscriptioncmds.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/subscriptioncmds.h diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h index c1581ad178eeb..08c463d3c431d 100644 --- a/src/include/commands/tablecmds.h +++ b/src/include/commands/tablecmds.h @@ -4,7 +4,7 @@ * prototypes for tablecmds.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/tablecmds.h diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h index fd1b28fca2268..49cfc8479a611 100644 --- a/src/include/commands/tablespace.h +++ b/src/include/commands/tablespace.h @@ -4,7 +4,7 @@ * Tablespace management commands (create/drop tablespace). * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/tablespace.h diff --git a/src/include/commands/trigger.h b/src/include/commands/trigger.h index 244540d90b96a..9e557cfbce330 100644 --- a/src/include/commands/trigger.h +++ b/src/include/commands/trigger.h @@ -3,7 +3,7 @@ * trigger.h * Declarations for trigger handling. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/trigger.h diff --git a/src/include/commands/typecmds.h b/src/include/commands/typecmds.h index 989914dfe1131..880679127b5e2 100644 --- a/src/include/commands/typecmds.h +++ b/src/include/commands/typecmds.h @@ -4,7 +4,7 @@ * prototypes for typecmds.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/typecmds.h diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index a4cd7214009ca..857509287d767 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -4,7 +4,7 @@ * header file for postgres vacuum cleaner and statistics analyzer * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/vacuum.h diff --git a/src/include/commands/variable.h b/src/include/commands/variable.h index 2749ff19d0a32..483bc7919f826 100644 --- a/src/include/commands/variable.h +++ b/src/include/commands/variable.h @@ -2,7 +2,7 @@ * variable.h * Routines for handling specialized SET variables. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/variable.h diff --git a/src/include/commands/view.h b/src/include/commands/view.h index 44a16d87bb741..d28f8176a4320 100644 --- a/src/include/commands/view.h +++ b/src/include/commands/view.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/commands/view.h diff --git a/src/include/common/archive.h b/src/include/common/archive.h index b269910f03c72..b5fd143be816c 100644 --- a/src/include/common/archive.h +++ b/src/include/common/archive.h @@ -3,7 +3,7 @@ * archive.h * Common WAL archive routines * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/common/archive.h diff --git a/src/include/common/base64.h b/src/include/common/base64.h index 5de44992aacc0..3b9705613fcd1 100644 --- a/src/include/common/base64.h +++ b/src/include/common/base64.h @@ -3,7 +3,7 @@ * Encoding and decoding routines for base64 without whitespace * support. * - * Portions Copyright (c) 2001-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2001-2021, PostgreSQL Global Development Group * * src/include/common/base64.h */ diff --git a/src/include/common/checksum_helper.h b/src/include/common/checksum_helper.h index b07a34e7e4989..ebdf1ccf447f1 100644 --- a/src/include/common/checksum_helper.h +++ b/src/include/common/checksum_helper.h @@ -3,7 +3,7 @@ * checksum_helper.h * Compute a checksum of any of various types using common routines * - * Portions Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2016-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/include/common/checksum_helper.h diff --git a/src/include/common/config_info.h b/src/include/common/config_info.h index f36b7838d0fb4..814f4d3d1bbc7 100644 --- a/src/include/common/config_info.h +++ b/src/include/common/config_info.h @@ -2,7 +2,7 @@ * config_info.h * Common code for pg_config output * - * Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Copyright (c) 2016-2021, PostgreSQL Global Development Group * * src/include/common/config_info.h */ diff --git a/src/include/common/connect.h b/src/include/common/connect.h index 2cc5d7dd251b5..71c2d6e72c496 100644 --- a/src/include/common/connect.h +++ b/src/include/common/connect.h @@ -3,7 +3,7 @@ * Interfaces in support of FE/BE connections. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/common/connect.h diff --git a/src/include/common/controldata_utils.h b/src/include/common/controldata_utils.h index bf3c1f864c286..dea78113d0a94 100644 --- a/src/include/common/controldata_utils.h +++ b/src/include/common/controldata_utils.h @@ -2,7 +2,7 @@ * controldata_utils.h * Common code for pg_controldata output * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/common/controldata_utils.h diff --git a/src/include/common/cryptohash.h b/src/include/common/cryptohash.h index 6ead1cb8e5bc1..4c3df8e5ae64b 100644 --- a/src/include/common/cryptohash.h +++ b/src/include/common/cryptohash.h @@ -3,7 +3,7 @@ * cryptohash.h * Generic headers for cryptographic hash functions. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/common/fe_memutils.h b/src/include/common/fe_memutils.h index b2badd3172b2c..a8b59f5db73e8 100644 --- a/src/include/common/fe_memutils.h +++ b/src/include/common/fe_memutils.h @@ -2,7 +2,7 @@ * fe_memutils.h * memory management support for frontend code * - * Copyright (c) 2003-2020, PostgreSQL Global Development Group + * Copyright (c) 2003-2021, PostgreSQL Global Development Group * * src/include/common/fe_memutils.h */ diff --git a/src/include/common/file_perm.h b/src/include/common/file_perm.h index d87881693c4b4..ba1823a0839bc 100644 --- a/src/include/common/file_perm.h +++ b/src/include/common/file_perm.h @@ -3,7 +3,7 @@ * File and directory permission definitions * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/common/file_perm.h diff --git a/src/include/common/file_utils.h b/src/include/common/file_utils.h index fef846485f836..978a57460a34f 100644 --- a/src/include/common/file_utils.h +++ b/src/include/common/file_utils.h @@ -3,7 +3,7 @@ * Assorted utility functions to work on files. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/common/file_utils.h diff --git a/src/include/common/hashfn.h b/src/include/common/hashfn.h index 6ecc864f840ec..c634cc067a12b 100644 --- a/src/include/common/hashfn.h +++ b/src/include/common/hashfn.h @@ -1,7 +1,7 @@ /* * Utilities for working with hash values. * - * Portions Copyright (c) 2017-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2017-2021, PostgreSQL Global Development Group */ #ifndef HASHFN_H diff --git a/src/include/common/hex_decode.h b/src/include/common/hex_decode.h index 1f99f069b29c4..29ab2484585d4 100644 --- a/src/include/common/hex_decode.h +++ b/src/include/common/hex_decode.h @@ -2,7 +2,7 @@ * hex_decode.h * hex decoding * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/common/hex_decode.h diff --git a/src/include/common/int.h b/src/include/common/int.h index a2972218e7216..079954d7f0b13 100644 --- a/src/include/common/int.h +++ b/src/include/common/int.h @@ -11,7 +11,7 @@ * the 64 bit cases can be considerably faster with intrinsics. In case no * intrinsics are available 128 bit math is used where available. * - * Copyright (c) 2017-2020, PostgreSQL Global Development Group + * Copyright (c) 2017-2021, PostgreSQL Global Development Group * * src/include/common/int.h * diff --git a/src/include/common/int128.h b/src/include/common/int128.h index a83edc710c5c0..01aedf6d1c155 100644 --- a/src/include/common/int128.h +++ b/src/include/common/int128.h @@ -8,7 +8,7 @@ * * See src/tools/testint128.c for a simple test harness for this file. * - * Copyright (c) 2017-2020, PostgreSQL Global Development Group + * Copyright (c) 2017-2021, PostgreSQL Global Development Group * * src/include/common/int128.h * diff --git a/src/include/common/ip.h b/src/include/common/ip.h index 34c78eb5f1da3..27f8c4ccd940d 100644 --- a/src/include/common/ip.h +++ b/src/include/common/ip.h @@ -5,7 +5,7 @@ * * These definitions are used by both frontend and backend code. * - * Copyright (c) 2003-2020, PostgreSQL Global Development Group + * Copyright (c) 2003-2021, PostgreSQL Global Development Group * * src/include/common/ip.h * diff --git a/src/include/common/jsonapi.h b/src/include/common/jsonapi.h index 1fee0ea81e47a..03331f6d13fad 100644 --- a/src/include/common/jsonapi.h +++ b/src/include/common/jsonapi.h @@ -3,7 +3,7 @@ * jsonapi.h * Declarations for JSON API support. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/common/jsonapi.h diff --git a/src/include/common/keywords.h b/src/include/common/keywords.h index c9f9a9f991a7b..19e4eda8f9e57 100644 --- a/src/include/common/keywords.h +++ b/src/include/common/keywords.h @@ -4,7 +4,7 @@ * PostgreSQL's list of SQL keywords * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/common/keywords.h diff --git a/src/include/common/kwlookup.h b/src/include/common/kwlookup.h index 9c0c7f88d89b8..70d4b8e51bc31 100644 --- a/src/include/common/kwlookup.h +++ b/src/include/common/kwlookup.h @@ -4,7 +4,7 @@ * Key word lookup for PostgreSQL * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/common/kwlookup.h diff --git a/src/include/common/link-canary.h b/src/include/common/link-canary.h index e8665dc140090..acb05b65d9ff8 100644 --- a/src/include/common/link-canary.h +++ b/src/include/common/link-canary.h @@ -3,7 +3,7 @@ * link-canary.h * Detect whether src/common functions came from frontend or backend. * - * Copyright (c) 2018-2020, PostgreSQL Global Development Group + * Copyright (c) 2018-2021, PostgreSQL Global Development Group * * src/include/common/link-canary.h * diff --git a/src/include/common/logging.h b/src/include/common/logging.h index 3205b8fef9b70..a71cf8424946e 100644 --- a/src/include/common/logging.h +++ b/src/include/common/logging.h @@ -1,7 +1,7 @@ /*------------------------------------------------------------------------- * Logging framework for frontend programs * - * Copyright (c) 2018-2020, PostgreSQL Global Development Group + * Copyright (c) 2018-2021, PostgreSQL Global Development Group * * src/include/common/logging.h * diff --git a/src/include/common/md5.h b/src/include/common/md5.h index 5dac70cbc5024..6d100f5cfc2c6 100644 --- a/src/include/common/md5.h +++ b/src/include/common/md5.h @@ -6,7 +6,7 @@ * These definitions are needed by both frontend and backend code to work * with MD5-encrypted passwords. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/common/md5.h diff --git a/src/include/common/openssl.h b/src/include/common/openssl.h index 9d1c681d9f845..fcc5b50533eb0 100644 --- a/src/include/common/openssl.h +++ b/src/include/common/openssl.h @@ -3,7 +3,7 @@ * openssl.h * OpenSSL supporting functionality shared between frontend and backend * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/common/relpath.h b/src/include/common/relpath.h index 869cabcc0d2bb..a44be11ca0a46 100644 --- a/src/include/common/relpath.h +++ b/src/include/common/relpath.h @@ -3,7 +3,7 @@ * relpath.h * Declarations for GetRelationPath() and friends * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/common/relpath.h diff --git a/src/include/common/restricted_token.h b/src/include/common/restricted_token.h index 4a93808db4dd1..75455e6d78e27 100644 --- a/src/include/common/restricted_token.h +++ b/src/include/common/restricted_token.h @@ -2,7 +2,7 @@ * restricted_token.h * helper routine to ensure restricted token on Windows * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/common/restricted_token.h diff --git a/src/include/common/saslprep.h b/src/include/common/saslprep.h index 3abf2acce0f35..a2c7a464dbf70 100644 --- a/src/include/common/saslprep.h +++ b/src/include/common/saslprep.h @@ -5,7 +5,7 @@ * * These definitions are used by both frontend and backend code. * - * Copyright (c) 2017-2020, PostgreSQL Global Development Group + * Copyright (c) 2017-2021, PostgreSQL Global Development Group * * src/include/common/saslprep.h * diff --git a/src/include/common/scram-common.h b/src/include/common/scram-common.h index f4a7c60725b31..9d684b41e8e0a 100644 --- a/src/include/common/scram-common.h +++ b/src/include/common/scram-common.h @@ -3,7 +3,7 @@ * scram-common.h * Declarations for helper functions used for SCRAM authentication * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/common/scram-common.h diff --git a/src/include/common/sha2.h b/src/include/common/sha2.h index c8b9096043ff3..f4bae35af10c2 100644 --- a/src/include/common/sha2.h +++ b/src/include/common/sha2.h @@ -3,7 +3,7 @@ * sha2.h * Constants related to SHA224, 256, 384 AND 512. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/common/shortest_dec.h b/src/include/common/shortest_dec.h index a0282318a24e2..c21f39faf5bae 100644 --- a/src/include/common/shortest_dec.h +++ b/src/include/common/shortest_dec.h @@ -2,7 +2,7 @@ * * Ryu floating-point output. * - * Portions Copyright (c) 2018-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2018-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/include/common/shortest_dec.h diff --git a/src/include/common/string.h b/src/include/common/string.h index 655ccc0570818..686c158efe732 100644 --- a/src/include/common/string.h +++ b/src/include/common/string.h @@ -2,7 +2,7 @@ * string.h * string handling helpers * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/common/string.h diff --git a/src/include/common/unicode_norm.h b/src/include/common/unicode_norm.h index 731e05bf7dd63..3c2279000aa8a 100644 --- a/src/include/common/unicode_norm.h +++ b/src/include/common/unicode_norm.h @@ -5,7 +5,7 @@ * * These definitions are used by both frontend and backend code. * - * Copyright (c) 2017-2020, PostgreSQL Global Development Group + * Copyright (c) 2017-2021, PostgreSQL Global Development Group * * src/include/common/unicode_norm.h * diff --git a/src/include/common/unicode_norm_hashfunc.h b/src/include/common/unicode_norm_hashfunc.h index e6acb2a8d0f74..5d0501621c7cf 100644 --- a/src/include/common/unicode_norm_hashfunc.h +++ b/src/include/common/unicode_norm_hashfunc.h @@ -3,7 +3,7 @@ * unicode_norm_hashfunc.h * Perfect hash functions used for Unicode normalization * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/common/unicode_norm_hashfunc.h diff --git a/src/include/common/unicode_norm_table.h b/src/include/common/unicode_norm_table.h index 96d43b893c18a..7da633c33b67b 100644 --- a/src/include/common/unicode_norm_table.h +++ b/src/include/common/unicode_norm_table.h @@ -3,7 +3,7 @@ * unicode_norm_table.h * Composition table used for Unicode normalization * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/common/unicode_norm_table.h diff --git a/src/include/common/username.h b/src/include/common/username.h index 2a7c6c4f0d20f..bd3ee5f72de90 100644 --- a/src/include/common/username.h +++ b/src/include/common/username.h @@ -2,7 +2,7 @@ * username.h * lookup effective username * - * Copyright (c) 2003-2020, PostgreSQL Global Development Group + * Copyright (c) 2003-2021, PostgreSQL Global Development Group * * src/include/common/username.h */ diff --git a/src/include/datatype/timestamp.h b/src/include/datatype/timestamp.h index 6be6d35d1e2c2..99873497a6d6c 100644 --- a/src/include/datatype/timestamp.h +++ b/src/include/datatype/timestamp.h @@ -5,7 +5,7 @@ * * Note: this file must be includable in both frontend and backend contexts. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/datatype/timestamp.h diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h index b4e0a9b7d3d0d..1b7f9865b0a57 100644 --- a/src/include/executor/execExpr.h +++ b/src/include/executor/execExpr.h @@ -4,7 +4,7 @@ * Low level infrastructure related to expression evaluation * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/execExpr.h diff --git a/src/include/executor/execParallel.h b/src/include/executor/execParallel.h index 5a39a5b29c4e6..3888175a2f42b 100644 --- a/src/include/executor/execParallel.h +++ b/src/include/executor/execParallel.h @@ -2,7 +2,7 @@ * execParallel.h * POSTGRES parallel execution interface * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/executor/execPartition.h b/src/include/executor/execPartition.h index 473c4cd84fc64..d30ffde7d92d4 100644 --- a/src/include/executor/execPartition.h +++ b/src/include/executor/execPartition.h @@ -2,7 +2,7 @@ * execPartition.h * POSTGRES partitioning executor interface * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/executor/execdebug.h b/src/include/executor/execdebug.h index 4af6e0013dadc..596c49905e1fc 100644 --- a/src/include/executor/execdebug.h +++ b/src/include/executor/execdebug.h @@ -7,7 +7,7 @@ * for debug printouts, because that's more flexible than printf(). * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/execdebug.h diff --git a/src/include/executor/execdesc.h b/src/include/executor/execdesc.h index b5cead3502d81..017ad87117539 100644 --- a/src/include/executor/execdesc.h +++ b/src/include/executor/execdesc.h @@ -5,7 +5,7 @@ * and related modules. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/execdesc.h diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 0c48d2a519e83..53f431e1ed79f 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -4,7 +4,7 @@ * support for the POSTGRES executor module * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/executor.h diff --git a/src/include/executor/functions.h b/src/include/executor/functions.h index a0db24bde699f..c975a93661e89 100644 --- a/src/include/executor/functions.h +++ b/src/include/executor/functions.h @@ -4,7 +4,7 @@ * Declarations for execution of SQL-language functions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/functions.h diff --git a/src/include/executor/hashjoin.h b/src/include/executor/hashjoin.h index eb5daba36b0ff..d74034f64f821 100644 --- a/src/include/executor/hashjoin.h +++ b/src/include/executor/hashjoin.h @@ -4,7 +4,7 @@ * internal structures for hash joins * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/hashjoin.h diff --git a/src/include/executor/instrument.h b/src/include/executor/instrument.h index 9dc3ecb07d79b..aa8eceda5f411 100644 --- a/src/include/executor/instrument.h +++ b/src/include/executor/instrument.h @@ -4,7 +4,7 @@ * definitions for run-time statistics collection * * - * Copyright (c) 2001-2020, PostgreSQL Global Development Group + * Copyright (c) 2001-2021, PostgreSQL Global Development Group * * src/include/executor/instrument.h * diff --git a/src/include/executor/nodeAgg.h b/src/include/executor/nodeAgg.h index b955169538444..398446d11f877 100644 --- a/src/include/executor/nodeAgg.h +++ b/src/include/executor/nodeAgg.h @@ -4,7 +4,7 @@ * prototypes for nodeAgg.c * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeAgg.h diff --git a/src/include/executor/nodeAppend.h b/src/include/executor/nodeAppend.h index be222ebff6910..cafd410a5daeb 100644 --- a/src/include/executor/nodeAppend.h +++ b/src/include/executor/nodeAppend.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeAppend.h diff --git a/src/include/executor/nodeBitmapAnd.h b/src/include/executor/nodeBitmapAnd.h index 2271bb791d6aa..ac5d4aece6d30 100644 --- a/src/include/executor/nodeBitmapAnd.h +++ b/src/include/executor/nodeBitmapAnd.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeBitmapAnd.h diff --git a/src/include/executor/nodeBitmapHeapscan.h b/src/include/executor/nodeBitmapHeapscan.h index 10228afd13b57..3b0bd5acb8ede 100644 --- a/src/include/executor/nodeBitmapHeapscan.h +++ b/src/include/executor/nodeBitmapHeapscan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeBitmapHeapscan.h diff --git a/src/include/executor/nodeBitmapIndexscan.h b/src/include/executor/nodeBitmapIndexscan.h index 42a24e67c2889..95bf2287013a2 100644 --- a/src/include/executor/nodeBitmapIndexscan.h +++ b/src/include/executor/nodeBitmapIndexscan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeBitmapIndexscan.h diff --git a/src/include/executor/nodeBitmapOr.h b/src/include/executor/nodeBitmapOr.h index 58a7b8cbfa39f..1c1da2f145f6f 100644 --- a/src/include/executor/nodeBitmapOr.h +++ b/src/include/executor/nodeBitmapOr.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeBitmapOr.h diff --git a/src/include/executor/nodeCtescan.h b/src/include/executor/nodeCtescan.h index 3e7555233ad0f..2c33442d7da55 100644 --- a/src/include/executor/nodeCtescan.h +++ b/src/include/executor/nodeCtescan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeCtescan.h diff --git a/src/include/executor/nodeCustom.h b/src/include/executor/nodeCustom.h index 1d5287518bc7a..0be69a505648f 100644 --- a/src/include/executor/nodeCustom.h +++ b/src/include/executor/nodeCustom.h @@ -4,7 +4,7 @@ * * prototypes for CustomScan nodes * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * ------------------------------------------------------------------------ diff --git a/src/include/executor/nodeForeignscan.h b/src/include/executor/nodeForeignscan.h index 326d713ebf4e5..6ae7733e25b00 100644 --- a/src/include/executor/nodeForeignscan.h +++ b/src/include/executor/nodeForeignscan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeForeignscan.h diff --git a/src/include/executor/nodeFunctionscan.h b/src/include/executor/nodeFunctionscan.h index 74e8eefd38be3..8f210a774d473 100644 --- a/src/include/executor/nodeFunctionscan.h +++ b/src/include/executor/nodeFunctionscan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeFunctionscan.h diff --git a/src/include/executor/nodeGather.h b/src/include/executor/nodeGather.h index 105248b786664..e7c92b84c41ba 100644 --- a/src/include/executor/nodeGather.h +++ b/src/include/executor/nodeGather.h @@ -4,7 +4,7 @@ * prototypes for nodeGather.c * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeGather.h diff --git a/src/include/executor/nodeGatherMerge.h b/src/include/executor/nodeGatherMerge.h index a8f960bdfca59..65e72456e4435 100644 --- a/src/include/executor/nodeGatherMerge.h +++ b/src/include/executor/nodeGatherMerge.h @@ -4,7 +4,7 @@ * prototypes for nodeGatherMerge.c * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeGatherMerge.h diff --git a/src/include/executor/nodeGroup.h b/src/include/executor/nodeGroup.h index 2965c742d528f..8cb2e090e9446 100644 --- a/src/include/executor/nodeGroup.h +++ b/src/include/executor/nodeGroup.h @@ -4,7 +4,7 @@ * prototypes for nodeGroup.c * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeGroup.h diff --git a/src/include/executor/nodeHash.h b/src/include/executor/nodeHash.h index 2db4e2f67267b..3fbe02e80d500 100644 --- a/src/include/executor/nodeHash.h +++ b/src/include/executor/nodeHash.h @@ -4,7 +4,7 @@ * prototypes for nodeHash.c * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeHash.h diff --git a/src/include/executor/nodeHashjoin.h b/src/include/executor/nodeHashjoin.h index dc67162b20d30..7d6541a057ba6 100644 --- a/src/include/executor/nodeHashjoin.h +++ b/src/include/executor/nodeHashjoin.h @@ -4,7 +4,7 @@ * prototypes for nodeHashjoin.c * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeHashjoin.h diff --git a/src/include/executor/nodeIncrementalSort.h b/src/include/executor/nodeIncrementalSort.h index e62c02a4f3007..0e14183356398 100644 --- a/src/include/executor/nodeIncrementalSort.h +++ b/src/include/executor/nodeIncrementalSort.h @@ -2,7 +2,7 @@ * * nodeIncrementalSort.h * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeIncrementalSort.h diff --git a/src/include/executor/nodeIndexonlyscan.h b/src/include/executor/nodeIndexonlyscan.h index 9f1d26fb722ad..bcb266b2b6e6b 100644 --- a/src/include/executor/nodeIndexonlyscan.h +++ b/src/include/executor/nodeIndexonlyscan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeIndexonlyscan.h diff --git a/src/include/executor/nodeIndexscan.h b/src/include/executor/nodeIndexscan.h index 1b6b318a75e1b..70a2cff1990f7 100644 --- a/src/include/executor/nodeIndexscan.h +++ b/src/include/executor/nodeIndexscan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeIndexscan.h diff --git a/src/include/executor/nodeLimit.h b/src/include/executor/nodeLimit.h index cbcb94153dcfc..789871f01f33b 100644 --- a/src/include/executor/nodeLimit.h +++ b/src/include/executor/nodeLimit.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeLimit.h diff --git a/src/include/executor/nodeLockRows.h b/src/include/executor/nodeLockRows.h index 85d0e17fd6c0b..ca4b72a24f10d 100644 --- a/src/include/executor/nodeLockRows.h +++ b/src/include/executor/nodeLockRows.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeLockRows.h diff --git a/src/include/executor/nodeMaterial.h b/src/include/executor/nodeMaterial.h index 99e7cbfc94320..3acfc886cea36 100644 --- a/src/include/executor/nodeMaterial.h +++ b/src/include/executor/nodeMaterial.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeMaterial.h diff --git a/src/include/executor/nodeMergeAppend.h b/src/include/executor/nodeMergeAppend.h index 2c8618930ecb2..eb54c2fb4d87a 100644 --- a/src/include/executor/nodeMergeAppend.h +++ b/src/include/executor/nodeMergeAppend.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeMergeAppend.h diff --git a/src/include/executor/nodeMergejoin.h b/src/include/executor/nodeMergejoin.h index ae8105a5cfd4a..031d67d751fa4 100644 --- a/src/include/executor/nodeMergejoin.h +++ b/src/include/executor/nodeMergejoin.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeMergejoin.h diff --git a/src/include/executor/nodeModifyTable.h b/src/include/executor/nodeModifyTable.h index 46a2dc9511889..83e296553104f 100644 --- a/src/include/executor/nodeModifyTable.h +++ b/src/include/executor/nodeModifyTable.h @@ -3,7 +3,7 @@ * nodeModifyTable.h * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeModifyTable.h diff --git a/src/include/executor/nodeNamedtuplestorescan.h b/src/include/executor/nodeNamedtuplestorescan.h index 6fcf08eea9c65..fd270a5346c64 100644 --- a/src/include/executor/nodeNamedtuplestorescan.h +++ b/src/include/executor/nodeNamedtuplestorescan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeNamedtuplestorescan.h diff --git a/src/include/executor/nodeNestloop.h b/src/include/executor/nodeNestloop.h index 5a048a799fbc4..9f32e92759eb0 100644 --- a/src/include/executor/nodeNestloop.h +++ b/src/include/executor/nodeNestloop.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeNestloop.h diff --git a/src/include/executor/nodeProjectSet.h b/src/include/executor/nodeProjectSet.h index 76e433fa5a415..5852237f1fca9 100644 --- a/src/include/executor/nodeProjectSet.h +++ b/src/include/executor/nodeProjectSet.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeProjectSet.h diff --git a/src/include/executor/nodeRecursiveunion.h b/src/include/executor/nodeRecursiveunion.h index c7253ce4945b1..b1f5f5d8fc9f3 100644 --- a/src/include/executor/nodeRecursiveunion.h +++ b/src/include/executor/nodeRecursiveunion.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeRecursiveunion.h diff --git a/src/include/executor/nodeResult.h b/src/include/executor/nodeResult.h index b86167205658b..197eabac7154d 100644 --- a/src/include/executor/nodeResult.h +++ b/src/include/executor/nodeResult.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeResult.h diff --git a/src/include/executor/nodeSamplescan.h b/src/include/executor/nodeSamplescan.h index c24fca5e353ad..7142a8a2a37cb 100644 --- a/src/include/executor/nodeSamplescan.h +++ b/src/include/executor/nodeSamplescan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeSamplescan.h diff --git a/src/include/executor/nodeSeqscan.h b/src/include/executor/nodeSeqscan.h index 2ef48ceec042e..ef1521ca7bc4b 100644 --- a/src/include/executor/nodeSeqscan.h +++ b/src/include/executor/nodeSeqscan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeSeqscan.h diff --git a/src/include/executor/nodeSetOp.h b/src/include/executor/nodeSetOp.h index a3577b3e3efdc..d40ed74795e9a 100644 --- a/src/include/executor/nodeSetOp.h +++ b/src/include/executor/nodeSetOp.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeSetOp.h diff --git a/src/include/executor/nodeSort.h b/src/include/executor/nodeSort.h index 092555614e8c2..bf9a5229991a8 100644 --- a/src/include/executor/nodeSort.h +++ b/src/include/executor/nodeSort.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeSort.h diff --git a/src/include/executor/nodeSubplan.h b/src/include/executor/nodeSubplan.h index b629af1f5fb92..df136cbb6a433 100644 --- a/src/include/executor/nodeSubplan.h +++ b/src/include/executor/nodeSubplan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeSubplan.h diff --git a/src/include/executor/nodeSubqueryscan.h b/src/include/executor/nodeSubqueryscan.h index 5e237b0a8ce2a..ded12a7d7522b 100644 --- a/src/include/executor/nodeSubqueryscan.h +++ b/src/include/executor/nodeSubqueryscan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeSubqueryscan.h diff --git a/src/include/executor/nodeTableFuncscan.h b/src/include/executor/nodeTableFuncscan.h index 644babc08b9b1..6b64e08a65fdf 100644 --- a/src/include/executor/nodeTableFuncscan.h +++ b/src/include/executor/nodeTableFuncscan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeTableFuncscan.h diff --git a/src/include/executor/nodeTidscan.h b/src/include/executor/nodeTidscan.h index 92a818d85f155..6be5ace6e2094 100644 --- a/src/include/executor/nodeTidscan.h +++ b/src/include/executor/nodeTidscan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeTidscan.h diff --git a/src/include/executor/nodeUnique.h b/src/include/executor/nodeUnique.h index bc653fd56e3dc..1cde34f292908 100644 --- a/src/include/executor/nodeUnique.h +++ b/src/include/executor/nodeUnique.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeUnique.h diff --git a/src/include/executor/nodeValuesscan.h b/src/include/executor/nodeValuesscan.h index 5f2a1d55feba0..1c2a46145aa40 100644 --- a/src/include/executor/nodeValuesscan.h +++ b/src/include/executor/nodeValuesscan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeValuesscan.h diff --git a/src/include/executor/nodeWindowAgg.h b/src/include/executor/nodeWindowAgg.h index 4c53eb0439b7e..f64841c6936df 100644 --- a/src/include/executor/nodeWindowAgg.h +++ b/src/include/executor/nodeWindowAgg.h @@ -4,7 +4,7 @@ * prototypes for nodeWindowAgg.c * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeWindowAgg.h diff --git a/src/include/executor/nodeWorktablescan.h b/src/include/executor/nodeWorktablescan.h index 09ecc490f5a6a..998a731c20f70 100644 --- a/src/include/executor/nodeWorktablescan.h +++ b/src/include/executor/nodeWorktablescan.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/nodeWorktablescan.h diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h index 896ec0a2ad8d2..6e603d007d736 100644 --- a/src/include/executor/spi.h +++ b/src/include/executor/spi.h @@ -3,7 +3,7 @@ * spi.h * Server Programming Interface public declarations * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/spi.h diff --git a/src/include/executor/spi_priv.h b/src/include/executor/spi_priv.h index 6220928bd3401..29a77781a9d57 100644 --- a/src/include/executor/spi_priv.h +++ b/src/include/executor/spi_priv.h @@ -3,7 +3,7 @@ * spi_priv.h * Server Programming Interface private declarations * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/spi_priv.h diff --git a/src/include/executor/tablefunc.h b/src/include/executor/tablefunc.h index 4131056ba0153..17626b00bf042 100644 --- a/src/include/executor/tablefunc.h +++ b/src/include/executor/tablefunc.h @@ -3,7 +3,7 @@ * tablefunc.h * interface for TableFunc executor node * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/tablefunc.h diff --git a/src/include/executor/tqueue.h b/src/include/executor/tqueue.h index 264eb566410d8..ed470f0f5170f 100644 --- a/src/include/executor/tqueue.h +++ b/src/include/executor/tqueue.h @@ -3,7 +3,7 @@ * tqueue.h * Use shm_mq to send & receive tuples between parallel backends * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/tqueue.h diff --git a/src/include/executor/tstoreReceiver.h b/src/include/executor/tstoreReceiver.h index e9461cf914610..1f58b4f599e67 100644 --- a/src/include/executor/tstoreReceiver.h +++ b/src/include/executor/tstoreReceiver.h @@ -4,7 +4,7 @@ * prototypes for tstoreReceiver.c * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/tstoreReceiver.h diff --git a/src/include/executor/tuptable.h b/src/include/executor/tuptable.h index f7df70b5abd58..679e57fbdddce 100644 --- a/src/include/executor/tuptable.h +++ b/src/include/executor/tuptable.h @@ -4,7 +4,7 @@ * tuple table support stuff * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/tuptable.h diff --git a/src/include/fe_utils/archive.h b/src/include/fe_utils/archive.h index a6beaf04ea76b..3e6b291538439 100644 --- a/src/include/fe_utils/archive.h +++ b/src/include/fe_utils/archive.h @@ -3,7 +3,7 @@ * archive.h * Routines to access WAL archives from frontend * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/fe_utils/archive.h diff --git a/src/include/fe_utils/cancel.h b/src/include/fe_utils/cancel.h index 2a1169a97aaab..3a87d1a8090b5 100644 --- a/src/include/fe_utils/cancel.h +++ b/src/include/fe_utils/cancel.h @@ -3,7 +3,7 @@ * Query cancellation support for frontend code * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/fe_utils/cancel.h diff --git a/src/include/fe_utils/conditional.h b/src/include/fe_utils/conditional.h index 999de3efa59c6..c64c655775981 100644 --- a/src/include/fe_utils/conditional.h +++ b/src/include/fe_utils/conditional.h @@ -14,7 +14,7 @@ * a true branch?) so that the interpreter knows whether to execute * code and whether to evaluate conditions. * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/include/fe_utils/conditional.h * diff --git a/src/include/fe_utils/mbprint.h b/src/include/fe_utils/mbprint.h index 1aa718bf58157..df677dc569ae7 100644 --- a/src/include/fe_utils/mbprint.h +++ b/src/include/fe_utils/mbprint.h @@ -3,7 +3,7 @@ * Multibyte character printing support for frontend code * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/fe_utils/mbprint.h diff --git a/src/include/fe_utils/print.h b/src/include/fe_utils/print.h index 9a47efa8de9ca..27ccbd5119f71 100644 --- a/src/include/fe_utils/print.h +++ b/src/include/fe_utils/print.h @@ -3,7 +3,7 @@ * Query-result printing support for frontend code * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/fe_utils/print.h diff --git a/src/include/fe_utils/psqlscan.h b/src/include/fe_utils/psqlscan.h index 91d1091bcc5fb..e55f1fa2136c6 100644 --- a/src/include/fe_utils/psqlscan.h +++ b/src/include/fe_utils/psqlscan.h @@ -10,7 +10,7 @@ * backslash commands. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/fe_utils/psqlscan.h diff --git a/src/include/fe_utils/psqlscan_int.h b/src/include/fe_utils/psqlscan_int.h index 311f80394a49f..2bc3cc4ae7317 100644 --- a/src/include/fe_utils/psqlscan_int.h +++ b/src/include/fe_utils/psqlscan_int.h @@ -34,7 +34,7 @@ * same flex version, or if they don't use the same flex options. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/fe_utils/psqlscan_int.h diff --git a/src/include/fe_utils/recovery_gen.h b/src/include/fe_utils/recovery_gen.h index c8655cd29496c..7ac8953943944 100644 --- a/src/include/fe_utils/recovery_gen.h +++ b/src/include/fe_utils/recovery_gen.h @@ -2,7 +2,7 @@ * * Generator for recovery configuration * - * Portions Copyright (c) 2011-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2011-2021, PostgreSQL Global Development Group * * src/include/fe_utils/recovery_gen.h * diff --git a/src/include/fe_utils/simple_list.h b/src/include/fe_utils/simple_list.h index db04e677f231b..b05b99841e71c 100644 --- a/src/include/fe_utils/simple_list.h +++ b/src/include/fe_utils/simple_list.h @@ -7,7 +7,7 @@ * facilities, but it's all we need in, eg, pg_dump. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/fe_utils/simple_list.h diff --git a/src/include/fe_utils/string_utils.h b/src/include/fe_utils/string_utils.h index 5924d3248a160..c290c302f572e 100644 --- a/src/include/fe_utils/string_utils.h +++ b/src/include/fe_utils/string_utils.h @@ -6,7 +6,7 @@ * assorted contexts. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/fe_utils/string_utils.h diff --git a/src/include/fmgr.h b/src/include/fmgr.h index ce37e342cd000..ab7b85c86e14f 100644 --- a/src/include/fmgr.h +++ b/src/include/fmgr.h @@ -8,7 +8,7 @@ * or call fmgr-callable functions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/fmgr.h diff --git a/src/include/foreign/fdwapi.h b/src/include/foreign/fdwapi.h index 95556dfb15cb5..2953499fb103c 100644 --- a/src/include/foreign/fdwapi.h +++ b/src/include/foreign/fdwapi.h @@ -3,7 +3,7 @@ * fdwapi.h * API for foreign-data wrappers * - * Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Copyright (c) 2010-2021, PostgreSQL Global Development Group * * src/include/foreign/fdwapi.h * diff --git a/src/include/foreign/foreign.h b/src/include/foreign/foreign.h index 5e0cf533fbe4a..8169eb76b1713 100644 --- a/src/include/foreign/foreign.h +++ b/src/include/foreign/foreign.h @@ -4,7 +4,7 @@ * support for foreign-data wrappers, servers and user mappings. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * src/include/foreign/foreign.h * diff --git a/src/include/funcapi.h b/src/include/funcapi.h index 2f46442087e2a..83e6bc2a1fb97 100644 --- a/src/include/funcapi.h +++ b/src/include/funcapi.h @@ -8,7 +8,7 @@ * or call FUNCAPI-callable functions or macros. * * - * Copyright (c) 2002-2020, PostgreSQL Global Development Group + * Copyright (c) 2002-2021, PostgreSQL Global Development Group * * src/include/funcapi.h * diff --git a/src/include/getaddrinfo.h b/src/include/getaddrinfo.h index 38fa3b84e703f..4cf4c4d40506a 100644 --- a/src/include/getaddrinfo.h +++ b/src/include/getaddrinfo.h @@ -13,7 +13,7 @@ * This code will also work on platforms where struct addrinfo is defined * in the system headers but no getaddrinfo() can be located. * - * Copyright (c) 2003-2020, PostgreSQL Global Development Group + * Copyright (c) 2003-2021, PostgreSQL Global Development Group * * src/include/getaddrinfo.h * diff --git a/src/include/getopt_long.h b/src/include/getopt_long.h index 47c49113e5f49..812e2c84bcbe6 100644 --- a/src/include/getopt_long.h +++ b/src/include/getopt_long.h @@ -2,7 +2,7 @@ * Portions Copyright (c) 1987, 1993, 1994 * The Regents of the University of California. All rights reserved. * - * Portions Copyright (c) 2003-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2021, PostgreSQL Global Development Group * * src/include/getopt_long.h */ diff --git a/src/include/jit/jit.h b/src/include/jit/jit.h index 5a77f7d4a01e5..b634df30b98f2 100644 --- a/src/include/jit/jit.h +++ b/src/include/jit/jit.h @@ -2,7 +2,7 @@ * jit.h * Provider independent JIT infrastructure. * - * Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Copyright (c) 2016-2021, PostgreSQL Global Development Group * * src/include/jit/jit.h * diff --git a/src/include/jit/llvmjit.h b/src/include/jit/llvmjit.h index 1c89075eaffe4..a8ba5a4facd21 100644 --- a/src/include/jit/llvmjit.h +++ b/src/include/jit/llvmjit.h @@ -2,7 +2,7 @@ * llvmjit.h * LLVM JIT provider. * - * Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Copyright (c) 2016-2021, PostgreSQL Global Development Group * * src/include/jit/llvmjit.h * diff --git a/src/include/jit/llvmjit_emit.h b/src/include/jit/llvmjit_emit.h index 3142df608b3c6..a9e8d65dfee7e 100644 --- a/src/include/jit/llvmjit_emit.h +++ b/src/include/jit/llvmjit_emit.h @@ -2,7 +2,7 @@ * llvmjit_emit.h * Helpers to make emitting LLVM IR a bit more concise and pgindent proof. * - * Copyright (c) 2018-2020, PostgreSQL Global Development Group + * Copyright (c) 2018-2021, PostgreSQL Global Development Group * * src/include/jit/llvmjit_emit.h */ diff --git a/src/include/lib/binaryheap.h b/src/include/lib/binaryheap.h index 8d5db56468864..5831351ec11b2 100644 --- a/src/include/lib/binaryheap.h +++ b/src/include/lib/binaryheap.h @@ -3,7 +3,7 @@ * * A simple binary heap implementation * - * Portions Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2012-2021, PostgreSQL Global Development Group * * src/include/lib/binaryheap.h */ diff --git a/src/include/lib/bipartite_match.h b/src/include/lib/bipartite_match.h index a4c3e7dcf5ba6..ee65ae2679225 100644 --- a/src/include/lib/bipartite_match.h +++ b/src/include/lib/bipartite_match.h @@ -1,7 +1,7 @@ /* * bipartite_match.h * - * Copyright (c) 2015-2020, PostgreSQL Global Development Group + * Copyright (c) 2015-2021, PostgreSQL Global Development Group * * src/include/lib/bipartite_match.h */ diff --git a/src/include/lib/bloomfilter.h b/src/include/lib/bloomfilter.h index 52343ba40b667..d919dad69b14c 100644 --- a/src/include/lib/bloomfilter.h +++ b/src/include/lib/bloomfilter.h @@ -3,7 +3,7 @@ * bloomfilter.h * Space-efficient set membership testing * - * Copyright (c) 2018-2020, PostgreSQL Global Development Group + * Copyright (c) 2018-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/include/lib/bloomfilter.h diff --git a/src/include/lib/dshash.h b/src/include/lib/dshash.h index b86df68e77df2..c069ec9de7c25 100644 --- a/src/include/lib/dshash.h +++ b/src/include/lib/dshash.h @@ -3,7 +3,7 @@ * dshash.h * Concurrent hash tables backed by dynamic shared memory areas. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/lib/hyperloglog.h b/src/include/lib/hyperloglog.h index dea4138e98c55..42f8917197f4f 100644 --- a/src/include/lib/hyperloglog.h +++ b/src/include/lib/hyperloglog.h @@ -3,7 +3,7 @@ * * A simple HyperLogLog cardinality estimator implementation * - * Portions Copyright (c) 2014-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2014-2021, PostgreSQL Global Development Group * * Based on Hideaki Ohno's C++ implementation. The copyright terms of Ohno's * original version (the MIT license) follow. diff --git a/src/include/lib/ilist.h b/src/include/lib/ilist.h index 98db885f6ff4f..aa196428ed92c 100644 --- a/src/include/lib/ilist.h +++ b/src/include/lib/ilist.h @@ -96,7 +96,7 @@ * } * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/lib/integerset.h b/src/include/lib/integerset.h index 67bf5c5039278..589535f04f71f 100644 --- a/src/include/lib/integerset.h +++ b/src/include/lib/integerset.h @@ -2,7 +2,7 @@ * integerset.h * In-memory data structure to hold a large set of integers efficiently * - * Portions Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2012-2021, PostgreSQL Global Development Group * * src/include/lib/integerset.h */ diff --git a/src/include/lib/knapsack.h b/src/include/lib/knapsack.h index 2d90dc4239ae8..dcfdbe34d9959 100644 --- a/src/include/lib/knapsack.h +++ b/src/include/lib/knapsack.h @@ -1,7 +1,7 @@ /* * knapsack.h * - * Copyright (c) 2017-2020, PostgreSQL Global Development Group + * Copyright (c) 2017-2021, PostgreSQL Global Development Group * * src/include/lib/knapsack.h */ diff --git a/src/include/lib/pairingheap.h b/src/include/lib/pairingheap.h index 7c5c0f765f1d9..73d1a30e80b8d 100644 --- a/src/include/lib/pairingheap.h +++ b/src/include/lib/pairingheap.h @@ -3,7 +3,7 @@ * * A Pairing Heap implementation * - * Portions Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2012-2021, PostgreSQL Global Development Group * * src/include/lib/pairingheap.h */ diff --git a/src/include/lib/qunique.h b/src/include/lib/qunique.h index 95d9fef637a37..d33b219ee41f7 100644 --- a/src/include/lib/qunique.h +++ b/src/include/lib/qunique.h @@ -2,7 +2,7 @@ * * qunique.h * inline array unique functions - * Portions Copyright (c) 2019-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2019-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/include/lib/qunique.h diff --git a/src/include/lib/rbtree.h b/src/include/lib/rbtree.h index cd2c2fdb7d9de..48c60f7ea665b 100644 --- a/src/include/lib/rbtree.h +++ b/src/include/lib/rbtree.h @@ -3,7 +3,7 @@ * rbtree.h * interface for PostgreSQL generic Red-Black binary tree package * - * Copyright (c) 2009-2020, PostgreSQL Global Development Group + * Copyright (c) 2009-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/include/lib/rbtree.h diff --git a/src/include/lib/stringinfo.h b/src/include/lib/stringinfo.h index 5a2a3dbfbc09f..262d79fb3db8d 100644 --- a/src/include/lib/stringinfo.h +++ b/src/include/lib/stringinfo.h @@ -8,7 +8,7 @@ * (null-terminated text) or arbitrary binary data. All storage is allocated * with palloc() (falling back to malloc in frontend code). * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/lib/stringinfo.h diff --git a/src/include/libpq/auth.h b/src/include/libpq/auth.h index 81202e6085896..3610fae3fffef 100644 --- a/src/include/libpq/auth.h +++ b/src/include/libpq/auth.h @@ -4,7 +4,7 @@ * Definitions for network authentication routines * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/auth.h diff --git a/src/include/libpq/be-fsstubs.h b/src/include/libpq/be-fsstubs.h index 4fbd7ccaf66a3..9c15efef4ba38 100644 --- a/src/include/libpq/be-fsstubs.h +++ b/src/include/libpq/be-fsstubs.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/be-fsstubs.h diff --git a/src/include/libpq/be-gssapi-common.h b/src/include/libpq/be-gssapi-common.h index e1c23ac545937..c07d7e7c5ae65 100644 --- a/src/include/libpq/be-gssapi-common.h +++ b/src/include/libpq/be-gssapi-common.h @@ -3,7 +3,7 @@ * be-gssapi-common.h * Definitions for GSSAPI authentication and encryption handling * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/be-gssapi-common.h diff --git a/src/include/libpq/crypt.h b/src/include/libpq/crypt.h index 0c99e6c18a1c2..a4fea6e477af2 100644 --- a/src/include/libpq/crypt.h +++ b/src/include/libpq/crypt.h @@ -3,7 +3,7 @@ * crypt.h * Interface to libpq/crypt.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/crypt.h diff --git a/src/include/libpq/ifaddr.h b/src/include/libpq/ifaddr.h index 4b615182c94a8..e6ef14175faf9 100644 --- a/src/include/libpq/ifaddr.h +++ b/src/include/libpq/ifaddr.h @@ -3,7 +3,7 @@ * ifaddr.h * IP netmask calculations, and enumerating network interfaces. * - * Copyright (c) 2003-2020, PostgreSQL Global Development Group + * Copyright (c) 2003-2021, PostgreSQL Global Development Group * * src/include/libpq/ifaddr.h * diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h index fa778e11921bc..66a8673d93948 100644 --- a/src/include/libpq/libpq-be.h +++ b/src/include/libpq/libpq-be.h @@ -8,7 +8,7 @@ * Structs that need to be client-visible are in pqcomm.h. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/libpq-be.h diff --git a/src/include/libpq/libpq-fs.h b/src/include/libpq/libpq-fs.h index a3c2cd987540c..e61768cdfdd91 100644 --- a/src/include/libpq/libpq-fs.h +++ b/src/include/libpq/libpq-fs.h @@ -4,7 +4,7 @@ * definitions for using Inversion file system routines (ie, large objects) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/libpq-fs.h diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h index b1152475ace58..a55898c85afe1 100644 --- a/src/include/libpq/libpq.h +++ b/src/include/libpq/libpq.h @@ -4,7 +4,7 @@ * POSTGRES LIBPQ buffer structure definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/libpq.h diff --git a/src/include/libpq/pqcomm.h b/src/include/libpq/pqcomm.h index cf967c39871cd..a86b895b268b3 100644 --- a/src/include/libpq/pqcomm.h +++ b/src/include/libpq/pqcomm.h @@ -6,7 +6,7 @@ * NOTE: for historical reasons, this does not correspond to pqcomm.c. * pqcomm.c's routines are declared in libpq.h. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/pqcomm.h diff --git a/src/include/libpq/pqformat.h b/src/include/libpq/pqformat.h index af31e9caba3d6..51f766617d378 100644 --- a/src/include/libpq/pqformat.h +++ b/src/include/libpq/pqformat.h @@ -3,7 +3,7 @@ * pqformat.h * Definitions for formatting and parsing frontend/backend messages * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/pqformat.h diff --git a/src/include/libpq/pqmq.h b/src/include/libpq/pqmq.h index ac0eb789d84e2..31a4723feac92 100644 --- a/src/include/libpq/pqmq.h +++ b/src/include/libpq/pqmq.h @@ -3,7 +3,7 @@ * pqmq.h * Use the frontend/backend protocol for communication over a shm_mq * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/pqmq.h diff --git a/src/include/libpq/pqsignal.h b/src/include/libpq/pqsignal.h index 695c4dc3f833d..1161b138748a9 100644 --- a/src/include/libpq/pqsignal.h +++ b/src/include/libpq/pqsignal.h @@ -3,7 +3,7 @@ * pqsignal.h * Backend signal(2) support (see also src/port/pqsignal.c) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/pqsignal.h diff --git a/src/include/libpq/scram.h b/src/include/libpq/scram.h index 83f1bbc996c75..2c879150dacc7 100644 --- a/src/include/libpq/scram.h +++ b/src/include/libpq/scram.h @@ -3,7 +3,7 @@ * scram.h * Interface to libpq/scram.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/scram.h diff --git a/src/include/mb/pg_wchar.h b/src/include/mb/pg_wchar.h index 494aefc7fab8a..9fc5e67595788 100644 --- a/src/include/mb/pg_wchar.h +++ b/src/include/mb/pg_wchar.h @@ -3,7 +3,7 @@ * pg_wchar.h * multibyte-character support * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/mb/pg_wchar.h diff --git a/src/include/mb/stringinfo_mb.h b/src/include/mb/stringinfo_mb.h index 3bef568eb63fe..ffc371224a583 100644 --- a/src/include/mb/stringinfo_mb.h +++ b/src/include/mb/stringinfo_mb.h @@ -3,7 +3,7 @@ * stringinfo_mb.h * multibyte support for StringInfo * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/mb/stringinfo_mb.h diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index 72e33523984f4..2c71db79c0af2 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -10,7 +10,7 @@ * Over time, this has also become the preferred place for widely known * resource-limitation stuff, such as work_mem and check_stack_depth(). * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/miscadmin.h diff --git a/src/include/nodes/bitmapset.h b/src/include/nodes/bitmapset.h index d113c271ee092..1fd12de6982b6 100644 --- a/src/include/nodes/bitmapset.h +++ b/src/include/nodes/bitmapset.h @@ -11,7 +11,7 @@ * bms_is_empty() in preference to testing for NULL.) * * - * Copyright (c) 2003-2020, PostgreSQL Global Development Group + * Copyright (c) 2003-2021, PostgreSQL Global Development Group * * src/include/nodes/bitmapset.h * diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 61ba4c36662ba..48c3f570fa995 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -4,7 +4,7 @@ * definitions for executor state nodes * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/execnodes.h diff --git a/src/include/nodes/extensible.h b/src/include/nodes/extensible.h index d7bf0ba913404..9e425e5651894 100644 --- a/src/include/nodes/extensible.h +++ b/src/include/nodes/extensible.h @@ -4,7 +4,7 @@ * Definitions for extensible nodes and custom scans * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/extensible.h diff --git a/src/include/nodes/lockoptions.h b/src/include/nodes/lockoptions.h index 56dfe3291bab9..b1524350ea737 100644 --- a/src/include/nodes/lockoptions.h +++ b/src/include/nodes/lockoptions.h @@ -4,7 +4,7 @@ * Common header for some locking-related declarations. * * - * Copyright (c) 2014-2020, PostgreSQL Global Development Group + * Copyright (c) 2014-2021, PostgreSQL Global Development Group * * src/include/nodes/lockoptions.h * diff --git a/src/include/nodes/makefuncs.h b/src/include/nodes/makefuncs.h index 7ebd794713622..48a7ebfe450ec 100644 --- a/src/include/nodes/makefuncs.h +++ b/src/include/nodes/makefuncs.h @@ -4,7 +4,7 @@ * prototypes for the creator functions of various nodes * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/makefuncs.h diff --git a/src/include/nodes/memnodes.h b/src/include/nodes/memnodes.h index c9f2bbcb367e5..9331ef80fd9d1 100644 --- a/src/include/nodes/memnodes.h +++ b/src/include/nodes/memnodes.h @@ -4,7 +4,7 @@ * POSTGRES memory context node definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/memnodes.h diff --git a/src/include/nodes/nodeFuncs.h b/src/include/nodes/nodeFuncs.h index 9cc56eecaa3ac..03a346c01d049 100644 --- a/src/include/nodes/nodeFuncs.h +++ b/src/include/nodes/nodeFuncs.h @@ -3,7 +3,7 @@ * nodeFuncs.h * Various general-purpose manipulations of Node trees * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/nodeFuncs.h diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 3684f87a8831d..fa28b21821fa4 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -4,7 +4,7 @@ * Definitions for tagged nodes. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/nodes.h diff --git a/src/include/nodes/params.h b/src/include/nodes/params.h index 4898d90848ee1..41c21fb502727 100644 --- a/src/include/nodes/params.h +++ b/src/include/nodes/params.h @@ -4,7 +4,7 @@ * Support for finding the values associated with Param nodes. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/params.h diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 48a79a7657348..a0f37e52687af 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -12,7 +12,7 @@ * identifying statement boundaries in multi-statement source strings. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/parsenodes.h diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h index b4059895de50a..cde2637798557 100644 --- a/src/include/nodes/pathnodes.h +++ b/src/include/nodes/pathnodes.h @@ -4,7 +4,7 @@ * Definitions for planner's internal data structures, especially Paths. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/pathnodes.h diff --git a/src/include/nodes/pg_list.h b/src/include/nodes/pg_list.h index cda77a841e347..710dcd37ef4bb 100644 --- a/src/include/nodes/pg_list.h +++ b/src/include/nodes/pg_list.h @@ -27,7 +27,7 @@ * always be so; try to be careful to maintain the distinction.) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/pg_list.h diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index 7e6b10f86b978..43160439f0580 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -4,7 +4,7 @@ * definitions for query plan nodes * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/plannodes.h diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index dd85908fe2f8c..e51be4bce8f9f 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -7,7 +7,7 @@ * and join trees. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/primnodes.h diff --git a/src/include/nodes/print.h b/src/include/nodes/print.h index 6126b491bfba5..7bb1e1b64a36e 100644 --- a/src/include/nodes/print.h +++ b/src/include/nodes/print.h @@ -4,7 +4,7 @@ * definitions for nodes/print.c * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/print.h diff --git a/src/include/nodes/readfuncs.h b/src/include/nodes/readfuncs.h index 4eb04caae3a2d..5dc78cdc384fb 100644 --- a/src/include/nodes/readfuncs.h +++ b/src/include/nodes/readfuncs.h @@ -4,7 +4,7 @@ * header file for read.c and readfuncs.c. These functions are internal * to the stringToNode interface and should not be used by anyone else. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/readfuncs.h diff --git a/src/include/nodes/replnodes.h b/src/include/nodes/replnodes.h index 5456141a8ab86..faa3a251f26d5 100644 --- a/src/include/nodes/replnodes.h +++ b/src/include/nodes/replnodes.h @@ -4,7 +4,7 @@ * definitions for replication grammar parse nodes * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/replnodes.h diff --git a/src/include/nodes/subscripting.h b/src/include/nodes/subscripting.h index 3b0a60773ded9..811b45ad3a8aa 100644 --- a/src/include/nodes/subscripting.h +++ b/src/include/nodes/subscripting.h @@ -3,7 +3,7 @@ * subscripting.h * API for generic type subscripting * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/subscripting.h diff --git a/src/include/nodes/supportnodes.h b/src/include/nodes/supportnodes.h index 9a33c4c896f6f..85e1b8a832fbd 100644 --- a/src/include/nodes/supportnodes.h +++ b/src/include/nodes/supportnodes.h @@ -23,7 +23,7 @@ * allows for future extensions of the set of request cases. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/supportnodes.h diff --git a/src/include/nodes/tidbitmap.h b/src/include/nodes/tidbitmap.h index d562fcae34eb4..bc6716610545d 100644 --- a/src/include/nodes/tidbitmap.h +++ b/src/include/nodes/tidbitmap.h @@ -13,7 +13,7 @@ * fact that a particular page needs to be visited. * * - * Copyright (c) 2003-2020, PostgreSQL Global Development Group + * Copyright (c) 2003-2021, PostgreSQL Global Development Group * * src/include/nodes/tidbitmap.h * diff --git a/src/include/nodes/value.h b/src/include/nodes/value.h index d4911b5d38f4f..b28928de54552 100644 --- a/src/include/nodes/value.h +++ b/src/include/nodes/value.h @@ -4,7 +4,7 @@ * interface for Value nodes * * - * Copyright (c) 2003-2020, PostgreSQL Global Development Group + * Copyright (c) 2003-2021, PostgreSQL Global Development Group * * src/include/nodes/value.h * diff --git a/src/include/optimizer/appendinfo.h b/src/include/optimizer/appendinfo.h index d6a27a60ddc36..4cbf8c26cc2ad 100644 --- a/src/include/optimizer/appendinfo.h +++ b/src/include/optimizer/appendinfo.h @@ -4,7 +4,7 @@ * Routines for mapping expressions between append rel parent(s) and * children * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/appendinfo.h diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h index 68855d0cee7aa..da3fc4df105e9 100644 --- a/src/include/optimizer/clauses.h +++ b/src/include/optimizer/clauses.h @@ -4,7 +4,7 @@ * prototypes for clauses.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/clauses.h diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h index 8e621d2f761c5..ed2e4af4be73c 100644 --- a/src/include/optimizer/cost.h +++ b/src/include/optimizer/cost.h @@ -4,7 +4,7 @@ * prototypes for costsize.c and clausesel.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/cost.h diff --git a/src/include/optimizer/geqo.h b/src/include/optimizer/geqo.h index aba549f14576f..24dcdfb6cce40 100644 --- a/src/include/optimizer/geqo.h +++ b/src/include/optimizer/geqo.h @@ -3,7 +3,7 @@ * geqo.h * prototypes for various files in optimizer/geqo * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/geqo.h diff --git a/src/include/optimizer/geqo_copy.h b/src/include/optimizer/geqo_copy.h index 87444b6712044..47c5449849cb0 100644 --- a/src/include/optimizer/geqo_copy.h +++ b/src/include/optimizer/geqo_copy.h @@ -3,7 +3,7 @@ * geqo_copy.h * prototypes for copy functions in optimizer/geqo * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/geqo_copy.h diff --git a/src/include/optimizer/geqo_gene.h b/src/include/optimizer/geqo_gene.h index 9d3a94f2e83fe..89300548841a2 100644 --- a/src/include/optimizer/geqo_gene.h +++ b/src/include/optimizer/geqo_gene.h @@ -3,7 +3,7 @@ * geqo_gene.h * genome representation in optimizer/geqo * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/geqo_gene.h diff --git a/src/include/optimizer/geqo_misc.h b/src/include/optimizer/geqo_misc.h index 93e6123d027f1..458c4089df054 100644 --- a/src/include/optimizer/geqo_misc.h +++ b/src/include/optimizer/geqo_misc.h @@ -3,7 +3,7 @@ * geqo_misc.h * prototypes for printout routines in optimizer/geqo * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/geqo_misc.h diff --git a/src/include/optimizer/geqo_mutation.h b/src/include/optimizer/geqo_mutation.h index bed56967c48a7..076e4ab5d3e73 100644 --- a/src/include/optimizer/geqo_mutation.h +++ b/src/include/optimizer/geqo_mutation.h @@ -3,7 +3,7 @@ * geqo_mutation.h * prototypes for mutation functions in optimizer/geqo * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/geqo_mutation.h diff --git a/src/include/optimizer/geqo_pool.h b/src/include/optimizer/geqo_pool.h index c3497a63ba7d5..d5c41ac8a428c 100644 --- a/src/include/optimizer/geqo_pool.h +++ b/src/include/optimizer/geqo_pool.h @@ -3,7 +3,7 @@ * geqo_pool.h * pool representation in optimizer/geqo * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/geqo_pool.h diff --git a/src/include/optimizer/geqo_random.h b/src/include/optimizer/geqo_random.h index 54898c1f56f66..7f4aad44397f0 100644 --- a/src/include/optimizer/geqo_random.h +++ b/src/include/optimizer/geqo_random.h @@ -3,7 +3,7 @@ * geqo_random.h * random number generator * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/geqo_random.h diff --git a/src/include/optimizer/geqo_recombination.h b/src/include/optimizer/geqo_recombination.h index 921cf146b7845..30018328c799b 100644 --- a/src/include/optimizer/geqo_recombination.h +++ b/src/include/optimizer/geqo_recombination.h @@ -3,7 +3,7 @@ * geqo_recombination.h * prototypes for recombination in the genetic query optimizer * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/geqo_recombination.h diff --git a/src/include/optimizer/geqo_selection.h b/src/include/optimizer/geqo_selection.h index 9f0f7b727af29..099c8ce4d974b 100644 --- a/src/include/optimizer/geqo_selection.h +++ b/src/include/optimizer/geqo_selection.h @@ -3,7 +3,7 @@ * geqo_selection.h * prototypes for selection routines in optimizer/geqo * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/geqo_selection.h diff --git a/src/include/optimizer/inherit.h b/src/include/optimizer/inherit.h index 0ba61326528d0..e9472f2f7321a 100644 --- a/src/include/optimizer/inherit.h +++ b/src/include/optimizer/inherit.h @@ -4,7 +4,7 @@ * prototypes for inherit.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/inherit.h diff --git a/src/include/optimizer/joininfo.h b/src/include/optimizer/joininfo.h index 753d2eff58653..739cc52cc2486 100644 --- a/src/include/optimizer/joininfo.h +++ b/src/include/optimizer/joininfo.h @@ -4,7 +4,7 @@ * prototypes for joininfo.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/joininfo.h diff --git a/src/include/optimizer/optimizer.h b/src/include/optimizer/optimizer.h index 446071c554d93..6235933ca4a2f 100644 --- a/src/include/optimizer/optimizer.h +++ b/src/include/optimizer/optimizer.h @@ -12,7 +12,7 @@ * example. For the most part, however, code outside the core planner * should not need to include any optimizer/ header except this one. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/optimizer.h diff --git a/src/include/optimizer/orclauses.h b/src/include/optimizer/orclauses.h index b5377fc417859..526101e18fa1a 100644 --- a/src/include/optimizer/orclauses.h +++ b/src/include/optimizer/orclauses.h @@ -4,7 +4,7 @@ * prototypes for orclauses.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/orclauses.h diff --git a/src/include/optimizer/paramassign.h b/src/include/optimizer/paramassign.h index 02b4b501df8c4..b4fd379939bf2 100644 --- a/src/include/optimizer/paramassign.h +++ b/src/include/optimizer/paramassign.h @@ -3,7 +3,7 @@ * paramassign.h * Functions for assigning PARAM_EXEC slots during planning. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/paramassign.h diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h index 3bd7072ae8c60..23dec14cbd38c 100644 --- a/src/include/optimizer/pathnode.h +++ b/src/include/optimizer/pathnode.h @@ -4,7 +4,7 @@ * prototypes for pathnode.c, relnode.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/pathnode.h diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h index bf6c16b8040c0..2d51cbecaa3c6 100644 --- a/src/include/optimizer/paths.h +++ b/src/include/optimizer/paths.h @@ -4,7 +4,7 @@ * prototypes for various files in optimizer/path * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/paths.h diff --git a/src/include/optimizer/placeholder.h b/src/include/optimizer/placeholder.h index b5a6b308c83fc..69ef5aedb2b12 100644 --- a/src/include/optimizer/placeholder.h +++ b/src/include/optimizer/placeholder.h @@ -4,7 +4,7 @@ * prototypes for optimizer/util/placeholder.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/placeholder.h diff --git a/src/include/optimizer/plancat.h b/src/include/optimizer/plancat.h index c29a7091ec04a..8d1d6c1b42eb5 100644 --- a/src/include/optimizer/plancat.h +++ b/src/include/optimizer/plancat.h @@ -4,7 +4,7 @@ * prototypes for plancat.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/plancat.h diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h index 81c4a7e560789..777655210b63f 100644 --- a/src/include/optimizer/planmain.h +++ b/src/include/optimizer/planmain.h @@ -4,7 +4,7 @@ * prototypes for various files in optimizer/plan * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/planmain.h diff --git a/src/include/optimizer/planner.h b/src/include/optimizer/planner.h index beb7dbbcbe836..9a15de50259bc 100644 --- a/src/include/optimizer/planner.h +++ b/src/include/optimizer/planner.h @@ -8,7 +8,7 @@ * non-planner code. Declarations here are meant for use by other * planner modules. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/planner.h diff --git a/src/include/optimizer/prep.h b/src/include/optimizer/prep.h index 0abe6bec00e78..f49196a4d384a 100644 --- a/src/include/optimizer/prep.h +++ b/src/include/optimizer/prep.h @@ -4,7 +4,7 @@ * prototypes for files in optimizer/prep/ * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/prep.h diff --git a/src/include/optimizer/restrictinfo.h b/src/include/optimizer/restrictinfo.h index df6b97426d63c..266faaf07c3dd 100644 --- a/src/include/optimizer/restrictinfo.h +++ b/src/include/optimizer/restrictinfo.h @@ -4,7 +4,7 @@ * prototypes for restrictinfo.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/restrictinfo.h diff --git a/src/include/optimizer/subselect.h b/src/include/optimizer/subselect.h index d6a872bd2c380..059bdf941ef76 100644 --- a/src/include/optimizer/subselect.h +++ b/src/include/optimizer/subselect.h @@ -3,7 +3,7 @@ * subselect.h * Planning routines for subselects. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/subselect.h diff --git a/src/include/optimizer/tlist.h b/src/include/optimizer/tlist.h index 1d4c7da545a0c..e081ef2d5e439 100644 --- a/src/include/optimizer/tlist.h +++ b/src/include/optimizer/tlist.h @@ -4,7 +4,7 @@ * prototypes for tlist.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/optimizer/tlist.h diff --git a/src/include/parser/analyze.h b/src/include/parser/analyze.h index d6a467a57287e..fede4be820aa9 100644 --- a/src/include/parser/analyze.h +++ b/src/include/parser/analyze.h @@ -4,7 +4,7 @@ * parse analysis for optimizable statements * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/analyze.h diff --git a/src/include/parser/gramparse.h b/src/include/parser/gramparse.h index 7c7be136d5c67..989f850cbcd5e 100644 --- a/src/include/parser/gramparse.h +++ b/src/include/parser/gramparse.h @@ -8,7 +8,7 @@ * Definitions that are needed outside the core parser should be in parser.h. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/gramparse.h diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index 71dcdf28894d1..8c554e1f690d4 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -7,7 +7,7 @@ * by the PG_KEYWORD macro, which is not defined in this file; it can * be defined by the caller for special purposes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/parser/parse_agg.h b/src/include/parser/parse_agg.h index 1a364d5cef8f8..0a2546c3ea977 100644 --- a/src/include/parser/parse_agg.h +++ b/src/include/parser/parse_agg.h @@ -3,7 +3,7 @@ * parse_agg.h * handle aggregates and window functions in parser * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_agg.h diff --git a/src/include/parser/parse_clause.h b/src/include/parser/parse_clause.h index 75a4fcfa598b7..0eab3c03e874e 100644 --- a/src/include/parser/parse_clause.h +++ b/src/include/parser/parse_clause.h @@ -4,7 +4,7 @@ * handle clauses in parser * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_clause.h diff --git a/src/include/parser/parse_coerce.h b/src/include/parser/parse_coerce.h index 33d7cfc8b646c..6ebdbd63ee0e3 100644 --- a/src/include/parser/parse_coerce.h +++ b/src/include/parser/parse_coerce.h @@ -4,7 +4,7 @@ * Routines for type coercion. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_coerce.h diff --git a/src/include/parser/parse_collate.h b/src/include/parser/parse_collate.h index c1021e7c0c501..45245d6c6dac9 100644 --- a/src/include/parser/parse_collate.h +++ b/src/include/parser/parse_collate.h @@ -4,7 +4,7 @@ * Routines for assigning collation information. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_collate.h diff --git a/src/include/parser/parse_cte.h b/src/include/parser/parse_cte.h index 63b32419d0ffb..dea519fc2a64a 100644 --- a/src/include/parser/parse_cte.h +++ b/src/include/parser/parse_cte.h @@ -4,7 +4,7 @@ * handle CTEs (common table expressions) in parser * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_cte.h diff --git a/src/include/parser/parse_enr.h b/src/include/parser/parse_enr.h index a013f103378be..65787c25543d0 100644 --- a/src/include/parser/parse_enr.h +++ b/src/include/parser/parse_enr.h @@ -4,7 +4,7 @@ * Internal definitions for parser * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_enr.h diff --git a/src/include/parser/parse_expr.h b/src/include/parser/parse_expr.h index 5668f88302e8b..8ac4a0a36980b 100644 --- a/src/include/parser/parse_expr.h +++ b/src/include/parser/parse_expr.h @@ -3,7 +3,7 @@ * parse_expr.h * handle expressions in parser * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_expr.h diff --git a/src/include/parser/parse_func.h b/src/include/parser/parse_func.h index dd189f5452efc..aaf07f8f73d8e 100644 --- a/src/include/parser/parse_func.h +++ b/src/include/parser/parse_func.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_func.h diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h index beb56fec87a8a..dfc214b06fb38 100644 --- a/src/include/parser/parse_node.h +++ b/src/include/parser/parse_node.h @@ -4,7 +4,7 @@ * Internal definitions for parser * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_node.h diff --git a/src/include/parser/parse_oper.h b/src/include/parser/parse_oper.h index 09695a2765cff..8ebe95c69958b 100644 --- a/src/include/parser/parse_oper.h +++ b/src/include/parser/parse_oper.h @@ -4,7 +4,7 @@ * handle operator things for parser * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_oper.h diff --git a/src/include/parser/parse_param.h b/src/include/parser/parse_param.h index 833f78dfa6ec5..b42fff296ceae 100644 --- a/src/include/parser/parse_param.h +++ b/src/include/parser/parse_param.h @@ -3,7 +3,7 @@ * parse_param.h * handle parameters in parser * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_param.h diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h index 93f94466a05a4..35e64070a89af 100644 --- a/src/include/parser/parse_relation.h +++ b/src/include/parser/parse_relation.h @@ -4,7 +4,7 @@ * prototypes for parse_relation.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_relation.h diff --git a/src/include/parser/parse_target.h b/src/include/parser/parse_target.h index 7039df29cbbc9..9d3637747d4f0 100644 --- a/src/include/parser/parse_target.h +++ b/src/include/parser/parse_target.h @@ -4,7 +4,7 @@ * handle target lists * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_target.h diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h index bb83d7294a3e2..f4585fd248fd4 100644 --- a/src/include/parser/parse_type.h +++ b/src/include/parser/parse_type.h @@ -3,7 +3,7 @@ * parse_type.h * handle type operations for parser * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_type.h diff --git a/src/include/parser/parse_utilcmd.h b/src/include/parser/parse_utilcmd.h index bc3d66ed88146..bfa4a6b0f2099 100644 --- a/src/include/parser/parse_utilcmd.h +++ b/src/include/parser/parse_utilcmd.h @@ -4,7 +4,7 @@ * parse analysis for utility commands * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parse_utilcmd.h diff --git a/src/include/parser/parser.h b/src/include/parser/parser.h index 3bdeeb8b0b188..0973003044498 100644 --- a/src/include/parser/parser.h +++ b/src/include/parser/parser.h @@ -5,7 +5,7 @@ * * This is the external API for the raw lexing/parsing functions. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parser.h diff --git a/src/include/parser/parsetree.h b/src/include/parser/parsetree.h index 3ed5862640eda..6e1058f1c20c2 100644 --- a/src/include/parser/parsetree.h +++ b/src/include/parser/parsetree.h @@ -5,7 +5,7 @@ * parse trees. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parsetree.h diff --git a/src/include/parser/scanner.h b/src/include/parser/scanner.h index a27352afc1453..0d8182faa0d83 100644 --- a/src/include/parser/scanner.h +++ b/src/include/parser/scanner.h @@ -8,7 +8,7 @@ * higher-level API provided by parser.h. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/scanner.h diff --git a/src/include/parser/scansup.h b/src/include/parser/scansup.h index 5bc426660df6a..813327b707499 100644 --- a/src/include/parser/scansup.h +++ b/src/include/parser/scansup.h @@ -3,7 +3,7 @@ * scansup.h * scanner support routines used by the core lexer * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/scansup.h diff --git a/src/include/partitioning/partbounds.h b/src/include/partitioning/partbounds.h index 192b0b1e2ad89..6bd330dd938a9 100644 --- a/src/include/partitioning/partbounds.h +++ b/src/include/partitioning/partbounds.h @@ -2,7 +2,7 @@ * * partbounds.h * - * Copyright (c) 2007-2020, PostgreSQL Global Development Group + * Copyright (c) 2007-2021, PostgreSQL Global Development Group * * src/include/partitioning/partbounds.h * diff --git a/src/include/partitioning/partdefs.h b/src/include/partitioning/partdefs.h index 6414e2c116364..d742b96152153 100644 --- a/src/include/partitioning/partdefs.h +++ b/src/include/partitioning/partdefs.h @@ -3,7 +3,7 @@ * partdefs.h * Base definitions for partitioned table handling * - * Copyright (c) 2007-2020, PostgreSQL Global Development Group + * Copyright (c) 2007-2021, PostgreSQL Global Development Group * * src/include/partitioning/partdefs.h * diff --git a/src/include/partitioning/partdesc.h b/src/include/partitioning/partdesc.h index 70df764981e70..ff113199e5c3a 100644 --- a/src/include/partitioning/partdesc.h +++ b/src/include/partitioning/partdesc.h @@ -2,7 +2,7 @@ * * partdesc.h * - * Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Copyright (c) 1996-2021, PostgreSQL Global Development Group * * src/include/partitioning/partdesc.h * diff --git a/src/include/partitioning/partprune.h b/src/include/partitioning/partprune.h index babdad2c3ef16..1f9544c0dcfd7 100644 --- a/src/include/partitioning/partprune.h +++ b/src/include/partitioning/partprune.h @@ -4,7 +4,7 @@ * prototypes for partprune.c * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/partitioning/partprune.h diff --git a/src/include/pg_config_manual.h b/src/include/pg_config_manual.h index 705dc69c06a28..3cbdc6d180edd 100644 --- a/src/include/pg_config_manual.h +++ b/src/include/pg_config_manual.h @@ -6,7 +6,7 @@ * for developers. If you edit any of these, be sure to do a *full* * rebuild (and an initdb if noted). * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/pg_config_manual.h diff --git a/src/include/pg_getopt.h b/src/include/pg_getopt.h index e646fc3419e41..66f1b75060442 100644 --- a/src/include/pg_getopt.h +++ b/src/include/pg_getopt.h @@ -11,7 +11,7 @@ * Portions Copyright (c) 1987, 1993, 1994 * The Regents of the University of California. All rights reserved. * - * Portions Copyright (c) 2003-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2021, PostgreSQL Global Development Group * * src/include/pg_getopt.h */ diff --git a/src/include/pg_trace.h b/src/include/pg_trace.h index cf212aeabdbdb..a1ecedb7dd087 100644 --- a/src/include/pg_trace.h +++ b/src/include/pg_trace.h @@ -3,7 +3,7 @@ * * Definitions for the PostgreSQL tracing framework * - * Copyright (c) 2006-2020, PostgreSQL Global Development Group + * Copyright (c) 2006-2021, PostgreSQL Global Development Group * * src/include/pg_trace.h * ---------- diff --git a/src/include/pgstat.h b/src/include/pgstat.h index 5954068dec534..3a7e1997506e2 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -3,7 +3,7 @@ * * Definitions for the PostgreSQL statistics collector daemon. * - * Copyright (c) 2001-2020, PostgreSQL Global Development Group + * Copyright (c) 2001-2021, PostgreSQL Global Development Group * * src/include/pgstat.h * ---------- diff --git a/src/include/pgtar.h b/src/include/pgtar.h index 0f08dc0c2ca88..6d47ece652044 100644 --- a/src/include/pgtar.h +++ b/src/include/pgtar.h @@ -4,7 +4,7 @@ * Functions for manipulating tarfile datastructures (src/port/tar.c) * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/pgtar.h diff --git a/src/include/pgtime.h b/src/include/pgtime.h index 0fc76d0e609bc..28bd27e7f79f9 100644 --- a/src/include/pgtime.h +++ b/src/include/pgtime.h @@ -3,7 +3,7 @@ * pgtime.h * PostgreSQL internal timezone library * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/include/pgtime.h diff --git a/src/include/port.h b/src/include/port.h index c631185c8bbb2..3e9d4fcd3769a 100644 --- a/src/include/port.h +++ b/src/include/port.h @@ -3,7 +3,7 @@ * port.h * Header for src/port/ compatibility functions. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/port.h diff --git a/src/include/port/atomics.h b/src/include/port/atomics.h index 4956ec55cbf33..856338f161473 100644 --- a/src/include/port/atomics.h +++ b/src/include/port/atomics.h @@ -28,7 +28,7 @@ * For an introduction to using memory barriers within the PostgreSQL backend, * see src/backend/storage/lmgr/README.barrier * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/port/atomics.h diff --git a/src/include/port/atomics/arch-arm.h b/src/include/port/atomics/arch-arm.h index 6b925a7df4b05..efa385321e8b6 100644 --- a/src/include/port/atomics/arch-arm.h +++ b/src/include/port/atomics/arch-arm.h @@ -3,7 +3,7 @@ * arch-arm.h * Atomic operations considerations specific to ARM * - * Portions Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2013-2021, PostgreSQL Global Development Group * * NOTES: * diff --git a/src/include/port/atomics/arch-hppa.h b/src/include/port/atomics/arch-hppa.h index a581b3f57ee33..0661c0e555ec1 100644 --- a/src/include/port/atomics/arch-hppa.h +++ b/src/include/port/atomics/arch-hppa.h @@ -3,7 +3,7 @@ * arch-hppa.h * Atomic operations considerations specific to HPPA * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES: diff --git a/src/include/port/atomics/arch-ia64.h b/src/include/port/atomics/arch-ia64.h index 9feb153ef274b..45f36f2b8e9e5 100644 --- a/src/include/port/atomics/arch-ia64.h +++ b/src/include/port/atomics/arch-ia64.h @@ -3,7 +3,7 @@ * arch-ia64.h * Atomic operations considerations specific to intel itanium * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES: diff --git a/src/include/port/atomics/arch-ppc.h b/src/include/port/atomics/arch-ppc.h index a82ae38c1d6e8..081429636bfbe 100644 --- a/src/include/port/atomics/arch-ppc.h +++ b/src/include/port/atomics/arch-ppc.h @@ -3,7 +3,7 @@ * arch-ppc.h * Atomic operations considerations specific to PowerPC * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES: diff --git a/src/include/port/atomics/arch-x86.h b/src/include/port/atomics/arch-x86.h index 13cc4f555919c..2cab5a327a587 100644 --- a/src/include/port/atomics/arch-x86.h +++ b/src/include/port/atomics/arch-x86.h @@ -7,7 +7,7 @@ * support for xadd and cmpxchg. Given that the 386 isn't supported anywhere * anymore that's not much of a restriction luckily. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES: diff --git a/src/include/port/atomics/fallback.h b/src/include/port/atomics/fallback.h index e3849c80e1653..b344aae955e49 100644 --- a/src/include/port/atomics/fallback.h +++ b/src/include/port/atomics/fallback.h @@ -4,7 +4,7 @@ * Fallback for platforms without spinlock and/or atomics support. Slower * than native atomics support, but not unusably slow. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/port/atomics/fallback.h diff --git a/src/include/port/atomics/generic-acc.h b/src/include/port/atomics/generic-acc.h index 195b8f4838982..3c75b6a871b4a 100644 --- a/src/include/port/atomics/generic-acc.h +++ b/src/include/port/atomics/generic-acc.h @@ -3,7 +3,7 @@ * generic-acc.h * Atomic operations support when using HPs acc on HPUX * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES: diff --git a/src/include/port/atomics/generic-gcc.h b/src/include/port/atomics/generic-gcc.h index 1a3dce34ed378..99fda188c46e8 100644 --- a/src/include/port/atomics/generic-gcc.h +++ b/src/include/port/atomics/generic-gcc.h @@ -3,7 +3,7 @@ * generic-gcc.h * Atomic operations, implemented using gcc (or compatible) intrinsics. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES: diff --git a/src/include/port/atomics/generic-msvc.h b/src/include/port/atomics/generic-msvc.h index c74c6093d1c76..f535b4567b536 100644 --- a/src/include/port/atomics/generic-msvc.h +++ b/src/include/port/atomics/generic-msvc.h @@ -3,7 +3,7 @@ * generic-msvc.h * Atomic operations support when using MSVC * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES: diff --git a/src/include/port/atomics/generic-sunpro.h b/src/include/port/atomics/generic-sunpro.h index 9aaeb739e761a..7196021ec027f 100644 --- a/src/include/port/atomics/generic-sunpro.h +++ b/src/include/port/atomics/generic-sunpro.h @@ -3,7 +3,7 @@ * generic-sunpro.h * Atomic operations for solaris' CC * - * Portions Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2013-2021, PostgreSQL Global Development Group * * NOTES: * diff --git a/src/include/port/atomics/generic.h b/src/include/port/atomics/generic.h index d60a0d9e7fc28..6d094dc4a4005 100644 --- a/src/include/port/atomics/generic.h +++ b/src/include/port/atomics/generic.h @@ -4,7 +4,7 @@ * Implement higher level operations based on some lower level atomic * operations. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/port/atomics/generic.h diff --git a/src/include/port/pg_bitutils.h b/src/include/port/pg_bitutils.h index 887e782911105..f9b77ec2780ad 100644 --- a/src/include/port/pg_bitutils.h +++ b/src/include/port/pg_bitutils.h @@ -4,7 +4,7 @@ * Miscellaneous functions for bit-wise operations. * * - * Copyright (c) 2019-2020, PostgreSQL Global Development Group + * Copyright (c) 2019-2021, PostgreSQL Global Development Group * * src/include/port/pg_bitutils.h * diff --git a/src/include/port/pg_bswap.h b/src/include/port/pg_bswap.h index 9fd14d129abfe..6dfa7757c6bbb 100644 --- a/src/include/port/pg_bswap.h +++ b/src/include/port/pg_bswap.h @@ -11,7 +11,7 @@ * return the same. Use caution when using these wrapper macros with signed * integers. * - * Copyright (c) 2015-2020, PostgreSQL Global Development Group + * Copyright (c) 2015-2021, PostgreSQL Global Development Group * * src/include/port/pg_bswap.h * diff --git a/src/include/port/pg_crc32c.h b/src/include/port/pg_crc32c.h index 3c6f906683224..f3c4107ff99c0 100644 --- a/src/include/port/pg_crc32c.h +++ b/src/include/port/pg_crc32c.h @@ -23,7 +23,7 @@ * EQ_CRC32C(c1, c2) * Check for equality of two CRCs. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/port/pg_crc32c.h diff --git a/src/include/port/win32_port.h b/src/include/port/win32_port.h index 2ffe056a0fefd..05c5a5344206f 100644 --- a/src/include/port/win32_port.h +++ b/src/include/port/win32_port.h @@ -6,7 +6,7 @@ * Note this is read in MinGW as well as native Windows builds, * but not in Cygwin builds. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/port/win32_port.h diff --git a/src/include/portability/instr_time.h b/src/include/portability/instr_time.h index d6459327ccfe9..39a4f0600e237 100644 --- a/src/include/portability/instr_time.h +++ b/src/include/portability/instr_time.h @@ -46,7 +46,7 @@ * Beware of multiple evaluations of the macro arguments. * * - * Copyright (c) 2001-2020, PostgreSQL Global Development Group + * Copyright (c) 2001-2021, PostgreSQL Global Development Group * * src/include/portability/instr_time.h * diff --git a/src/include/portability/mem.h b/src/include/portability/mem.h index c1c8eb5ff3a48..566d21fb5faa2 100644 --- a/src/include/portability/mem.h +++ b/src/include/portability/mem.h @@ -3,7 +3,7 @@ * mem.h * portability definitions for various memory operations * - * Copyright (c) 2001-2020, PostgreSQL Global Development Group + * Copyright (c) 2001-2021, PostgreSQL Global Development Group * * src/include/portability/mem.h * diff --git a/src/include/postgres.h b/src/include/postgres.h index c48f47e930ad0..2ed572004dd28 100644 --- a/src/include/postgres.h +++ b/src/include/postgres.h @@ -7,7 +7,7 @@ * Client-side code should include postgres_fe.h instead. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1995, Regents of the University of California * * src/include/postgres.h diff --git a/src/include/postgres_fe.h b/src/include/postgres_fe.h index e99258f2d6627..3cdb911faa697 100644 --- a/src/include/postgres_fe.h +++ b/src/include/postgres_fe.h @@ -8,7 +8,7 @@ * postgres.h. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1995, Regents of the University of California * * src/include/postgres_fe.h diff --git a/src/include/postmaster/autovacuum.h b/src/include/postmaster/autovacuum.h index 7277effe03485..aacdd0f5753dd 100644 --- a/src/include/postmaster/autovacuum.h +++ b/src/include/postmaster/autovacuum.h @@ -4,7 +4,7 @@ * header file for integrated autovacuum daemon * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/postmaster/autovacuum.h diff --git a/src/include/postmaster/bgworker.h b/src/include/postmaster/bgworker.h index 4c6ebaa41b9c6..8e9ef7c7bfacc 100644 --- a/src/include/postmaster/bgworker.h +++ b/src/include/postmaster/bgworker.h @@ -31,7 +31,7 @@ * different) code. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/postmaster/bgworker_internals.h b/src/include/postmaster/bgworker_internals.h index dd6cabc45b543..fc7706314be55 100644 --- a/src/include/postmaster/bgworker_internals.h +++ b/src/include/postmaster/bgworker_internals.h @@ -2,7 +2,7 @@ * bgworker_internals.h * POSTGRES pluggable background workers internals * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/postmaster/bgwriter.h b/src/include/postmaster/bgwriter.h index 0a5708b32e690..c430b1b236622 100644 --- a/src/include/postmaster/bgwriter.h +++ b/src/include/postmaster/bgwriter.h @@ -6,7 +6,7 @@ * The bgwriter process used to handle checkpointing duties too. Now * there is a separate process, but we did not bother to split this header. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * src/include/postmaster/bgwriter.h * diff --git a/src/include/postmaster/fork_process.h b/src/include/postmaster/fork_process.h index 8cb568fc6338b..64e037331e3e2 100644 --- a/src/include/postmaster/fork_process.h +++ b/src/include/postmaster/fork_process.h @@ -3,7 +3,7 @@ * fork_process.h * Exports from postmaster/fork_process.c. * - * Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Copyright (c) 1996-2021, PostgreSQL Global Development Group * * src/include/postmaster/fork_process.h * diff --git a/src/include/postmaster/interrupt.h b/src/include/postmaster/interrupt.h index 4f567129e4c45..85a1293ef1bfc 100644 --- a/src/include/postmaster/interrupt.h +++ b/src/include/postmaster/interrupt.h @@ -7,7 +7,7 @@ * have their own implementations, but we provide a few generic things * here to facilitate code reuse. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/postmaster/pgarch.h b/src/include/postmaster/pgarch.h index b3200874ca81e..d102a21ab7ebf 100644 --- a/src/include/postmaster/pgarch.h +++ b/src/include/postmaster/pgarch.h @@ -3,7 +3,7 @@ * pgarch.h * Exports from postmaster/pgarch.c. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/postmaster/pgarch.h diff --git a/src/include/postmaster/postmaster.h b/src/include/postmaster/postmaster.h index babc87dfc9d2a..cfa59c4dc0dfa 100644 --- a/src/include/postmaster/postmaster.h +++ b/src/include/postmaster/postmaster.h @@ -3,7 +3,7 @@ * postmaster.h * Exports from postmaster/postmaster.c. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/postmaster/postmaster.h diff --git a/src/include/postmaster/startup.h b/src/include/postmaster/startup.h index bec313764a192..bf6adf1d36e79 100644 --- a/src/include/postmaster/startup.h +++ b/src/include/postmaster/startup.h @@ -3,7 +3,7 @@ * startup.h * Exports from postmaster/startup.c. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * src/include/postmaster/startup.h * diff --git a/src/include/postmaster/syslogger.h b/src/include/postmaster/syslogger.h index f611bd1411437..1491eecb0f8f2 100644 --- a/src/include/postmaster/syslogger.h +++ b/src/include/postmaster/syslogger.h @@ -3,7 +3,7 @@ * syslogger.h * Exports from postmaster/syslogger.c. * - * Copyright (c) 2004-2020, PostgreSQL Global Development Group + * Copyright (c) 2004-2021, PostgreSQL Global Development Group * * src/include/postmaster/syslogger.h * diff --git a/src/include/postmaster/walwriter.h b/src/include/postmaster/walwriter.h index 011dc26a6ece2..3ccc332333c14 100644 --- a/src/include/postmaster/walwriter.h +++ b/src/include/postmaster/walwriter.h @@ -3,7 +3,7 @@ * walwriter.h * Exports from postmaster/walwriter.c. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * src/include/postmaster/walwriter.h * diff --git a/src/include/regex/regexport.h b/src/include/regex/regexport.h index 23e599d9b3276..e6209463f7f83 100644 --- a/src/include/regex/regexport.h +++ b/src/include/regex/regexport.h @@ -17,7 +17,7 @@ * line and start/end of string. Colors are numbered 0..C-1, but note that * color 0 is "white" (all unused characters) and can generally be ignored. * - * Portions Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2013-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1998, 1999 Henry Spencer * * IDENTIFICATION diff --git a/src/include/replication/backup_manifest.h b/src/include/replication/backup_manifest.h index e7c40474972f4..099108910ce48 100644 --- a/src/include/replication/backup_manifest.h +++ b/src/include/replication/backup_manifest.h @@ -3,7 +3,7 @@ * backup_manifest.h * Routines for generating a backup manifest. * - * Portions Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2021, PostgreSQL Global Development Group * * src/include/replication/backup_manifest.h * diff --git a/src/include/replication/basebackup.h b/src/include/replication/basebackup.h index f5f044dacd41c..cdfe4b5e19dd5 100644 --- a/src/include/replication/basebackup.h +++ b/src/include/replication/basebackup.h @@ -3,7 +3,7 @@ * basebackup.h * Exports from replication/basebackup.c. * - * Portions Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2021, PostgreSQL Global Development Group * * src/include/replication/basebackup.h * diff --git a/src/include/replication/decode.h b/src/include/replication/decode.h index 8479e16dd87cc..69918080bb536 100644 --- a/src/include/replication/decode.h +++ b/src/include/replication/decode.h @@ -2,7 +2,7 @@ * decode.h * PostgreSQL WAL to logical transformation * - * Portions Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2012-2021, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/include/replication/logical.h b/src/include/replication/logical.h index 28c9c1f474eb3..c253403372373 100644 --- a/src/include/replication/logical.h +++ b/src/include/replication/logical.h @@ -2,7 +2,7 @@ * logical.h * PostgreSQL logical decoding coordination * - * Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Copyright (c) 2012-2021, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/include/replication/logicallauncher.h b/src/include/replication/logicallauncher.h index b22e591bafb24..421ec1580d806 100644 --- a/src/include/replication/logicallauncher.h +++ b/src/include/replication/logicallauncher.h @@ -3,7 +3,7 @@ * logicallauncher.h * Exports for logical replication launcher. * - * Portions Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2016-2021, PostgreSQL Global Development Group * * src/include/replication/logicallauncher.h * diff --git a/src/include/replication/logicalproto.h b/src/include/replication/logicalproto.h index 1f2535df800e2..fa4c37277b134 100644 --- a/src/include/replication/logicalproto.h +++ b/src/include/replication/logicalproto.h @@ -3,7 +3,7 @@ * logicalproto.h * logical replication protocol * - * Copyright (c) 2015-2020, PostgreSQL Global Development Group + * Copyright (c) 2015-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/include/replication/logicalproto.h diff --git a/src/include/replication/logicalrelation.h b/src/include/replication/logicalrelation.h index 62ddd3c7a2ae5..3f0b3deefb8ce 100644 --- a/src/include/replication/logicalrelation.h +++ b/src/include/replication/logicalrelation.h @@ -3,7 +3,7 @@ * logicalrelation.h * Relation definitions for logical replication relation mapping. * - * Portions Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2016-2021, PostgreSQL Global Development Group * * src/include/replication/logicalrelation.h * diff --git a/src/include/replication/logicalworker.h b/src/include/replication/logicalworker.h index 7ea143608e440..2ad61a001a113 100644 --- a/src/include/replication/logicalworker.h +++ b/src/include/replication/logicalworker.h @@ -3,7 +3,7 @@ * logicalworker.h * Exports for logical replication workers. * - * Portions Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2016-2021, PostgreSQL Global Development Group * * src/include/replication/logicalworker.h * diff --git a/src/include/replication/message.h b/src/include/replication/message.h index e97891ebcafa7..d3fb324c81623 100644 --- a/src/include/replication/message.h +++ b/src/include/replication/message.h @@ -2,7 +2,7 @@ * message.h * Exports from replication/logical/message.c * - * Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Copyright (c) 2013-2021, PostgreSQL Global Development Group * * src/include/replication/message.h *------------------------------------------------------------------------- diff --git a/src/include/replication/origin.h b/src/include/replication/origin.h index 7e063750d0103..731445ae8f792 100644 --- a/src/include/replication/origin.h +++ b/src/include/replication/origin.h @@ -2,7 +2,7 @@ * origin.h * Exports from replication/logical/origin.c * - * Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Copyright (c) 2013-2021, PostgreSQL Global Development Group * * src/include/replication/origin.h *------------------------------------------------------------------------- diff --git a/src/include/replication/output_plugin.h b/src/include/replication/output_plugin.h index 89e1dc3517d66..2c2c964c55ffc 100644 --- a/src/include/replication/output_plugin.h +++ b/src/include/replication/output_plugin.h @@ -2,7 +2,7 @@ * output_plugin.h * PostgreSQL Logical Decode Plugin Interface * - * Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Copyright (c) 2012-2021, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/include/replication/pgoutput.h b/src/include/replication/pgoutput.h index a8c676ed23b52..4ba052fe38a18 100644 --- a/src/include/replication/pgoutput.h +++ b/src/include/replication/pgoutput.h @@ -3,7 +3,7 @@ * pgoutput.h * Logical Replication output plugin * - * Copyright (c) 2015-2020, PostgreSQL Global Development Group + * Copyright (c) 2015-2021, PostgreSQL Global Development Group * * IDENTIFICATION * pgoutput.h diff --git a/src/include/replication/reorderbuffer.h b/src/include/replication/reorderbuffer.h index 1e60afe70f4a0..9f982137d9373 100644 --- a/src/include/replication/reorderbuffer.h +++ b/src/include/replication/reorderbuffer.h @@ -2,7 +2,7 @@ * reorderbuffer.h * PostgreSQL logical replay/reorder buffer management. * - * Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Copyright (c) 2012-2021, PostgreSQL Global Development Group * * src/include/replication/reorderbuffer.h */ diff --git a/src/include/replication/slot.h b/src/include/replication/slot.h index 63bab6967fb58..53f636c56f5b3 100644 --- a/src/include/replication/slot.h +++ b/src/include/replication/slot.h @@ -2,7 +2,7 @@ * slot.h * Replication slot management. * - * Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Copyright (c) 2012-2021, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/src/include/replication/snapbuild.h b/src/include/replication/snapbuild.h index 7f0f3ca1def50..d9f187a58ec2d 100644 --- a/src/include/replication/snapbuild.h +++ b/src/include/replication/snapbuild.h @@ -3,7 +3,7 @@ * snapbuild.h * Exports from replication/logical/snapbuild.c. * - * Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Copyright (c) 2012-2021, PostgreSQL Global Development Group * * src/include/replication/snapbuild.h * diff --git a/src/include/replication/syncrep.h b/src/include/replication/syncrep.h index 9d286b66c6569..4266afde8bea8 100644 --- a/src/include/replication/syncrep.h +++ b/src/include/replication/syncrep.h @@ -3,7 +3,7 @@ * syncrep.h * Exports from replication/syncrep.c. * - * Portions Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/include/replication/syncrep.h diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h index 1b05b39df4bd1..4313f516d3562 100644 --- a/src/include/replication/walreceiver.h +++ b/src/include/replication/walreceiver.h @@ -3,7 +3,7 @@ * walreceiver.h * Exports from replication/walreceiverfuncs.c. * - * Portions Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2021, PostgreSQL Global Development Group * * src/include/replication/walreceiver.h * diff --git a/src/include/replication/walsender.h b/src/include/replication/walsender.h index 40d81b87f07bf..828106933caf9 100644 --- a/src/include/replication/walsender.h +++ b/src/include/replication/walsender.h @@ -3,7 +3,7 @@ * walsender.h * Exports from replication/walsender.c. * - * Portions Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2021, PostgreSQL Global Development Group * * src/include/replication/walsender.h * diff --git a/src/include/replication/walsender_private.h b/src/include/replication/walsender_private.h index 509856c057ec3..68571072e703d 100644 --- a/src/include/replication/walsender_private.h +++ b/src/include/replication/walsender_private.h @@ -3,7 +3,7 @@ * walsender_private.h * Private definitions from replication/walsender.c. * - * Portions Copyright (c) 2010-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2010-2021, PostgreSQL Global Development Group * * src/include/replication/walsender_private.h * diff --git a/src/include/replication/worker_internal.h b/src/include/replication/worker_internal.h index 6602b23edc51a..d046022e49cff 100644 --- a/src/include/replication/worker_internal.h +++ b/src/include/replication/worker_internal.h @@ -3,7 +3,7 @@ * worker_internal.h * Internal headers shared by logical replication workers. * - * Portions Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2016-2021, PostgreSQL Global Development Group * * src/include/replication/worker_internal.h * diff --git a/src/include/rewrite/prs2lock.h b/src/include/rewrite/prs2lock.h index 84ee6a5809c43..8c356550e1bdb 100644 --- a/src/include/rewrite/prs2lock.h +++ b/src/include/rewrite/prs2lock.h @@ -3,7 +3,7 @@ * prs2lock.h * data structures for POSTGRES Rule System II (rewrite rules only) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/rewrite/prs2lock.h diff --git a/src/include/rewrite/rewriteDefine.h b/src/include/rewrite/rewriteDefine.h index c25733a4b7dd5..b5dd36aab7ee7 100644 --- a/src/include/rewrite/rewriteDefine.h +++ b/src/include/rewrite/rewriteDefine.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/rewrite/rewriteDefine.h diff --git a/src/include/rewrite/rewriteHandler.h b/src/include/rewrite/rewriteHandler.h index a18211f4a23ce..1fea1a4691ab0 100644 --- a/src/include/rewrite/rewriteHandler.h +++ b/src/include/rewrite/rewriteHandler.h @@ -4,7 +4,7 @@ * External interface to query rewriter. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/rewrite/rewriteHandler.h diff --git a/src/include/rewrite/rewriteManip.h b/src/include/rewrite/rewriteManip.h index 5ece81612de5f..812414e63f94f 100644 --- a/src/include/rewrite/rewriteManip.h +++ b/src/include/rewrite/rewriteManip.h @@ -4,7 +4,7 @@ * Querytree manipulation subroutines for query rewriter. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/rewrite/rewriteManip.h diff --git a/src/include/rewrite/rewriteRemove.h b/src/include/rewrite/rewriteRemove.h index f07896c5f3a31..08277becca1dd 100644 --- a/src/include/rewrite/rewriteRemove.h +++ b/src/include/rewrite/rewriteRemove.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/rewrite/rewriteRemove.h diff --git a/src/include/rewrite/rewriteSupport.h b/src/include/rewrite/rewriteSupport.h index f58f356c1142f..bf0014ffb51a9 100644 --- a/src/include/rewrite/rewriteSupport.h +++ b/src/include/rewrite/rewriteSupport.h @@ -4,7 +4,7 @@ * * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/rewrite/rewriteSupport.h diff --git a/src/include/rewrite/rowsecurity.h b/src/include/rewrite/rowsecurity.h index 2e0bac5a980cd..22476de971a75 100644 --- a/src/include/rewrite/rowsecurity.h +++ b/src/include/rewrite/rowsecurity.h @@ -5,7 +5,7 @@ * prototypes for rewrite/rowsecurity.c and the structures for managing * the row security policies for relations in relcache. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * ------------------------------------------------------------------------- diff --git a/src/include/rusagestub.h b/src/include/rusagestub.h index 3a812a29bc56b..211750380bf8d 100644 --- a/src/include/rusagestub.h +++ b/src/include/rusagestub.h @@ -4,7 +4,7 @@ * Stubs for getrusage(3). * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/rusagestub.h diff --git a/src/include/snowball/header.h b/src/include/snowball/header.h index 912e072adf65d..48521d7040a40 100644 --- a/src/include/snowball/header.h +++ b/src/include/snowball/header.h @@ -13,7 +13,7 @@ * * NOTE: this file should not be included into any non-snowball sources! * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * src/include/snowball/header.h * diff --git a/src/include/statistics/extended_stats_internal.h b/src/include/statistics/extended_stats_internal.h index 02bf6a0502751..c849bd57c03ab 100644 --- a/src/include/statistics/extended_stats_internal.h +++ b/src/include/statistics/extended_stats_internal.h @@ -3,7 +3,7 @@ * extended_stats_internal.h * POSTGRES extended statistics internal declarations * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/statistics/statistics.h b/src/include/statistics/statistics.h index c9ed21155cd73..fec50688ea490 100644 --- a/src/include/statistics/statistics.h +++ b/src/include/statistics/statistics.h @@ -3,7 +3,7 @@ * statistics.h * Extended statistics and selectivity estimation functions. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/statistics/statistics.h diff --git a/src/include/storage/backendid.h b/src/include/storage/backendid.h index e5fe0e724c835..7aa3936899410 100644 --- a/src/include/storage/backendid.h +++ b/src/include/storage/backendid.h @@ -4,7 +4,7 @@ * POSTGRES backend id communication definitions * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/backendid.h diff --git a/src/include/storage/barrier.h b/src/include/storage/barrier.h index e0de24378bff9..ba997717fd166 100644 --- a/src/include/storage/barrier.h +++ b/src/include/storage/barrier.h @@ -3,7 +3,7 @@ * barrier.h * Barriers for synchronizing cooperating processes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/barrier.h diff --git a/src/include/storage/block.h b/src/include/storage/block.h index d73e3930516a0..4a5c476d2d0a0 100644 --- a/src/include/storage/block.h +++ b/src/include/storage/block.h @@ -4,7 +4,7 @@ * POSTGRES disk block definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/block.h diff --git a/src/include/storage/buf.h b/src/include/storage/buf.h index dde87f8f6f14b..ad72919941daa 100644 --- a/src/include/storage/buf.h +++ b/src/include/storage/buf.h @@ -4,7 +4,7 @@ * Basic buffer manager data types. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/buf.h diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h index 3377fa5676800..f6b5782965395 100644 --- a/src/include/storage/buf_internals.h +++ b/src/include/storage/buf_internals.h @@ -5,7 +5,7 @@ * strategy. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/buf_internals.h diff --git a/src/include/storage/buffile.h b/src/include/storage/buffile.h index fc34c49522dae..566523de1fa31 100644 --- a/src/include/storage/buffile.h +++ b/src/include/storage/buffile.h @@ -15,7 +15,7 @@ * but currently we have no need for oversize temp files without buffered * access. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/buffile.h diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h index ee91b8fa26c17..ff6cd0fc54e36 100644 --- a/src/include/storage/bufmgr.h +++ b/src/include/storage/bufmgr.h @@ -4,7 +4,7 @@ * POSTGRES buffer manager definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/bufmgr.h diff --git a/src/include/storage/bufpage.h b/src/include/storage/bufpage.h index d0a52f8e08fc9..359b749f7f408 100644 --- a/src/include/storage/bufpage.h +++ b/src/include/storage/bufpage.h @@ -4,7 +4,7 @@ * Standard POSTGRES buffer page definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/bufpage.h diff --git a/src/include/storage/checksum.h b/src/include/storage/checksum.h index 6e77744cbce7e..80d2359192198 100644 --- a/src/include/storage/checksum.h +++ b/src/include/storage/checksum.h @@ -3,7 +3,7 @@ * checksum.h * Checksum implementation for data pages. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/checksum.h diff --git a/src/include/storage/checksum_impl.h b/src/include/storage/checksum_impl.h index 364acfafd21cc..ef30268330a73 100644 --- a/src/include/storage/checksum_impl.h +++ b/src/include/storage/checksum_impl.h @@ -8,7 +8,7 @@ * referenced by storage/checksum.h. (Note: you may need to redefine * Assert() as empty to compile this successfully externally.) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/checksum_impl.h diff --git a/src/include/storage/condition_variable.h b/src/include/storage/condition_variable.h index ad209acfac068..0b7578f8c4cc5 100644 --- a/src/include/storage/condition_variable.h +++ b/src/include/storage/condition_variable.h @@ -12,7 +12,7 @@ * can be canceled prior to the fulfillment of the condition) and do not * use pointers internally (so that they are safe to use within DSMs). * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/condition_variable.h diff --git a/src/include/storage/copydir.h b/src/include/storage/copydir.h index 5d28f59c1d3af..2c3936b0dad8b 100644 --- a/src/include/storage/copydir.h +++ b/src/include/storage/copydir.h @@ -3,7 +3,7 @@ * copydir.h * Copy a directory. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/copydir.h diff --git a/src/include/storage/dsm.h b/src/include/storage/dsm.h index 0455576f4af4c..e4e3e9b3f742f 100644 --- a/src/include/storage/dsm.h +++ b/src/include/storage/dsm.h @@ -3,7 +3,7 @@ * dsm.h * manage dynamic shared memory segments * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/dsm.h diff --git a/src/include/storage/dsm_impl.h b/src/include/storage/dsm_impl.h index f6841e2534f96..ff72f7b0e58a0 100644 --- a/src/include/storage/dsm_impl.h +++ b/src/include/storage/dsm_impl.h @@ -3,7 +3,7 @@ * dsm_impl.h * low-level dynamic shared memory primitives * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/dsm_impl.h diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h index 4e1cc12e239aa..f2662a96fd7bb 100644 --- a/src/include/storage/fd.h +++ b/src/include/storage/fd.h @@ -4,7 +4,7 @@ * Virtual file descriptor definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/fd.h diff --git a/src/include/storage/freespace.h b/src/include/storage/freespace.h index 81668ada1934d..600826ca4b78a 100644 --- a/src/include/storage/freespace.h +++ b/src/include/storage/freespace.h @@ -4,7 +4,7 @@ * POSTGRES free space map for quickly finding free space in relations * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/freespace.h diff --git a/src/include/storage/fsm_internals.h b/src/include/storage/fsm_internals.h index 48d25a1f9f01a..09749769b3c8d 100644 --- a/src/include/storage/fsm_internals.h +++ b/src/include/storage/fsm_internals.h @@ -4,7 +4,7 @@ * internal functions for free space map * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/fsm_internals.h diff --git a/src/include/storage/indexfsm.h b/src/include/storage/indexfsm.h index fb896b43df773..1885b816a2731 100644 --- a/src/include/storage/indexfsm.h +++ b/src/include/storage/indexfsm.h @@ -4,7 +4,7 @@ * POSTGRES free space map for quickly finding an unused page in index * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/indexfsm.h diff --git a/src/include/storage/ipc.h b/src/include/storage/ipc.h index 88994fdc260bc..753a6dd4d7e97 100644 --- a/src/include/storage/ipc.h +++ b/src/include/storage/ipc.h @@ -8,7 +8,7 @@ * exit-time cleanup for either a postmaster or a backend. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/ipc.h diff --git a/src/include/storage/item.h b/src/include/storage/item.h index 43a47261fbed3..cb439655362bb 100644 --- a/src/include/storage/item.h +++ b/src/include/storage/item.h @@ -4,7 +4,7 @@ * POSTGRES disk item definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/item.h diff --git a/src/include/storage/itemid.h b/src/include/storage/itemid.h index 5b0229b6a40b6..d1f0e382485c5 100644 --- a/src/include/storage/itemid.h +++ b/src/include/storage/itemid.h @@ -4,7 +4,7 @@ * Standard POSTGRES buffer page item identifier/line pointer definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/itemid.h diff --git a/src/include/storage/itemptr.h b/src/include/storage/itemptr.h index 944f6fe6bd36a..0e6990140b801 100644 --- a/src/include/storage/itemptr.h +++ b/src/include/storage/itemptr.h @@ -4,7 +4,7 @@ * POSTGRES disk item pointer definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/itemptr.h diff --git a/src/include/storage/large_object.h b/src/include/storage/large_object.h index 2623d1a1b0c4b..ae1e2482eaa57 100644 --- a/src/include/storage/large_object.h +++ b/src/include/storage/large_object.h @@ -5,7 +5,7 @@ * zillions of large objects (internal, external, jaquith, inversion). * Now we only support inversion. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/large_object.h diff --git a/src/include/storage/latch.h b/src/include/storage/latch.h index 7c742021fb1b1..1468f30a8e00e 100644 --- a/src/include/storage/latch.h +++ b/src/include/storage/latch.h @@ -90,7 +90,7 @@ * efficient than using WaitLatch or WaitLatchOrSocket. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/latch.h diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h index f7cabcbbf550e..b009559229b66 100644 --- a/src/include/storage/lmgr.h +++ b/src/include/storage/lmgr.h @@ -4,7 +4,7 @@ * POSTGRES lock manager definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/lmgr.h diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h index 1c3e9c1999f56..2e6ef174e9a72 100644 --- a/src/include/storage/lock.h +++ b/src/include/storage/lock.h @@ -4,7 +4,7 @@ * POSTGRES low-level lock mechanism * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/lock.h diff --git a/src/include/storage/lockdefs.h b/src/include/storage/lockdefs.h index ef0daf708d177..f99ad0eff609c 100644 --- a/src/include/storage/lockdefs.h +++ b/src/include/storage/lockdefs.h @@ -7,7 +7,7 @@ * contains definition that have to (indirectly) be available when included by * FRONTEND code. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/lockdefs.h diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h index af9b41795d26d..cbf2510fbf565 100644 --- a/src/include/storage/lwlock.h +++ b/src/include/storage/lwlock.h @@ -4,7 +4,7 @@ * Lightweight lock manager * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/lwlock.h diff --git a/src/include/storage/md.h b/src/include/storage/md.h index 07fd1bb7d06c8..752b440864d84 100644 --- a/src/include/storage/md.h +++ b/src/include/storage/md.h @@ -4,7 +4,7 @@ * magnetic disk storage manager public interface declarations. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/md.h diff --git a/src/include/storage/off.h b/src/include/storage/off.h index 9bfdec8c234ab..a5df0ab219dd3 100644 --- a/src/include/storage/off.h +++ b/src/include/storage/off.h @@ -4,7 +4,7 @@ * POSTGRES disk "offset" definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/off.h diff --git a/src/include/storage/pg_sema.h b/src/include/storage/pg_sema.h index ef8a7b48f7c3f..3112a8ce22d95 100644 --- a/src/include/storage/pg_sema.h +++ b/src/include/storage/pg_sema.h @@ -10,7 +10,7 @@ * be provided by each port. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/pg_sema.h diff --git a/src/include/storage/pg_shmem.h b/src/include/storage/pg_shmem.h index 9992932a00597..059df1b72c23f 100644 --- a/src/include/storage/pg_shmem.h +++ b/src/include/storage/pg_shmem.h @@ -14,7 +14,7 @@ * only one ID number. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/pg_shmem.h diff --git a/src/include/storage/pmsignal.h b/src/include/storage/pmsignal.h index b6aa158160ad9..dbbed18f617e4 100644 --- a/src/include/storage/pmsignal.h +++ b/src/include/storage/pmsignal.h @@ -4,7 +4,7 @@ * routines for signaling between the postmaster and its child processes * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/pmsignal.h diff --git a/src/include/storage/predicate.h b/src/include/storage/predicate.h index 86e756d5fb67f..152b6986114be 100644 --- a/src/include/storage/predicate.h +++ b/src/include/storage/predicate.h @@ -4,7 +4,7 @@ * POSTGRES public predicate locking definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/predicate.h diff --git a/src/include/storage/predicate_internals.h b/src/include/storage/predicate_internals.h index cf9694d65e3bb..104f560d380a0 100644 --- a/src/include/storage/predicate_internals.h +++ b/src/include/storage/predicate_internals.h @@ -4,7 +4,7 @@ * POSTGRES internal predicate locking definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/predicate_internals.h diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index e77f76ae8a18a..989c5849d4583 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -4,7 +4,7 @@ * per-process shared memory data structures * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/proc.h diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h index ea8a876ca45c6..f40b20f7eac84 100644 --- a/src/include/storage/procarray.h +++ b/src/include/storage/procarray.h @@ -4,7 +4,7 @@ * POSTGRES process array definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/procarray.h diff --git a/src/include/storage/proclist.h b/src/include/storage/proclist.h index 94200911d90f1..afdd4f8f0be1b 100644 --- a/src/include/storage/proclist.h +++ b/src/include/storage/proclist.h @@ -10,7 +10,7 @@ * See proclist_types.h for the structs that these functions operate on. They * are separated to break a header dependency cycle with proc.h. * - * Portions Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2016-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/include/storage/proclist.h diff --git a/src/include/storage/proclist_types.h b/src/include/storage/proclist_types.h index aba5578899b03..b2d6e8265e20e 100644 --- a/src/include/storage/proclist_types.h +++ b/src/include/storage/proclist_types.h @@ -5,7 +5,7 @@ * * See proclist.h for functions that operate on these types. * - * Portions Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2016-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/include/storage/proclist_types.h diff --git a/src/include/storage/procsignal.h b/src/include/storage/procsignal.h index 5cb39697f38f9..4ae7dc33b8e12 100644 --- a/src/include/storage/procsignal.h +++ b/src/include/storage/procsignal.h @@ -4,7 +4,7 @@ * Routines for interprocess signaling * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/procsignal.h diff --git a/src/include/storage/reinit.h b/src/include/storage/reinit.h index 15d2e410dc86b..fad1e5c4732a2 100644 --- a/src/include/storage/reinit.h +++ b/src/include/storage/reinit.h @@ -4,7 +4,7 @@ * Reinitialization of unlogged relations * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/reinit.h diff --git a/src/include/storage/relfilenode.h b/src/include/storage/relfilenode.h index 4de9fc1e69872..5e36d3b93ce01 100644 --- a/src/include/storage/relfilenode.h +++ b/src/include/storage/relfilenode.h @@ -4,7 +4,7 @@ * Physical access information for relations. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/relfilenode.h diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h index 31a5ca6fb32d6..254c40d477912 100644 --- a/src/include/storage/s_lock.h +++ b/src/include/storage/s_lock.h @@ -86,7 +86,7 @@ * when using the SysV semaphore code. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/s_lock.h diff --git a/src/include/storage/sharedfileset.h b/src/include/storage/sharedfileset.h index d5edb600af966..09ba121aafadf 100644 --- a/src/include/storage/sharedfileset.h +++ b/src/include/storage/sharedfileset.h @@ -4,7 +4,7 @@ * Shared temporary file management. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/sharedfileset.h diff --git a/src/include/storage/shm_mq.h b/src/include/storage/shm_mq.h index 5005f2ced8a7a..e693f3f760090 100644 --- a/src/include/storage/shm_mq.h +++ b/src/include/storage/shm_mq.h @@ -3,7 +3,7 @@ * shm_mq.h * single-reader, single-writer shared memory message queue * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/shm_mq.h diff --git a/src/include/storage/shm_toc.h b/src/include/storage/shm_toc.h index c3886d538d726..dd29a59351e83 100644 --- a/src/include/storage/shm_toc.h +++ b/src/include/storage/shm_toc.h @@ -12,7 +12,7 @@ * other data structure within the segment and only put the pointer to * the data structure itself in the table of contents. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/shm_toc.h diff --git a/src/include/storage/shmem.h b/src/include/storage/shmem.h index e9e32ab8f1fa0..31024e5a50f39 100644 --- a/src/include/storage/shmem.h +++ b/src/include/storage/shmem.h @@ -11,7 +11,7 @@ * at the same address. This means shared memory pointers can be passed * around directly between different processes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/shmem.h diff --git a/src/include/storage/sinval.h b/src/include/storage/sinval.h index 903818bea3170..f03dc23b14607 100644 --- a/src/include/storage/sinval.h +++ b/src/include/storage/sinval.h @@ -4,7 +4,7 @@ * POSTGRES shared cache invalidation communication definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/sinval.h diff --git a/src/include/storage/sinvaladt.h b/src/include/storage/sinvaladt.h index 426f5478ba5ac..14148bf82010d 100644 --- a/src/include/storage/sinvaladt.h +++ b/src/include/storage/sinvaladt.h @@ -12,7 +12,7 @@ * The struct type SharedInvalidationMessage, defining the contents of * a single message, is defined in sinval.h. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/sinvaladt.h diff --git a/src/include/storage/smgr.h b/src/include/storage/smgr.h index f28a842401326..ebf4a199dcb4d 100644 --- a/src/include/storage/smgr.h +++ b/src/include/storage/smgr.h @@ -4,7 +4,7 @@ * storage manager switch public interface declarations. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/smgr.h diff --git a/src/include/storage/spin.h b/src/include/storage/spin.h index 5ad25d0f6fc62..ef067981429e3 100644 --- a/src/include/storage/spin.h +++ b/src/include/storage/spin.h @@ -41,7 +41,7 @@ * be again. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/spin.h diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h index faaf1d3817b6c..9b5cc01c97b53 100644 --- a/src/include/storage/standby.h +++ b/src/include/storage/standby.h @@ -4,7 +4,7 @@ * Definitions for hot standby mode. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/standby.h diff --git a/src/include/storage/standbydefs.h b/src/include/storage/standbydefs.h index 4dda1c403a4b8..d99e6f40c6dfd 100644 --- a/src/include/storage/standbydefs.h +++ b/src/include/storage/standbydefs.h @@ -4,7 +4,7 @@ * Frontend exposed definitions for hot standby mode. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/standbydefs.h diff --git a/src/include/storage/sync.h b/src/include/storage/sync.h index f32e412e751d9..fbdf34f7620b6 100644 --- a/src/include/storage/sync.h +++ b/src/include/storage/sync.h @@ -3,7 +3,7 @@ * sync.h * File synchronization management code. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/storage/sync.h diff --git a/src/include/tcop/cmdtag.h b/src/include/tcop/cmdtag.h index f75a91e7c8e7f..f67b2528f61a2 100644 --- a/src/include/tcop/cmdtag.h +++ b/src/include/tcop/cmdtag.h @@ -3,7 +3,7 @@ * cmdtag.h * Declarations for commandtag names and enumeration. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/tcop/cmdtag.h diff --git a/src/include/tcop/cmdtaglist.h b/src/include/tcop/cmdtaglist.h index be94852bbd30d..9ba24d4ca9a35 100644 --- a/src/include/tcop/cmdtaglist.h +++ b/src/include/tcop/cmdtaglist.h @@ -8,7 +8,7 @@ * determined by the PG_CMDTAG macro, which is not defined in this file; * it can be defined by the caller for special purposes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/tcop/cmdtaglist.h diff --git a/src/include/tcop/deparse_utility.h b/src/include/tcop/deparse_utility.h index 10c74ff13b68e..371c6f33bc102 100644 --- a/src/include/tcop/deparse_utility.h +++ b/src/include/tcop/deparse_utility.h @@ -2,7 +2,7 @@ * * deparse_utility.h * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/tcop/deparse_utility.h diff --git a/src/include/tcop/dest.h b/src/include/tcop/dest.h index 2e07f1516d16b..88a7e59de548b 100644 --- a/src/include/tcop/dest.h +++ b/src/include/tcop/dest.h @@ -57,7 +57,7 @@ * calls in portal and cursor manipulations. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/tcop/dest.h diff --git a/src/include/tcop/fastpath.h b/src/include/tcop/fastpath.h index 3bb992c02c781..b67c44fe69e73 100644 --- a/src/include/tcop/fastpath.h +++ b/src/include/tcop/fastpath.h @@ -3,7 +3,7 @@ * fastpath.h * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/tcop/fastpath.h diff --git a/src/include/tcop/pquery.h b/src/include/tcop/pquery.h index 437642cc72c68..ed2c4d374b010 100644 --- a/src/include/tcop/pquery.h +++ b/src/include/tcop/pquery.h @@ -4,7 +4,7 @@ * prototypes for pquery.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/tcop/pquery.h diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h index bd30607b070f4..e5472100a436d 100644 --- a/src/include/tcop/tcopprot.h +++ b/src/include/tcop/tcopprot.h @@ -4,7 +4,7 @@ * prototypes for postgres.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/tcop/tcopprot.h diff --git a/src/include/tcop/utility.h b/src/include/tcop/utility.h index 9594856c88aad..841062b4b35bb 100644 --- a/src/include/tcop/utility.h +++ b/src/include/tcop/utility.h @@ -4,7 +4,7 @@ * prototypes for utility.c. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/tcop/utility.h diff --git a/src/include/tsearch/dicts/regis.h b/src/include/tsearch/dicts/regis.h index 014a409b84539..5411926e9e6e6 100644 --- a/src/include/tsearch/dicts/regis.h +++ b/src/include/tsearch/dicts/regis.h @@ -4,7 +4,7 @@ * * Declarations for fast regex subset, used by ISpell * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * src/include/tsearch/dicts/regis.h * diff --git a/src/include/tsearch/dicts/spell.h b/src/include/tsearch/dicts/spell.h index 7bb29376136cd..9847e30208c7e 100644 --- a/src/include/tsearch/dicts/spell.h +++ b/src/include/tsearch/dicts/spell.h @@ -4,7 +4,7 @@ * * Declarations for ISpell dictionary * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * src/include/tsearch/dicts/spell.h * diff --git a/src/include/tsearch/ts_cache.h b/src/include/tsearch/ts_cache.h index 9149796466f7e..888f7028b1eab 100644 --- a/src/include/tsearch/ts_cache.h +++ b/src/include/tsearch/ts_cache.h @@ -3,7 +3,7 @@ * ts_cache.h * Tsearch related object caches. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/tsearch/ts_cache.h diff --git a/src/include/tsearch/ts_locale.h b/src/include/tsearch/ts_locale.h index f1669fda2111b..cfd34b3244357 100644 --- a/src/include/tsearch/ts_locale.h +++ b/src/include/tsearch/ts_locale.h @@ -3,7 +3,7 @@ * ts_locale.h * locale compatibility layer for tsearch * - * Copyright (c) 1998-2020, PostgreSQL Global Development Group + * Copyright (c) 1998-2021, PostgreSQL Global Development Group * * src/include/tsearch/ts_locale.h * diff --git a/src/include/tsearch/ts_public.h b/src/include/tsearch/ts_public.h index 63aca2b1f5124..adb9ae5fb9c29 100644 --- a/src/include/tsearch/ts_public.h +++ b/src/include/tsearch/ts_public.h @@ -4,7 +4,7 @@ * Public interface to various tsearch modules, such as * parsers and dictionaries. * - * Copyright (c) 1998-2020, PostgreSQL Global Development Group + * Copyright (c) 1998-2021, PostgreSQL Global Development Group * * src/include/tsearch/ts_public.h * diff --git a/src/include/tsearch/ts_type.h b/src/include/tsearch/ts_type.h index e7edca9f167c0..7f44f1b14d39b 100644 --- a/src/include/tsearch/ts_type.h +++ b/src/include/tsearch/ts_type.h @@ -3,7 +3,7 @@ * ts_type.h * Definitions for the tsvector and tsquery types * - * Copyright (c) 1998-2020, PostgreSQL Global Development Group + * Copyright (c) 1998-2021, PostgreSQL Global Development Group * * src/include/tsearch/ts_type.h * diff --git a/src/include/tsearch/ts_utils.h b/src/include/tsearch/ts_utils.h index 400ba33001484..69a9ba8524ed3 100644 --- a/src/include/tsearch/ts_utils.h +++ b/src/include/tsearch/ts_utils.h @@ -3,7 +3,7 @@ * ts_utils.h * helper utilities for tsearch * - * Copyright (c) 1998-2020, PostgreSQL Global Development Group + * Copyright (c) 1998-2021, PostgreSQL Global Development Group * * src/include/tsearch/ts_utils.h * diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h index b263d92903234..541a438387bdf 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -4,7 +4,7 @@ * Definition of (and support for) access control list data structures. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/acl.h diff --git a/src/include/utils/aclchk_internal.h b/src/include/utils/aclchk_internal.h index 81ddf935ebd3a..946ba7aa1aecd 100644 --- a/src/include/utils/aclchk_internal.h +++ b/src/include/utils/aclchk_internal.h @@ -2,7 +2,7 @@ * * aclchk_internal.h * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/aclchk_internal.h diff --git a/src/include/utils/array.h b/src/include/utils/array.h index 16925880a1eb2..937caf7565b02 100644 --- a/src/include/utils/array.h +++ b/src/include/utils/array.h @@ -51,7 +51,7 @@ * arrays holding the elements. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/array.h diff --git a/src/include/utils/arrayaccess.h b/src/include/utils/arrayaccess.h index 674bf51fe48f1..d0483b2aa76d7 100644 --- a/src/include/utils/arrayaccess.h +++ b/src/include/utils/arrayaccess.h @@ -4,7 +4,7 @@ * Declarations for element-by-element access to Postgres arrays. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/arrayaccess.h diff --git a/src/include/utils/ascii.h b/src/include/utils/ascii.h index 0fe0d48f9e107..c246f40742794 100644 --- a/src/include/utils/ascii.h +++ b/src/include/utils/ascii.h @@ -1,7 +1,7 @@ /*----------------------------------------------------------------------- * ascii.h * - * Portions Copyright (c) 1999-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1999-2021, PostgreSQL Global Development Group * * src/include/utils/ascii.h * diff --git a/src/include/utils/attoptcache.h b/src/include/utils/attoptcache.h index 80b55271ffb8b..f55a9b6ee886c 100644 --- a/src/include/utils/attoptcache.h +++ b/src/include/utils/attoptcache.h @@ -3,7 +3,7 @@ * attoptcache.h * Attribute options cache. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/attoptcache.h diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 19271e0696067..6f739a882204c 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -4,7 +4,7 @@ * Declarations for operations on built-in types. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/builtins.h diff --git a/src/include/utils/bytea.h b/src/include/utils/bytea.h index d89ba2ba5e7e6..eb9df9e4f7b0d 100644 --- a/src/include/utils/bytea.h +++ b/src/include/utils/bytea.h @@ -4,7 +4,7 @@ * Declarations for BYTEA data type support. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/bytea.h diff --git a/src/include/utils/catcache.h b/src/include/utils/catcache.h index f4aa316604e6d..ddc2762eb3fa8 100644 --- a/src/include/utils/catcache.h +++ b/src/include/utils/catcache.h @@ -10,7 +10,7 @@ * guarantee that there can only be one matching row for a key combination. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/catcache.h diff --git a/src/include/utils/combocid.h b/src/include/utils/combocid.h index b39166a685453..7f2e1f7019d66 100644 --- a/src/include/utils/combocid.h +++ b/src/include/utils/combocid.h @@ -4,7 +4,7 @@ * Combo command ID support routines * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/combocid.h diff --git a/src/include/utils/date.h b/src/include/utils/date.h index 6fc491e6a6d77..89f15e72fa803 100644 --- a/src/include/utils/date.h +++ b/src/include/utils/date.h @@ -4,7 +4,7 @@ * Definitions for the SQL "date" and "time" types. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/date.h diff --git a/src/include/utils/datetime.h b/src/include/utils/datetime.h index 711bd02af0dc4..b56086c9d6430 100644 --- a/src/include/utils/datetime.h +++ b/src/include/utils/datetime.h @@ -6,7 +6,7 @@ * including date, and time. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/datetime.h diff --git a/src/include/utils/datum.h b/src/include/utils/datum.h index 9118a9388aa55..d4cf62bed7322 100644 --- a/src/include/utils/datum.h +++ b/src/include/utils/datum.h @@ -8,7 +8,7 @@ * of the Datum. (We do it this way because in most situations the caller * can look up the info just once and use it for many per-datum operations.) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/datum.h diff --git a/src/include/utils/dsa.h b/src/include/utils/dsa.h index e07126bc9a48b..74b69de6b0110 100644 --- a/src/include/utils/dsa.h +++ b/src/include/utils/dsa.h @@ -3,7 +3,7 @@ * dsa.h * Dynamic shared memory areas. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/utils/dynahash.h b/src/include/utils/dynahash.h index 768b95217609a..2f6adc2ef9c5a 100644 --- a/src/include/utils/dynahash.h +++ b/src/include/utils/dynahash.h @@ -4,7 +4,7 @@ * POSTGRES dynahash.h file definitions * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/dynahash.h diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h index d2bdfa0be3a97..3c0e57621fc25 100644 --- a/src/include/utils/elog.h +++ b/src/include/utils/elog.h @@ -4,7 +4,7 @@ * POSTGRES error reporting/logging definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/elog.h diff --git a/src/include/utils/evtcache.h b/src/include/utils/evtcache.h index bb1e39eb649b2..58ddb71cb12a1 100644 --- a/src/include/utils/evtcache.h +++ b/src/include/utils/evtcache.h @@ -3,7 +3,7 @@ * evtcache.h * Special-purpose cache for event trigger data. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/utils/expandeddatum.h b/src/include/utils/expandeddatum.h index be4970fa9cacd..f1815a8cd6a9d 100644 --- a/src/include/utils/expandeddatum.h +++ b/src/include/utils/expandeddatum.h @@ -34,7 +34,7 @@ * value if they fail partway through. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/expandeddatum.h diff --git a/src/include/utils/expandedrecord.h b/src/include/utils/expandedrecord.h index 75b578934560c..0f744b175ef7e 100644 --- a/src/include/utils/expandedrecord.h +++ b/src/include/utils/expandedrecord.h @@ -3,7 +3,7 @@ * expandedrecord.h * Declarations for composite expanded objects. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/expandedrecord.h diff --git a/src/include/utils/float.h b/src/include/utils/float.h index 79bf8daca8094..fcf7bd581bd97 100644 --- a/src/include/utils/float.h +++ b/src/include/utils/float.h @@ -3,7 +3,7 @@ * float.h * Definitions for the built-in floating-point types * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/include/utils/fmgrtab.h b/src/include/utils/fmgrtab.h index 8e822c41ebc3b..21a5f21156f7f 100644 --- a/src/include/utils/fmgrtab.h +++ b/src/include/utils/fmgrtab.h @@ -3,7 +3,7 @@ * fmgrtab.h * The function manager's table of internal functions. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/fmgrtab.h diff --git a/src/include/utils/formatting.h b/src/include/utils/formatting.h index 8f62aa38e935d..93f979f32091f 100644 --- a/src/include/utils/formatting.h +++ b/src/include/utils/formatting.h @@ -4,7 +4,7 @@ * src/include/utils/formatting.h * * - * Portions Copyright (c) 1999-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1999-2021, PostgreSQL Global Development Group * * The PostgreSQL routines for a DateTime/int/float/numeric formatting, * inspired by the Oracle TO_CHAR() / TO_DATE() / TO_NUMBER() routines. diff --git a/src/include/utils/freepage.h b/src/include/utils/freepage.h index b758fafe024ef..59f50ad30c688 100644 --- a/src/include/utils/freepage.h +++ b/src/include/utils/freepage.h @@ -3,7 +3,7 @@ * freepage.h * Management of page-organized free memory. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/freepage.h diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h index 1b96990dcc4e5..0b87437d83a93 100644 --- a/src/include/utils/geo_decls.h +++ b/src/include/utils/geo_decls.h @@ -3,7 +3,7 @@ * geo_decls.h - Declarations for various 2D constructs. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/geo_decls.h diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 6a20a3bcece65..5004ee4177900 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -4,7 +4,7 @@ * External declarations pertaining to backend/utils/misc/guc.c and * backend/utils/misc/guc-file.l * - * Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Copyright (c) 2000-2021, PostgreSQL Global Development Group * Written by Peter Eisentraut . * * src/include/utils/guc.h diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h index 7f36e1146f21a..b9b5c1addaca8 100644 --- a/src/include/utils/guc_tables.h +++ b/src/include/utils/guc_tables.h @@ -5,7 +5,7 @@ * * See src/backend/utils/misc/README for design notes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * src/include/utils/guc_tables.h * diff --git a/src/include/utils/help_config.h b/src/include/utils/help_config.h index 1d2345e155a6b..3f277c740b086 100644 --- a/src/include/utils/help_config.h +++ b/src/include/utils/help_config.h @@ -3,7 +3,7 @@ * help_config.h * Interface to the --help-config option of main.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * src/include/utils/help_config.h * diff --git a/src/include/utils/hsearch.h b/src/include/utils/hsearch.h index 13c6602217ecb..d7af0239c8c38 100644 --- a/src/include/utils/hsearch.h +++ b/src/include/utils/hsearch.h @@ -4,7 +4,7 @@ * exported definitions for utils/hash/dynahash.c; see notes therein * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/hsearch.h diff --git a/src/include/utils/index_selfuncs.h b/src/include/utils/index_selfuncs.h index 1710c1d2543bc..289b1b709a34d 100644 --- a/src/include/utils/index_selfuncs.h +++ b/src/include/utils/index_selfuncs.h @@ -9,7 +9,7 @@ * If you make it depend on anything besides access/amapi.h, that's likely * a mistake. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/index_selfuncs.h diff --git a/src/include/utils/inet.h b/src/include/utils/inet.h index f88b075119055..d8c59ca6e6ee2 100644 --- a/src/include/utils/inet.h +++ b/src/include/utils/inet.h @@ -4,7 +4,7 @@ * Declarations for operations on INET datatypes. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/inet.h diff --git a/src/include/utils/int8.h b/src/include/utils/int8.h index c4fec343e7adf..6571188f9030e 100644 --- a/src/include/utils/int8.h +++ b/src/include/utils/int8.h @@ -4,7 +4,7 @@ * Declarations for operations on 64-bit integers. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/int8.h diff --git a/src/include/utils/inval.h b/src/include/utils/inval.h index 463888c3894f9..49ae5d2864692 100644 --- a/src/include/utils/inval.h +++ b/src/include/utils/inval.h @@ -4,7 +4,7 @@ * POSTGRES cache invalidation dispatcher definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/inval.h diff --git a/src/include/utils/json.h b/src/include/utils/json.h index 4345fbdc31632..7daf09f20e311 100644 --- a/src/include/utils/json.h +++ b/src/include/utils/json.h @@ -3,7 +3,7 @@ * json.h * Declarations for JSON data type support. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/json.h diff --git a/src/include/utils/jsonb.h b/src/include/utils/jsonb.h index 58600116931f2..d9f009d19b498 100644 --- a/src/include/utils/jsonb.h +++ b/src/include/utils/jsonb.h @@ -3,7 +3,7 @@ * jsonb.h * Declarations for jsonb data type support. * - * Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Copyright (c) 1996-2021, PostgreSQL Global Development Group * * src/include/utils/jsonb.h * diff --git a/src/include/utils/jsonfuncs.h b/src/include/utils/jsonfuncs.h index 4796b2b78bf9a..0ca48591d04c0 100644 --- a/src/include/utils/jsonfuncs.h +++ b/src/include/utils/jsonfuncs.h @@ -3,7 +3,7 @@ * jsonfuncs.h * Functions to process JSON data types. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/jsonfuncs.h diff --git a/src/include/utils/jsonpath.h b/src/include/utils/jsonpath.h index 4ef0880d9033f..87d302b702852 100644 --- a/src/include/utils/jsonpath.h +++ b/src/include/utils/jsonpath.h @@ -3,7 +3,7 @@ * jsonpath.h * Definitions for jsonpath datatype * - * Copyright (c) 2019-2020, PostgreSQL Global Development Group + * Copyright (c) 2019-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/include/utils/jsonpath.h diff --git a/src/include/utils/logtape.h b/src/include/utils/logtape.h index da5159e4c6c76..85d2e03c631c6 100644 --- a/src/include/utils/logtape.h +++ b/src/include/utils/logtape.h @@ -5,7 +5,7 @@ * * See logtape.c for explanations. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/logtape.h diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h index e5ad7b95d1715..ae720c1496b65 100644 --- a/src/include/utils/lsyscache.h +++ b/src/include/utils/lsyscache.h @@ -3,7 +3,7 @@ * lsyscache.h * Convenience routines for common queries in the system catalog cache. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/lsyscache.h diff --git a/src/include/utils/memdebug.h b/src/include/utils/memdebug.h index efa190a45ebee..e88b4c6e8efbb 100644 --- a/src/include/utils/memdebug.h +++ b/src/include/utils/memdebug.h @@ -7,7 +7,7 @@ * empty definitions for Valgrind client request macros we use. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/memdebug.h diff --git a/src/include/utils/memutils.h b/src/include/utils/memutils.h index 909bc2e988862..36aae4e51c8f0 100644 --- a/src/include/utils/memutils.h +++ b/src/include/utils/memutils.h @@ -7,7 +7,7 @@ * of the API of the memory management subsystem. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/memutils.h diff --git a/src/include/utils/multirangetypes.h b/src/include/utils/multirangetypes.h index 1d877f08b56be..70e9a5370132f 100644 --- a/src/include/utils/multirangetypes.h +++ b/src/include/utils/multirangetypes.h @@ -4,7 +4,7 @@ * Declarations for Postgres multirange types. * * - * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/multirangetypes.h diff --git a/src/include/utils/numeric.h b/src/include/utils/numeric.h index 2a768b9a04ad5..a362b5beb2b8a 100644 --- a/src/include/utils/numeric.h +++ b/src/include/utils/numeric.h @@ -5,7 +5,7 @@ * * Original coding 1998, Jan Wieck. Heavily revised 2003, Tom Lane. * - * Copyright (c) 1998-2020, PostgreSQL Global Development Group + * Copyright (c) 1998-2021, PostgreSQL Global Development Group * * src/include/utils/numeric.h * diff --git a/src/include/utils/old_snapshot.h b/src/include/utils/old_snapshot.h index e6da1833a6341..c9c73f114b3b6 100644 --- a/src/include/utils/old_snapshot.h +++ b/src/include/utils/old_snapshot.h @@ -3,7 +3,7 @@ * old_snapshot.h * Data structures for 'snapshot too old' * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/include/utils/palloc.h b/src/include/utils/palloc.h index c801e12478230..399e5c84a4ad6 100644 --- a/src/include/utils/palloc.h +++ b/src/include/utils/palloc.h @@ -18,7 +18,7 @@ * everything that should be freed. See utils/mmgr/README for more info. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/palloc.h diff --git a/src/include/utils/partcache.h b/src/include/utils/partcache.h index 19e35fe5ff46b..a451bfb239db0 100644 --- a/src/include/utils/partcache.h +++ b/src/include/utils/partcache.h @@ -2,7 +2,7 @@ * * partcache.h * - * Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Copyright (c) 1996-2021, PostgreSQL Global Development Group * * src/include/utils/partcache.h * diff --git a/src/include/utils/pg_crc.h b/src/include/utils/pg_crc.h index 5fea60702a1af..dfbae9d8c0241 100644 --- a/src/include/utils/pg_crc.h +++ b/src/include/utils/pg_crc.h @@ -26,7 +26,7 @@ * * The CRC-32C variant is in port/pg_crc32c.h. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/pg_crc.h diff --git a/src/include/utils/pg_locale.h b/src/include/utils/pg_locale.h index 96da132c031bb..34dff74bd11b1 100644 --- a/src/include/utils/pg_locale.h +++ b/src/include/utils/pg_locale.h @@ -4,7 +4,7 @@ * * src/include/utils/pg_locale.h * - * Copyright (c) 2002-2020, PostgreSQL Global Development Group + * Copyright (c) 2002-2021, PostgreSQL Global Development Group * *----------------------------------------------------------------------- */ diff --git a/src/include/utils/pg_lsn.h b/src/include/utils/pg_lsn.h index 25d6c5b38eb6c..eeeac5ccc000b 100644 --- a/src/include/utils/pg_lsn.h +++ b/src/include/utils/pg_lsn.h @@ -5,7 +5,7 @@ * PostgreSQL. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/pg_lsn.h diff --git a/src/include/utils/pg_rusage.h b/src/include/utils/pg_rusage.h index 685cd419f17e4..c0def804eea90 100644 --- a/src/include/utils/pg_rusage.h +++ b/src/include/utils/pg_rusage.h @@ -4,7 +4,7 @@ * header file for resource usage measurement support routines * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/pg_rusage.h diff --git a/src/include/utils/pidfile.h b/src/include/utils/pidfile.h index 63fefe5c4c549..f5305a875e104 100644 --- a/src/include/utils/pidfile.h +++ b/src/include/utils/pidfile.h @@ -3,7 +3,7 @@ * pidfile.h * Declarations describing the data directory lock file (postmaster.pid) * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/pidfile.h diff --git a/src/include/utils/plancache.h b/src/include/utils/plancache.h index 4901568553c59..79d96e5ed0332 100644 --- a/src/include/utils/plancache.h +++ b/src/include/utils/plancache.h @@ -5,7 +5,7 @@ * * See plancache.c for comments. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/plancache.h diff --git a/src/include/utils/portal.h b/src/include/utils/portal.h index d41ff2efdad9e..3c17b039cc9ba 100644 --- a/src/include/utils/portal.h +++ b/src/include/utils/portal.h @@ -36,7 +36,7 @@ * to look like NO SCROLL cursors. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/portal.h diff --git a/src/include/utils/queryenvironment.h b/src/include/utils/queryenvironment.h index 4b8e19649a0bd..78f2f56953099 100644 --- a/src/include/utils/queryenvironment.h +++ b/src/include/utils/queryenvironment.h @@ -4,7 +4,7 @@ * Access to functions to mutate the query environment and retrieve the * actual data related to entries (if any). * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/queryenvironment.h diff --git a/src/include/utils/rangetypes.h b/src/include/utils/rangetypes.h index 8459a3d6e7a20..04c302c61997c 100644 --- a/src/include/utils/rangetypes.h +++ b/src/include/utils/rangetypes.h @@ -4,7 +4,7 @@ * Declarations for Postgres range types. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/rangetypes.h diff --git a/src/include/utils/regproc.h b/src/include/utils/regproc.h index 330417e888a06..308a7faaa42ce 100644 --- a/src/include/utils/regproc.h +++ b/src/include/utils/regproc.h @@ -3,7 +3,7 @@ * regproc.h * Functions for the built-in types regproc, regclass, regtype, etc. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/regproc.h diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index c5ffea40f2127..10b63982c0a64 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -4,7 +4,7 @@ * POSTGRES relation descriptor (a/k/a relcache entry) definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/rel.h diff --git a/src/include/utils/relcache.h b/src/include/utils/relcache.h index 9a85b7dd57f1f..2fcdf793238b8 100644 --- a/src/include/utils/relcache.h +++ b/src/include/utils/relcache.h @@ -4,7 +4,7 @@ * Relation descriptor cache definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/relcache.h diff --git a/src/include/utils/relfilenodemap.h b/src/include/utils/relfilenodemap.h index e2e1c76bc90c9..405b1123088d3 100644 --- a/src/include/utils/relfilenodemap.h +++ b/src/include/utils/relfilenodemap.h @@ -3,7 +3,7 @@ * relfilenodemap.h * relfilenode to oid mapping cache. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/relfilenodemap.h diff --git a/src/include/utils/relmapper.h b/src/include/utils/relmapper.h index 2626a74cdaa2e..c0d14daad9366 100644 --- a/src/include/utils/relmapper.h +++ b/src/include/utils/relmapper.h @@ -4,7 +4,7 @@ * Catalog-to-filenode mapping * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/relmapper.h diff --git a/src/include/utils/relptr.h b/src/include/utils/relptr.h index c6bf4e412c66c..55965f28d5aac 100644 --- a/src/include/utils/relptr.h +++ b/src/include/utils/relptr.h @@ -3,7 +3,7 @@ * relptr.h * This file contains basic declarations for relative pointers. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/relptr.h diff --git a/src/include/utils/reltrigger.h b/src/include/utils/reltrigger.h index b22acb034e9e7..7dc7699b5c6f1 100644 --- a/src/include/utils/reltrigger.h +++ b/src/include/utils/reltrigger.h @@ -4,7 +4,7 @@ * POSTGRES relation trigger definitions. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/reltrigger.h diff --git a/src/include/utils/resowner.h b/src/include/utils/resowner.h index 878f39ccf142d..109ac31b24851 100644 --- a/src/include/utils/resowner.h +++ b/src/include/utils/resowner.h @@ -9,7 +9,7 @@ * See utils/resowner/README for more info. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/resowner.h diff --git a/src/include/utils/resowner_private.h b/src/include/utils/resowner_private.h index c373788bc13eb..c480a1a24bec7 100644 --- a/src/include/utils/resowner_private.h +++ b/src/include/utils/resowner_private.h @@ -6,7 +6,7 @@ * See utils/resowner/README for more info. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/resowner_private.h diff --git a/src/include/utils/rls.h b/src/include/utils/rls.h index 49542f3aa7ac3..46b32347c3522 100644 --- a/src/include/utils/rls.h +++ b/src/include/utils/rls.h @@ -4,7 +4,7 @@ * Header file for Row Level Security (RLS) utility commands to be used * with the rowsecurity feature. * - * Copyright (c) 2007-2020, PostgreSQL Global Development Group + * Copyright (c) 2007-2021, PostgreSQL Global Development Group * * src/include/utils/rls.h * diff --git a/src/include/utils/ruleutils.h b/src/include/utils/ruleutils.h index 8306c760a9a29..ac3d0a6742f2a 100644 --- a/src/include/utils/ruleutils.h +++ b/src/include/utils/ruleutils.h @@ -3,7 +3,7 @@ * ruleutils.h * Declarations for ruleutils.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/ruleutils.h diff --git a/src/include/utils/sampling.h b/src/include/utils/sampling.h index 74646846b2021..a58d14281bc3e 100644 --- a/src/include/utils/sampling.h +++ b/src/include/utils/sampling.h @@ -3,7 +3,7 @@ * sampling.h * definitions for sampling functions * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/sampling.h diff --git a/src/include/utils/selfuncs.h b/src/include/utils/selfuncs.h index 68ffd7761f1de..f9be539602b25 100644 --- a/src/include/utils/selfuncs.h +++ b/src/include/utils/selfuncs.h @@ -5,7 +5,7 @@ * infrastructure for selectivity and cost estimation. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/selfuncs.h diff --git a/src/include/utils/sharedtuplestore.h b/src/include/utils/sharedtuplestore.h index 9754504cc5367..01ad6efe514c5 100644 --- a/src/include/utils/sharedtuplestore.h +++ b/src/include/utils/sharedtuplestore.h @@ -3,7 +3,7 @@ * sharedtuplestore.h * Simple mechanism for sharing tuples between backends. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/sharedtuplestore.h diff --git a/src/include/utils/snapmgr.h b/src/include/utils/snapmgr.h index b6b403e293135..579be352c5f46 100644 --- a/src/include/utils/snapmgr.h +++ b/src/include/utils/snapmgr.h @@ -3,7 +3,7 @@ * snapmgr.h * POSTGRES snapshot manager * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/snapmgr.h diff --git a/src/include/utils/snapshot.h b/src/include/utils/snapshot.h index dea072e5edf5e..6b60755c53908 100644 --- a/src/include/utils/snapshot.h +++ b/src/include/utils/snapshot.h @@ -3,7 +3,7 @@ * snapshot.h * POSTGRES snapshot definition * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/snapshot.h diff --git a/src/include/utils/sortsupport.h b/src/include/utils/sortsupport.h index fb262c6e8d42f..2f12a8b8eb200 100644 --- a/src/include/utils/sortsupport.h +++ b/src/include/utils/sortsupport.h @@ -42,7 +42,7 @@ * function for such cases, but probably not any other acceleration method. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/sortsupport.h diff --git a/src/include/utils/spccache.h b/src/include/utils/spccache.h index 7e4ec69aa2ef8..26ac680ff7aa0 100644 --- a/src/include/utils/spccache.h +++ b/src/include/utils/spccache.h @@ -3,7 +3,7 @@ * spccache.h * Tablespace cache. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/spccache.h diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h index e8f393520a330..d74a348600cae 100644 --- a/src/include/utils/syscache.h +++ b/src/include/utils/syscache.h @@ -6,7 +6,7 @@ * See also lsyscache.h, which provides convenience routines for * common cache-lookup operations. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/syscache.h diff --git a/src/include/utils/timeout.h b/src/include/utils/timeout.h index 83a15f67952c8..8adb4e14cacc1 100644 --- a/src/include/utils/timeout.h +++ b/src/include/utils/timeout.h @@ -4,7 +4,7 @@ * Routines to multiplex SIGALRM interrupts for multiple timeout reasons. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/timeout.h diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h index d45bf2bb7b95a..63bf71ac61f79 100644 --- a/src/include/utils/timestamp.h +++ b/src/include/utils/timestamp.h @@ -3,7 +3,7 @@ * timestamp.h * Definitions for the SQL "timestamp" and "interval" types. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/timestamp.h diff --git a/src/include/utils/tuplesort.h b/src/include/utils/tuplesort.h index c69b36e209ad6..f94949370b4ec 100644 --- a/src/include/utils/tuplesort.h +++ b/src/include/utils/tuplesort.h @@ -11,7 +11,7 @@ * algorithm. Parallel sorts use a variant of this external sort * algorithm, and are typically only used for large amounts of data. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/tuplesort.h diff --git a/src/include/utils/tuplestore.h b/src/include/utils/tuplestore.h index 2c6403f9e864b..99b1bc1e64be4 100644 --- a/src/include/utils/tuplestore.h +++ b/src/include/utils/tuplestore.h @@ -21,7 +21,7 @@ * Also, we have changed the API to return tuples in TupleTableSlots, * so that there is a check to prevent attempted access to system columns. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/tuplestore.h diff --git a/src/include/utils/typcache.h b/src/include/utils/typcache.h index dd69a06342fd1..1d68a9a4b7bf9 100644 --- a/src/include/utils/typcache.h +++ b/src/include/utils/typcache.h @@ -6,7 +6,7 @@ * The type cache exists to speed lookup of certain information about data * types that is not directly available from a type's pg_type row. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/typcache.h diff --git a/src/include/utils/tzparser.h b/src/include/utils/tzparser.h index 8eb602dc9a4ce..4bb42a347a159 100644 --- a/src/include/utils/tzparser.h +++ b/src/include/utils/tzparser.h @@ -3,7 +3,7 @@ * tzparser.h * Timezone offset file parsing definitions. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/tzparser.h diff --git a/src/include/utils/uuid.h b/src/include/utils/uuid.h index 281a1a6d1ffc3..bb3ca107e56f2 100644 --- a/src/include/utils/uuid.h +++ b/src/include/utils/uuid.h @@ -5,7 +5,7 @@ * to avoid conflicts with any uuid_t type that might be defined by * the system headers. * - * Copyright (c) 2007-2020, PostgreSQL Global Development Group + * Copyright (c) 2007-2021, PostgreSQL Global Development Group * * src/include/utils/uuid.h * diff --git a/src/include/utils/varbit.h b/src/include/utils/varbit.h index 91f8de1685e82..2fcbb5d49aa5a 100644 --- a/src/include/utils/varbit.h +++ b/src/include/utils/varbit.h @@ -5,7 +5,7 @@ * * Code originally contributed by Adriaan Joubert. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/varbit.h diff --git a/src/include/utils/varlena.h b/src/include/utils/varlena.h index 85e838f01e0ce..5c39723332d5a 100644 --- a/src/include/utils/varlena.h +++ b/src/include/utils/varlena.h @@ -3,7 +3,7 @@ * varlena.h * Functions for the variable-length built-in types. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/varlena.h diff --git a/src/include/utils/xid8.h b/src/include/utils/xid8.h index 288e62de9c336..8f59d793cd1be 100644 --- a/src/include/utils/xid8.h +++ b/src/include/utils/xid8.h @@ -3,7 +3,7 @@ * xid8.h * Header file for the "xid8" ADT. * - * Copyright (c) 2020, PostgreSQL Global Development Group + * Copyright (c) 2020-2021, PostgreSQL Global Development Group * * src/include/utils/xid8.h * diff --git a/src/include/utils/xml.h b/src/include/utils/xml.h index cf0e61fb9de0a..d79668f3c469f 100644 --- a/src/include/utils/xml.h +++ b/src/include/utils/xml.h @@ -4,7 +4,7 @@ * Declarations for XML data type support. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/xml.h diff --git a/src/include/windowapi.h b/src/include/windowapi.h index e8c9fc54d8cb5..c5324aa8f1d88 100644 --- a/src/include/windowapi.h +++ b/src/include/windowapi.h @@ -19,7 +19,7 @@ * function in nodeWindowAgg.c for details. * * - * Portions Copyright (c) 2000-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2000-2021, PostgreSQL Global Development Group * * src/include/windowapi.h * diff --git a/src/interfaces/ecpg/compatlib/Makefile b/src/interfaces/ecpg/compatlib/Makefile index 806d2922182a6..1c2866fa338a2 100644 --- a/src/interfaces/ecpg/compatlib/Makefile +++ b/src/interfaces/ecpg/compatlib/Makefile @@ -2,7 +2,7 @@ # # Makefile for ecpg compatibility library # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/interfaces/ecpg/compatlib/Makefile diff --git a/src/interfaces/ecpg/ecpglib/Makefile b/src/interfaces/ecpg/ecpglib/Makefile index 2053c60028093..13c4bebc0667f 100644 --- a/src/interfaces/ecpg/ecpglib/Makefile +++ b/src/interfaces/ecpg/ecpglib/Makefile @@ -2,7 +2,7 @@ # # Makefile for ecpg library # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/interfaces/ecpg/ecpglib/Makefile diff --git a/src/interfaces/ecpg/pgtypeslib/Makefile b/src/interfaces/ecpg/pgtypeslib/Makefile index ae79ead7a782d..513af51753edd 100644 --- a/src/interfaces/ecpg/pgtypeslib/Makefile +++ b/src/interfaces/ecpg/pgtypeslib/Makefile @@ -2,7 +2,7 @@ # # Makefile for ecpg pgtypes library # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/interfaces/ecpg/pgtypeslib/Makefile diff --git a/src/interfaces/ecpg/preproc/Makefile b/src/interfaces/ecpg/preproc/Makefile index c4fc23f920bdf..29479f96e9771 100644 --- a/src/interfaces/ecpg/preproc/Makefile +++ b/src/interfaces/ecpg/preproc/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/interfaces/ecpg/preproc # -# Copyright (c) 1998-2020, PostgreSQL Global Development Group +# Copyright (c) 1998-2021, PostgreSQL Global Development Group # # src/interfaces/ecpg/preproc/Makefile # diff --git a/src/interfaces/ecpg/preproc/c_kwlist.h b/src/interfaces/ecpg/preproc/c_kwlist.h index 8bf0199b65cf6..51c5dfbfe600a 100644 --- a/src/interfaces/ecpg/preproc/c_kwlist.h +++ b/src/interfaces/ecpg/preproc/c_kwlist.h @@ -7,7 +7,7 @@ * by the PG_KEYWORD macro, which is not defined in this file; it can * be defined by the caller for special purposes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/interfaces/ecpg/preproc/c_kwlist.h diff --git a/src/interfaces/ecpg/preproc/check_rules.pl b/src/interfaces/ecpg/preproc/check_rules.pl index 6843f901bd055..c0b5d1924acd3 100644 --- a/src/interfaces/ecpg/preproc/check_rules.pl +++ b/src/interfaces/ecpg/preproc/check_rules.pl @@ -3,7 +3,7 @@ # test parser generator for ecpg # call with backend grammar as stdin # -# Copyright (c) 2009-2020, PostgreSQL Global Development Group +# Copyright (c) 2009-2021, PostgreSQL Global Development Group # # Written by Michael Meskes # Andy Colson diff --git a/src/interfaces/ecpg/preproc/ecpg.c b/src/interfaces/ecpg/preproc/ecpg.c index 44a6d5119b2c9..f362664fdc1c0 100644 --- a/src/interfaces/ecpg/preproc/ecpg.c +++ b/src/interfaces/ecpg/preproc/ecpg.c @@ -1,7 +1,7 @@ /* src/interfaces/ecpg/preproc/ecpg.c */ /* Main for ecpg, the PostgreSQL embedded SQL precompiler. */ -/* Copyright (c) 1996-2020, PostgreSQL Global Development Group */ +/* Copyright (c) 1996-2021, PostgreSQL Global Development Group */ #include "postgres_fe.h" diff --git a/src/interfaces/ecpg/preproc/ecpg_kwlist.h b/src/interfaces/ecpg/preproc/ecpg_kwlist.h index 0170bfefdc311..3c466f84d8ee9 100644 --- a/src/interfaces/ecpg/preproc/ecpg_kwlist.h +++ b/src/interfaces/ecpg/preproc/ecpg_kwlist.h @@ -7,7 +7,7 @@ * by the PG_KEYWORD macro, which is not defined in this file; it can * be defined by the caller for special purposes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/interfaces/ecpg/preproc/ecpg_kwlist.h diff --git a/src/interfaces/ecpg/preproc/keywords.c b/src/interfaces/ecpg/preproc/keywords.c index f1640d0062b64..83609e31a20bb 100644 --- a/src/interfaces/ecpg/preproc/keywords.c +++ b/src/interfaces/ecpg/preproc/keywords.c @@ -4,7 +4,7 @@ * lexical token lookup for key words in PostgreSQL * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/interfaces/ecpg/preproc/parse.pl b/src/interfaces/ecpg/preproc/parse.pl index 52ba7dfa0cdcc..f2731ea873a43 100644 --- a/src/interfaces/ecpg/preproc/parse.pl +++ b/src/interfaces/ecpg/preproc/parse.pl @@ -3,7 +3,7 @@ # parser generator for ecpg version 2 # call with backend parser as stdin # -# Copyright (c) 2007-2020, PostgreSQL Global Development Group +# Copyright (c) 2007-2021, PostgreSQL Global Development Group # # Written by Mike Aubury # Michael Meskes diff --git a/src/interfaces/ecpg/preproc/parser.c b/src/interfaces/ecpg/preproc/parser.c index a2eeeba217418..a8571a3ffa1f4 100644 --- a/src/interfaces/ecpg/preproc/parser.c +++ b/src/interfaces/ecpg/preproc/parser.c @@ -10,7 +10,7 @@ * This file will need work if we ever want it to. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l index 1aebac89cd66e..7a0356638d70e 100644 --- a/src/interfaces/ecpg/preproc/pgc.l +++ b/src/interfaces/ecpg/preproc/pgc.l @@ -10,7 +10,7 @@ * only here to simplify syncing this file with scan.l. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/interfaces/ecpg/test/pg_regress_ecpg.c b/src/interfaces/ecpg/test/pg_regress_ecpg.c index 49b2d8141f5e2..31dd507ea0a02 100644 --- a/src/interfaces/ecpg/test/pg_regress_ecpg.c +++ b/src/interfaces/ecpg/test/pg_regress_ecpg.c @@ -8,7 +8,7 @@ * * This code is released under the terms of the PostgreSQL License. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/interfaces/ecpg/test/pg_regress_ecpg.c diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile index 4ac5f4b340f50..c4fde3f93dd56 100644 --- a/src/interfaces/libpq/Makefile +++ b/src/interfaces/libpq/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/interfaces/libpq library # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/interfaces/libpq/Makefile diff --git a/src/interfaces/libpq/fe-auth-scram.c b/src/interfaces/libpq/fe-auth-scram.c index 6dcf574f62f3b..b76f0befd0b87 100644 --- a/src/interfaces/libpq/fe-auth-scram.c +++ b/src/interfaces/libpq/fe-auth-scram.c @@ -3,7 +3,7 @@ * fe-auth-scram.c * The front-end (client) implementation of SCRAM authentication. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c index 9f5403d74ce3f..a25fe4dd17a8e 100644 --- a/src/interfaces/libpq/fe-auth.c +++ b/src/interfaces/libpq/fe-auth.c @@ -3,7 +3,7 @@ * fe-auth.c * The front-end (client) authorization routines * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/interfaces/libpq/fe-auth.h b/src/interfaces/libpq/fe-auth.h index dc4b15d3ac0db..7877dcbd09f13 100644 --- a/src/interfaces/libpq/fe-auth.h +++ b/src/interfaces/libpq/fe-auth.h @@ -4,7 +4,7 @@ * * Definitions for network authentication routines * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/interfaces/libpq/fe-auth.h diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index ae4866c8e427e..a834ce8cf05d0 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -3,7 +3,7 @@ * fe-connect.c * functions related to setting up a connection to the backend * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index eea0237c3a5c5..d48f0fd587b88 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -3,7 +3,7 @@ * fe-exec.c * functions related to sending a query down to the backend * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/interfaces/libpq/fe-gssapi-common.c b/src/interfaces/libpq/fe-gssapi-common.c index 6538a421c701d..c2e79bb55c5b4 100644 --- a/src/interfaces/libpq/fe-gssapi-common.c +++ b/src/interfaces/libpq/fe-gssapi-common.c @@ -3,7 +3,7 @@ * fe-gssapi-common.c * The front-end (client) GSSAPI common code * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/interfaces/libpq/fe-gssapi-common.h b/src/interfaces/libpq/fe-gssapi-common.h index 156925216ff14..477660660ac27 100644 --- a/src/interfaces/libpq/fe-gssapi-common.h +++ b/src/interfaces/libpq/fe-gssapi-common.h @@ -4,7 +4,7 @@ * * Definitions for GSSAPI common routines * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/interfaces/libpq/fe-gssapi-common.h diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c index a94ce0656085b..432935061f041 100644 --- a/src/interfaces/libpq/fe-lobj.c +++ b/src/interfaces/libpq/fe-lobj.c @@ -3,7 +3,7 @@ * fe-lobj.c * Front-end large object interface * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c index 4ffc7f33fb5e7..6094f048f3052 100644 --- a/src/interfaces/libpq/fe-misc.c +++ b/src/interfaces/libpq/fe-misc.c @@ -19,7 +19,7 @@ * routines. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/interfaces/libpq/fe-print.c b/src/interfaces/libpq/fe-print.c index 784eaae48e5b0..94219b1825bcb 100644 --- a/src/interfaces/libpq/fe-print.c +++ b/src/interfaces/libpq/fe-print.c @@ -3,7 +3,7 @@ * fe-print.c * functions for pretty-printing query results * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * These functions were formerly part of fe-exec.c, but they diff --git a/src/interfaces/libpq/fe-protocol2.c b/src/interfaces/libpq/fe-protocol2.c index 9360c541bec03..ad6587f924ef5 100644 --- a/src/interfaces/libpq/fe-protocol2.c +++ b/src/interfaces/libpq/fe-protocol2.c @@ -3,7 +3,7 @@ * fe-protocol2.c * functions that are specific to frontend/backend protocol version 2 * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c index 16965254757ce..a4d6ee26749d4 100644 --- a/src/interfaces/libpq/fe-protocol3.c +++ b/src/interfaces/libpq/fe-protocol3.c @@ -3,7 +3,7 @@ * fe-protocol3.c * functions that are specific to frontend/backend protocol version 3 * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/interfaces/libpq/fe-secure-common.c b/src/interfaces/libpq/fe-secure-common.c index 48512b6d76cf6..45d36359a5d40 100644 --- a/src/interfaces/libpq/fe-secure-common.c +++ b/src/interfaces/libpq/fe-secure-common.c @@ -8,7 +8,7 @@ * file contains support routines that are used by the library-specific * implementations such as fe-secure-openssl.c. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/interfaces/libpq/fe-secure-common.h b/src/interfaces/libpq/fe-secure-common.h index 8e483f6929fb0..2389f6717a302 100644 --- a/src/interfaces/libpq/fe-secure-common.h +++ b/src/interfaces/libpq/fe-secure-common.h @@ -4,7 +4,7 @@ * * common implementation-independent SSL support code * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/interfaces/libpq/fe-secure-gssapi.c b/src/interfaces/libpq/fe-secure-gssapi.c index 9416306eea02b..8c0ba69b7c071 100644 --- a/src/interfaces/libpq/fe-secure-gssapi.c +++ b/src/interfaces/libpq/fe-secure-gssapi.c @@ -3,7 +3,7 @@ * fe-secure-gssapi.c * The front-end (client) encryption support for GSSAPI * - * Portions Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2016-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/interfaces/libpq/fe-secure-gssapi.c diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c index d609a38bbe030..d63e4bb27972d 100644 --- a/src/interfaces/libpq/fe-secure-openssl.c +++ b/src/interfaces/libpq/fe-secure-openssl.c @@ -4,7 +4,7 @@ * OpenSSL support * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c index 97c3805303f54..373c59cb0d629 100644 --- a/src/interfaces/libpq/fe-secure.c +++ b/src/interfaces/libpq/fe-secure.c @@ -6,7 +6,7 @@ * message integrity and endpoint authentication. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/interfaces/libpq/legacy-pqsignal.c b/src/interfaces/libpq/legacy-pqsignal.c index 4703adbf0cc76..37fa9e58061bb 100644 --- a/src/interfaces/libpq/legacy-pqsignal.c +++ b/src/interfaces/libpq/legacy-pqsignal.c @@ -4,7 +4,7 @@ * reliable BSD-style signal(2) routine stolen from RWW who stole it * from Stevens... * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/interfaces/libpq/libpq-events.c b/src/interfaces/libpq/libpq-events.c index d050d7f3f2145..8e244899be268 100644 --- a/src/interfaces/libpq/libpq-events.c +++ b/src/interfaces/libpq/libpq-events.c @@ -3,7 +3,7 @@ * libpq-events.c * functions for supporting the libpq "events" API * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/interfaces/libpq/libpq-events.h b/src/interfaces/libpq/libpq-events.h index 5108a55cf6f60..30ed85177ba37 100644 --- a/src/interfaces/libpq/libpq-events.h +++ b/src/interfaces/libpq/libpq-events.h @@ -5,7 +5,7 @@ * that invoke the libpq "events" API, but are not interesting to * ordinary users of libpq. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/interfaces/libpq/libpq-events.h diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h index 3b6a9fbce3558..c266ad5b13844 100644 --- a/src/interfaces/libpq/libpq-fe.h +++ b/src/interfaces/libpq/libpq-fe.h @@ -4,7 +4,7 @@ * This file contains definitions for structures and * externs for functions used by frontend postgres applications. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/interfaces/libpq/libpq-fe.h diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index 1de91ae295b38..e1018adb9e5db 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -9,7 +9,7 @@ * more likely to break across PostgreSQL releases than code that uses * only the official API. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/interfaces/libpq/libpq-int.h diff --git a/src/interfaces/libpq/pqexpbuffer.c b/src/interfaces/libpq/pqexpbuffer.c index bd5ef77727061..a57f753bd6920 100644 --- a/src/interfaces/libpq/pqexpbuffer.c +++ b/src/interfaces/libpq/pqexpbuffer.c @@ -15,7 +15,7 @@ * a usable vsnprintf(), then a copy of our own implementation of it will * be linked into libpq. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/interfaces/libpq/pqexpbuffer.c diff --git a/src/interfaces/libpq/pqexpbuffer.h b/src/interfaces/libpq/pqexpbuffer.h index 65cd367662726..0251095780355 100644 --- a/src/interfaces/libpq/pqexpbuffer.h +++ b/src/interfaces/libpq/pqexpbuffer.h @@ -15,7 +15,7 @@ * a usable vsnprintf(), then a copy of our own implementation of it will * be linked into libpq. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/interfaces/libpq/pqexpbuffer.h diff --git a/src/interfaces/libpq/pthread-win32.c b/src/interfaces/libpq/pthread-win32.c index fd801c1a21030..6dbb0a343b3db 100644 --- a/src/interfaces/libpq/pthread-win32.c +++ b/src/interfaces/libpq/pthread-win32.c @@ -3,7 +3,7 @@ * pthread-win32.c * partial pthread implementation for win32 * -* Copyright (c) 2004-2020, PostgreSQL Global Development Group +* Copyright (c) 2004-2021, PostgreSQL Global Development Group * IDENTIFICATION * src/interfaces/libpq/pthread-win32.c * diff --git a/src/interfaces/libpq/test/uri-regress.c b/src/interfaces/libpq/test/uri-regress.c index 1fb25e860a5db..84fc52a7945e3 100644 --- a/src/interfaces/libpq/test/uri-regress.c +++ b/src/interfaces/libpq/test/uri-regress.c @@ -7,7 +7,7 @@ * prints out the values from the parsed PQconninfoOption struct that differ * from the defaults (obtained from PQconndefaults). * - * Portions Copyright (c) 2012-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2012-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/interfaces/libpq/test/uri-regress.c diff --git a/src/interfaces/libpq/win32.c b/src/interfaces/libpq/win32.c index cd19ec925281a..f6cf9dc2fa313 100644 --- a/src/interfaces/libpq/win32.c +++ b/src/interfaces/libpq/win32.c @@ -15,7 +15,7 @@ * The error constants are taken from the Frambak Bakfram LGSOCKET * library guys who in turn took them from the Winsock FAQ. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * */ diff --git a/src/pl/plperl/plperl.h b/src/pl/plperl/plperl.h index 619e7121a1bfe..ffcd147578ebf 100644 --- a/src/pl/plperl/plperl.h +++ b/src/pl/plperl/plperl.h @@ -5,7 +5,7 @@ * * This should be included _AFTER_ postgres.h and system include files * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1995, Regents of the University of California * * src/pl/plperl/plperl.h diff --git a/src/pl/plpgsql/src/generate-plerrcodes.pl b/src/pl/plpgsql/src/generate-plerrcodes.pl index a50de66ef813f..55ff16931d9c4 100644 --- a/src/pl/plpgsql/src/generate-plerrcodes.pl +++ b/src/pl/plpgsql/src/generate-plerrcodes.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl # # Generate the plerrcodes.h header from errcodes.txt -# Copyright (c) 2000-2020, PostgreSQL Global Development Group +# Copyright (c) 2000-2021, PostgreSQL Global Development Group use strict; use warnings; diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 042deb2a96c2c..81979c2961b33 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -3,7 +3,7 @@ * pl_comp.c - Compiler part of the PL/pgSQL * procedural language * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index b9e85a1a0fd28..f966ddf0b5e37 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -3,7 +3,7 @@ * pl_exec.c - Executor for the PL/pgSQL * procedural language * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/pl/plpgsql/src/pl_funcs.c b/src/pl/plpgsql/src/pl_funcs.c index ee60ced583852..ac72bfa8c03d0 100644 --- a/src/pl/plpgsql/src/pl_funcs.c +++ b/src/pl/plpgsql/src/pl_funcs.c @@ -3,7 +3,7 @@ * pl_funcs.c - Misc functions for the PL/pgSQL * procedural language * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y index 8227bf0449fc6..a154b9841a65c 100644 --- a/src/pl/plpgsql/src/pl_gram.y +++ b/src/pl/plpgsql/src/pl_gram.y @@ -3,7 +3,7 @@ * * pl_gram.y - Parser for the PL/pgSQL procedural language * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c index 7ece87df48b94..52e6c69cc5599 100644 --- a/src/pl/plpgsql/src/pl_handler.c +++ b/src/pl/plpgsql/src/pl_handler.c @@ -3,7 +3,7 @@ * pl_handler.c - Handler for the PL/pgSQL * procedural language * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/pl/plpgsql/src/pl_reserved_kwlist.h b/src/pl/plpgsql/src/pl_reserved_kwlist.h index d3c169a81f14a..daf835e683560 100644 --- a/src/pl/plpgsql/src/pl_reserved_kwlist.h +++ b/src/pl/plpgsql/src/pl_reserved_kwlist.h @@ -7,7 +7,7 @@ * by the PG_KEYWORD macro, which is not defined in this file; it can * be defined by the caller for special purposes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/pl/plpgsql/src/pl_reserved_kwlist.h diff --git a/src/pl/plpgsql/src/pl_scanner.c b/src/pl/plpgsql/src/pl_scanner.c index 9cea2e42ac4d3..e4c7a91ab540b 100644 --- a/src/pl/plpgsql/src/pl_scanner.c +++ b/src/pl/plpgsql/src/pl_scanner.c @@ -4,7 +4,7 @@ * lexical scanning for PL/pgSQL * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/pl/plpgsql/src/pl_unreserved_kwlist.h b/src/pl/plpgsql/src/pl_unreserved_kwlist.h index 99b3cf7d8aae1..44c8b68bfbc4b 100644 --- a/src/pl/plpgsql/src/pl_unreserved_kwlist.h +++ b/src/pl/plpgsql/src/pl_unreserved_kwlist.h @@ -7,7 +7,7 @@ * by the PG_KEYWORD macro, which is not defined in this file; it can * be defined by the caller for special purposes. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/pl/plpgsql/src/pl_unreserved_kwlist.h diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index 0c3d30fb1301c..dee175b7bf65a 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -3,7 +3,7 @@ * plpgsql.h - Definitions for the PL/pgSQL * procedural language * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/pl/plpython/generate-spiexceptions.pl b/src/pl/plpython/generate-spiexceptions.pl index 14967ba3eef6a..488c980e09717 100644 --- a/src/pl/plpython/generate-spiexceptions.pl +++ b/src/pl/plpython/generate-spiexceptions.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl # # Generate the spiexceptions.h header from errcodes.txt -# Copyright (c) 2000-2020, PostgreSQL Global Development Group +# Copyright (c) 2000-2021, PostgreSQL Global Development Group use strict; use warnings; diff --git a/src/pl/plpython/plpython.h b/src/pl/plpython/plpython.h index 6d981a0a06dee..994457b37d62e 100644 --- a/src/pl/plpython/plpython.h +++ b/src/pl/plpython/plpython.h @@ -2,7 +2,7 @@ * * plpython.h - Python as a procedural language for PostgreSQL * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/pl/plpython/plpython.h diff --git a/src/pl/tcl/generate-pltclerrcodes.pl b/src/pl/tcl/generate-pltclerrcodes.pl index bb9eb8a824dc0..c63c632325358 100644 --- a/src/pl/tcl/generate-pltclerrcodes.pl +++ b/src/pl/tcl/generate-pltclerrcodes.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl # # Generate the pltclerrcodes.h header from errcodes.txt -# Copyright (c) 2000-2020, PostgreSQL Global Development Group +# Copyright (c) 2000-2021, PostgreSQL Global Development Group use strict; use warnings; diff --git a/src/port/chklocale.c b/src/port/chklocale.c index 9e3c6db785638..3d47d37eae4d6 100644 --- a/src/port/chklocale.c +++ b/src/port/chklocale.c @@ -4,7 +4,7 @@ * Functions for handling locale-related info * * - * Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/port/dirent.c b/src/port/dirent.c index 70a444f9a53f9..77b90e7e3026d 100644 --- a/src/port/dirent.c +++ b/src/port/dirent.c @@ -3,7 +3,7 @@ * dirent.c * opendir/readdir/closedir for win32/msvc * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/dirmod.c b/src/port/dirmod.c index 8979f100803bf..763bc5f915a67 100644 --- a/src/port/dirmod.c +++ b/src/port/dirmod.c @@ -3,7 +3,7 @@ * dirmod.c * directory handling functions * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * This includes replacement versions of functions that work on diff --git a/src/port/dlopen.c b/src/port/dlopen.c index 30155bb3b0eaf..f7948b861f006 100644 --- a/src/port/dlopen.c +++ b/src/port/dlopen.c @@ -3,7 +3,7 @@ * dlopen.c * dynamic loader for platforms without dlopen() * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/erand48.c b/src/port/erand48.c index d67c8980f74d1..a82ea94220bd5 100644 --- a/src/port/erand48.c +++ b/src/port/erand48.c @@ -14,7 +14,7 @@ * erand48() is strangely coded to be almost-but-not-quite thread-safe, * which doesn't matter for the backend but is important for pgbench. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * Portions Copyright (c) 1993 Martin Birgmeier * All rights reserved. diff --git a/src/port/explicit_bzero.c b/src/port/explicit_bzero.c index 6bd8b0dd9d238..e39e20b8a569f 100644 --- a/src/port/explicit_bzero.c +++ b/src/port/explicit_bzero.c @@ -2,7 +2,7 @@ * * explicit_bzero.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/fls.c b/src/port/fls.c index 231fbba0c11ce..2c622c51ebc58 100644 --- a/src/port/fls.c +++ b/src/port/fls.c @@ -3,7 +3,7 @@ * fls.c * finds the last (most significant) bit that is set * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/port/getaddrinfo.c b/src/port/getaddrinfo.c index 495ad343f392d..bb194da529cd4 100644 --- a/src/port/getaddrinfo.c +++ b/src/port/getaddrinfo.c @@ -13,7 +13,7 @@ * use the Windows native routines, but if not, we use our own. * * - * Copyright (c) 2003-2020, PostgreSQL Global Development Group + * Copyright (c) 2003-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/port/getaddrinfo.c diff --git a/src/port/getpeereid.c b/src/port/getpeereid.c index 0025aaae1f584..d6aa755d30a43 100644 --- a/src/port/getpeereid.c +++ b/src/port/getpeereid.c @@ -3,7 +3,7 @@ * getpeereid.c * get peer userid for UNIX-domain socket connection * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/port/getrusage.c b/src/port/getrusage.c index 9424d1456555e..99f240f6dac53 100644 --- a/src/port/getrusage.c +++ b/src/port/getrusage.c @@ -3,7 +3,7 @@ * getrusage.c * get information about resource utilisation * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/kill.c b/src/port/kill.c index 1608554d0c631..99b35de45b6ad 100644 --- a/src/port/kill.c +++ b/src/port/kill.c @@ -3,7 +3,7 @@ * kill.c * kill() * - * Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Copyright (c) 1996-2021, PostgreSQL Global Development Group * * This is a replacement version of kill for Win32 which sends * signals that the backend can recognize. diff --git a/src/port/link.c b/src/port/link.c index c7e43854211bf..0b61da5a06555 100644 --- a/src/port/link.c +++ b/src/port/link.c @@ -2,7 +2,7 @@ * * link.c * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/mkdtemp.c b/src/port/mkdtemp.c index 0c042b16c93d0..c97b63787ca4c 100644 --- a/src/port/mkdtemp.c +++ b/src/port/mkdtemp.c @@ -3,7 +3,7 @@ * mkdtemp.c * create a mode-0700 temporary directory * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/port/noblock.c b/src/port/noblock.c index 5dbe5a968d3ea..b43222c338397 100644 --- a/src/port/noblock.c +++ b/src/port/noblock.c @@ -3,7 +3,7 @@ * noblock.c * set a file descriptor as blocking or non-blocking * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/port/open.c b/src/port/open.c index 327fe58190c41..14c6debba915c 100644 --- a/src/port/open.c +++ b/src/port/open.c @@ -4,7 +4,7 @@ * Win32 open() replacement * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * src/port/open.c * diff --git a/src/port/path.c b/src/port/path.c index 10e87fbae897b..c39d4688cd921 100644 --- a/src/port/path.c +++ b/src/port/path.c @@ -3,7 +3,7 @@ * path.c * portable path handling routines * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/pg_bitutils.c b/src/port/pg_bitutils.c index 392fbd338452e..2252021854ff0 100644 --- a/src/port/pg_bitutils.c +++ b/src/port/pg_bitutils.c @@ -3,7 +3,7 @@ * pg_bitutils.c * Miscellaneous functions for bit-wise operations. * - * Copyright (c) 2019-2020, PostgreSQL Global Development Group + * Copyright (c) 2019-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/port/pg_bitutils.c diff --git a/src/port/pg_crc32c_armv8.c b/src/port/pg_crc32c_armv8.c index 15275b22db552..9a6517c9dd91e 100644 --- a/src/port/pg_crc32c_armv8.c +++ b/src/port/pg_crc32c_armv8.c @@ -3,7 +3,7 @@ * pg_crc32c_armv8.c * Compute CRC-32C checksum using ARMv8 CRC Extension instructions * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/pg_crc32c_armv8_choose.c b/src/port/pg_crc32c_armv8_choose.c index 5e77052f2198d..ac8dcf6d51619 100644 --- a/src/port/pg_crc32c_armv8_choose.c +++ b/src/port/pg_crc32c_armv8_choose.c @@ -8,7 +8,7 @@ * computation. Otherwise, fall back to the pure software implementation * (slicing-by-8). * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/pg_crc32c_sb8.c b/src/port/pg_crc32c_sb8.c index 3f09cbbb54948..98da86cdd345e 100644 --- a/src/port/pg_crc32c_sb8.c +++ b/src/port/pg_crc32c_sb8.c @@ -8,7 +8,7 @@ * Generation", IEEE Transactions on Computers, vol.57, no. 11, * pp. 1550-1560, November 2008, doi:10.1109/TC.2008.85 * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/pg_crc32c_sse42.c b/src/port/pg_crc32c_sse42.c index dddcb2c6c9cd1..3b94a7388aba8 100644 --- a/src/port/pg_crc32c_sse42.c +++ b/src/port/pg_crc32c_sse42.c @@ -3,7 +3,7 @@ * pg_crc32c_sse42.c * Compute CRC-32C checksum using Intel SSE 4.2 instructions. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/pg_crc32c_sse42_choose.c b/src/port/pg_crc32c_sse42_choose.c index 6aa94475ad53c..0608e02011f7f 100644 --- a/src/port/pg_crc32c_sse42_choose.c +++ b/src/port/pg_crc32c_sse42_choose.c @@ -8,7 +8,7 @@ * computation. Otherwise, fall back to the pure software implementation * (slicing-by-8). * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/pg_strong_random.c b/src/port/pg_strong_random.c index 12bbd7fb08b44..07f24c0089705 100644 --- a/src/port/pg_strong_random.c +++ b/src/port/pg_strong_random.c @@ -10,7 +10,7 @@ * therefore, even when built for backend, it cannot rely on backend * infrastructure such as elog() or palloc(). * - * Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/port/pg_strong_random.c diff --git a/src/port/pgcheckdir.c b/src/port/pgcheckdir.c index ac4725ff7ab2c..9fb2f23bdd277 100644 --- a/src/port/pgcheckdir.c +++ b/src/port/pgcheckdir.c @@ -5,7 +5,7 @@ * A simple subroutine to check whether a directory exists and is empty or not. * Useful in both initdb and the backend. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * *------------------------------------------------------------------------- diff --git a/src/port/pgsleep.c b/src/port/pgsleep.c index f898104185c9d..d6d51363e71a3 100644 --- a/src/port/pgsleep.c +++ b/src/port/pgsleep.c @@ -4,7 +4,7 @@ * Portable delay handling. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * src/port/pgsleep.c * diff --git a/src/port/pgstrcasecmp.c b/src/port/pgstrcasecmp.c index 645f1c51c55aa..98e1aedfeefc1 100644 --- a/src/port/pgstrcasecmp.c +++ b/src/port/pgstrcasecmp.c @@ -18,7 +18,7 @@ * C library thinks the locale is. * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * src/port/pgstrcasecmp.c * diff --git a/src/port/pgstrsignal.c b/src/port/pgstrsignal.c index 1a6f7db085e31..0f3b5da04f076 100644 --- a/src/port/pgstrsignal.c +++ b/src/port/pgstrsignal.c @@ -9,7 +9,7 @@ * This file is not currently built in MSVC builds, since it's useless * on non-Unix platforms. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/port/pqsignal.c b/src/port/pqsignal.c index 9bd0068d9a774..a373b48093e5b 100644 --- a/src/port/pqsignal.c +++ b/src/port/pqsignal.c @@ -4,7 +4,7 @@ * reliable BSD-style signal(2) routine stolen from RWW who stole it * from Stevens... * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/pread.c b/src/port/pread.c index e7fecebe5ff24..486f07a7dffcc 100644 --- a/src/port/pread.c +++ b/src/port/pread.c @@ -3,7 +3,7 @@ * pread.c * Implementation of pread(2) for platforms that lack one. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/port/pread.c diff --git a/src/port/pwrite.c b/src/port/pwrite.c index 2e0c154462e65..282b27115e509 100644 --- a/src/port/pwrite.c +++ b/src/port/pwrite.c @@ -3,7 +3,7 @@ * pwrite.c * Implementation of pwrite(2) for platforms that lack one. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/port/pwrite.c diff --git a/src/port/quotes.c b/src/port/quotes.c index 24b6895333a44..63a219f5f4359 100644 --- a/src/port/quotes.c +++ b/src/port/quotes.c @@ -3,7 +3,7 @@ * quotes.c * string quoting and escaping functions * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/random.c b/src/port/random.c index f04432fe1f892..2dd59a08293d2 100644 --- a/src/port/random.c +++ b/src/port/random.c @@ -3,7 +3,7 @@ * random.c * random() wrapper * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/setenv.c b/src/port/setenv.c index d8a5647fb02fc..440bc832ce858 100644 --- a/src/port/setenv.c +++ b/src/port/setenv.c @@ -3,7 +3,7 @@ * setenv.c * setenv() emulation for machines without it * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/snprintf.c b/src/port/snprintf.c index 83a81033a5858..c0a452da0fea7 100644 --- a/src/port/snprintf.c +++ b/src/port/snprintf.c @@ -2,7 +2,7 @@ * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/src/port/srandom.c b/src/port/srandom.c index ce9e2bc245509..cf1007b2ef81a 100644 --- a/src/port/srandom.c +++ b/src/port/srandom.c @@ -3,7 +3,7 @@ * srandom.c * srandom() wrapper * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/strerror.c b/src/port/strerror.c index 127bc5ef1fee7..c07c983e75024 100644 --- a/src/port/strerror.c +++ b/src/port/strerror.c @@ -3,7 +3,7 @@ * strerror.c * Replacements for standard strerror() and strerror_r() functions * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/strlcpy.c b/src/port/strlcpy.c index 5ca1b42d4cd97..b8cc887b81944 100644 --- a/src/port/strlcpy.c +++ b/src/port/strlcpy.c @@ -3,7 +3,7 @@ * strlcpy.c * strncpy done right * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/port/strnlen.c b/src/port/strnlen.c index cae9a53dc5057..cdc4b64bddc7a 100644 --- a/src/port/strnlen.c +++ b/src/port/strnlen.c @@ -4,7 +4,7 @@ * Fallback implementation of strnlen(). * * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/port/strtof.c b/src/port/strtof.c index 2a5553bc5fe83..92bddfba40cbd 100644 --- a/src/port/strtof.c +++ b/src/port/strtof.c @@ -2,7 +2,7 @@ * * strtof.c * - * Portions Copyright (c) 2019-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 2019-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/port/system.c b/src/port/system.c index 7031ad556a2b3..8618e47f97238 100644 --- a/src/port/system.c +++ b/src/port/system.c @@ -29,7 +29,7 @@ * quote character on the command line, preserving any text after the last * quote character. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * src/port/system.c * diff --git a/src/port/thread.c b/src/port/thread.c index 0941cb6a88f4f..1f3bcbd1c988a 100644 --- a/src/port/thread.c +++ b/src/port/thread.c @@ -5,7 +5,7 @@ * Prototypes and macros around system calls, used to help make * threaded libraries reentrant and safe to use from threaded applications. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * src/port/thread.c * diff --git a/src/port/unsetenv.c b/src/port/unsetenv.c index a5f19f8db39ab..b65f3521f9ccf 100644 --- a/src/port/unsetenv.c +++ b/src/port/unsetenv.c @@ -3,7 +3,7 @@ * unsetenv.c * unsetenv() emulation for machines without it * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/win32env.c b/src/port/win32env.c index f5bed67297481..a03556078cead 100644 --- a/src/port/win32env.c +++ b/src/port/win32env.c @@ -6,7 +6,7 @@ * These functions update both the process environment and caches in * (potentially multiple) C run-time library (CRT) versions. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/win32error.c b/src/port/win32error.c index c9bfc9fa4a835..0e5f91adfa00f 100644 --- a/src/port/win32error.c +++ b/src/port/win32error.c @@ -3,7 +3,7 @@ * win32error.c * Map win32 error codes to errno values * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/port/win32error.c diff --git a/src/port/win32security.c b/src/port/win32security.c index 577162e5478ab..4a673fde19a47 100644 --- a/src/port/win32security.c +++ b/src/port/win32security.c @@ -3,7 +3,7 @@ * win32security.c * Microsoft Windows Win32 Security Support Functions * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/port/win32security.c diff --git a/src/port/win32setlocale.c b/src/port/win32setlocale.c index 543745ccd3ac6..4edae05bb7cfb 100644 --- a/src/port/win32setlocale.c +++ b/src/port/win32setlocale.c @@ -3,7 +3,7 @@ * win32setlocale.c * Wrapper to work around bugs in Windows setlocale() implementation * - * Copyright (c) 2011-2020, PostgreSQL Global Development Group + * Copyright (c) 2011-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/port/win32setlocale.c diff --git a/src/port/win32stat.c b/src/port/win32stat.c index 4351aa4d08f25..2ad8ee13595c9 100644 --- a/src/port/win32stat.c +++ b/src/port/win32stat.c @@ -3,7 +3,7 @@ * win32stat.c * Replacements for functions using GetFileInformationByHandle * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/port/win32ver.rc b/src/port/win32ver.rc index 5834b31ddcc0e..94fb77941a0c4 100644 --- a/src/port/win32ver.rc +++ b/src/port/win32ver.rc @@ -20,7 +20,7 @@ BEGIN VALUE "FileDescription", FILEDESC VALUE "FileVersion", PG_VERSION VALUE "InternalName", _INTERNAL_NAME_ - VALUE "LegalCopyright", "Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group. Portions Copyright (c) 1994, Regents of the University of California." + VALUE "LegalCopyright", "Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group. Portions Copyright (c) 1994, Regents of the University of California." VALUE "OriginalFileName", _ORIGINAL_NAME_ VALUE "ProductName", "PostgreSQL" VALUE "ProductVersion", PG_VERSION diff --git a/src/test/authentication/Makefile b/src/test/authentication/Makefile index 124d1d0771f76..9aa331e98147f 100644 --- a/src/test/authentication/Makefile +++ b/src/test/authentication/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/test/authentication # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/test/authentication/Makefile diff --git a/src/test/examples/testlo.c b/src/test/examples/testlo.c index d11dba8546d72..fa8da58e1b379 100644 --- a/src/test/examples/testlo.c +++ b/src/test/examples/testlo.c @@ -3,7 +3,7 @@ * testlo.c * test using large objects with libpq * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/test/examples/testlo64.c b/src/test/examples/testlo64.c index 96a55b915e5b8..6334171163ae2 100644 --- a/src/test/examples/testlo64.c +++ b/src/test/examples/testlo64.c @@ -3,7 +3,7 @@ * testlo64.c * test using large objects with libpq using 64-bit APIs * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/test/isolation/isolation_main.c b/src/test/isolation/isolation_main.c index a6a64e7ec527d..50893aa3abb9a 100644 --- a/src/test/isolation/isolation_main.c +++ b/src/test/isolation/isolation_main.c @@ -2,7 +2,7 @@ * * isolation_main --- pg_regress test launcher for isolation tests * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/test/isolation/isolation_main.c diff --git a/src/test/isolation/isolationtester.h b/src/test/isolation/isolationtester.h index 9cf50124168ff..488ff05928a09 100644 --- a/src/test/isolation/isolationtester.h +++ b/src/test/isolation/isolationtester.h @@ -3,7 +3,7 @@ * isolationtester.h * include file for isolation tests * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/test/isolation/specparse.y b/src/test/isolation/specparse.y index 5e007e1bf09ea..ae3a99996136b 100644 --- a/src/test/isolation/specparse.y +++ b/src/test/isolation/specparse.y @@ -4,7 +4,7 @@ * specparse.y * bison grammar for the isolation test file format * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * *------------------------------------------------------------------------- diff --git a/src/test/isolation/specscanner.l b/src/test/isolation/specscanner.l index 410f17727e125..19883c265b334 100644 --- a/src/test/isolation/specscanner.l +++ b/src/test/isolation/specscanner.l @@ -4,7 +4,7 @@ * specscanner.l * a lexical scanner for an isolation test specification * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * *------------------------------------------------------------------------- diff --git a/src/test/kerberos/Makefile b/src/test/kerberos/Makefile index 04a0f746b5fd4..e34e531b8dedd 100644 --- a/src/test/kerberos/Makefile +++ b/src/test/kerberos/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/test/kerberos # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/test/kerberos/Makefile diff --git a/src/test/ldap/Makefile b/src/test/ldap/Makefile index 3e5afd97779e7..ed135748021bc 100644 --- a/src/test/ldap/Makefile +++ b/src/test/ldap/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/test/ldap # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/test/ldap/Makefile diff --git a/src/test/modules/delay_execution/delay_execution.c b/src/test/modules/delay_execution/delay_execution.c index 03ea23d0f2660..b3d0841ba8092 100644 --- a/src/test/modules/delay_execution/delay_execution.c +++ b/src/test/modules/delay_execution/delay_execution.c @@ -10,7 +10,7 @@ * test behaviors where some specified action happens in another backend * between parsing and execution of any desired query. * - * Copyright (c) 2020, PostgreSQL Global Development Group + * Copyright (c) 2020-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/test/modules/delay_execution/delay_execution.c diff --git a/src/test/modules/dummy_index_am/dummy_index_am.c b/src/test/modules/dummy_index_am/dummy_index_am.c index 8f4cdab1b3343..ac35023fb5c0e 100644 --- a/src/test/modules/dummy_index_am/dummy_index_am.c +++ b/src/test/modules/dummy_index_am/dummy_index_am.c @@ -3,7 +3,7 @@ * dummy_index_am.c * Index AM template main file. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION diff --git a/src/test/modules/dummy_seclabel/dummy_seclabel.c b/src/test/modules/dummy_seclabel/dummy_seclabel.c index 695c7d6d252c7..9da114411d606 100644 --- a/src/test/modules/dummy_seclabel/dummy_seclabel.c +++ b/src/test/modules/dummy_seclabel/dummy_seclabel.c @@ -7,7 +7,7 @@ * perspective, but allows regression testing independent of platform-specific * features like SELinux. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California */ #include "postgres.h" diff --git a/src/test/modules/plsample/plsample.c b/src/test/modules/plsample/plsample.c index 80faef506b151..6fc33c728cc36 100644 --- a/src/test/modules/plsample/plsample.c +++ b/src/test/modules/plsample/plsample.c @@ -3,7 +3,7 @@ * plsample.c * Handler for the PL/Sample procedural language * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/test/modules/test_bloomfilter/test_bloomfilter.c b/src/test/modules/test_bloomfilter/test_bloomfilter.c index 2a3fe3370d327..96c50114286a5 100644 --- a/src/test/modules/test_bloomfilter/test_bloomfilter.c +++ b/src/test/modules/test_bloomfilter/test_bloomfilter.c @@ -3,7 +3,7 @@ * test_bloomfilter.c * Test false positive rate of Bloom filter. * - * Copyright (c) 2018-2020, PostgreSQL Global Development Group + * Copyright (c) 2018-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/test/modules/test_bloomfilter/test_bloomfilter.c diff --git a/src/test/modules/test_ddl_deparse/test_ddl_deparse.c b/src/test/modules/test_ddl_deparse/test_ddl_deparse.c index def4e39f19deb..1bae1e543803e 100644 --- a/src/test/modules/test_ddl_deparse/test_ddl_deparse.c +++ b/src/test/modules/test_ddl_deparse/test_ddl_deparse.c @@ -2,7 +2,7 @@ * test_ddl_deparse.c * Support functions for the test_ddl_deparse module * - * Copyright (c) 2014-2020, PostgreSQL Global Development Group + * Copyright (c) 2014-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/test/modules/test_ddl_deparse/test_ddl_deparse.c diff --git a/src/test/modules/test_ginpostinglist/test_ginpostinglist.c b/src/test/modules/test_ginpostinglist/test_ginpostinglist.c index 4a8451e6592fd..7ce515fcb70e8 100644 --- a/src/test/modules/test_ginpostinglist/test_ginpostinglist.c +++ b/src/test/modules/test_ginpostinglist/test_ginpostinglist.c @@ -3,7 +3,7 @@ * test_ginpostinglist.c * Test varbyte-encoding in ginpostinglist.c * - * Copyright (c) 2019-2020, PostgreSQL Global Development Group + * Copyright (c) 2019-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/test/modules/test_ginpostinglist/test_ginpostinglist.c diff --git a/src/test/modules/test_integerset/test_integerset.c b/src/test/modules/test_integerset/test_integerset.c index bb9c9a0a727d1..21c6f49b3789a 100644 --- a/src/test/modules/test_integerset/test_integerset.c +++ b/src/test/modules/test_integerset/test_integerset.c @@ -3,7 +3,7 @@ * test_integerset.c * Test integer set data structure. * - * Copyright (c) 2019-2020, PostgreSQL Global Development Group + * Copyright (c) 2019-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/test/modules/test_integerset/test_integerset.c diff --git a/src/test/modules/test_parser/test_parser.c b/src/test/modules/test_parser/test_parser.c index 1279e9affdbff..f133676d6fc32 100644 --- a/src/test/modules/test_parser/test_parser.c +++ b/src/test/modules/test_parser/test_parser.c @@ -3,7 +3,7 @@ * test_parser.c * Simple example of a text search parser * - * Copyright (c) 2007-2020, PostgreSQL Global Development Group + * Copyright (c) 2007-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/test/modules/test_parser/test_parser.c diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c index 7cbb1bf4fdf02..9c0aadd61c871 100644 --- a/src/test/modules/test_predtest/test_predtest.c +++ b/src/test/modules/test_predtest/test_predtest.c @@ -3,7 +3,7 @@ * test_predtest.c * Test correctness of optimizer's predicate proof logic. * - * Copyright (c) 2018-2020, PostgreSQL Global Development Group + * Copyright (c) 2018-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/test/modules/test_predtest/test_predtest.c diff --git a/src/test/modules/test_rbtree/test_rbtree.c b/src/test/modules/test_rbtree/test_rbtree.c index 1b4b8cfcf130d..713ebd1b26d92 100644 --- a/src/test/modules/test_rbtree/test_rbtree.c +++ b/src/test/modules/test_rbtree/test_rbtree.c @@ -3,7 +3,7 @@ * test_rbtree.c * Test correctness of red-black tree operations. * - * Copyright (c) 2009-2020, PostgreSQL Global Development Group + * Copyright (c) 2009-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/test/modules/test_rbtree/test_rbtree.c diff --git a/src/test/modules/test_rls_hooks/test_rls_hooks.c b/src/test/modules/test_rls_hooks/test_rls_hooks.c index c0aaabdcdb84d..06c48f5b52f3a 100644 --- a/src/test/modules/test_rls_hooks/test_rls_hooks.c +++ b/src/test/modules/test_rls_hooks/test_rls_hooks.c @@ -3,7 +3,7 @@ * test_rls_hooks.c * Code for testing RLS hooks. * - * Copyright (c) 2015-2020, PostgreSQL Global Development Group + * Copyright (c) 2015-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/test/modules/test_rls_hooks/test_rls_hooks.c diff --git a/src/test/modules/test_rls_hooks/test_rls_hooks.h b/src/test/modules/test_rls_hooks/test_rls_hooks.h index f4c94bc54b927..e5659c845afa0 100644 --- a/src/test/modules/test_rls_hooks/test_rls_hooks.h +++ b/src/test/modules/test_rls_hooks/test_rls_hooks.h @@ -3,7 +3,7 @@ * test_rls_hooks.h * Definitions for RLS hooks * - * Copyright (c) 2015-2020, PostgreSQL Global Development Group + * Copyright (c) 2015-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/test/modules/test_rls_hooks/test_rls_hooks.h diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c index 509a90fa91c4c..e05e97c6de2e9 100644 --- a/src/test/modules/test_shm_mq/setup.c +++ b/src/test/modules/test_shm_mq/setup.c @@ -5,7 +5,7 @@ * number of background workers for shared memory message queue * testing. * - * Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Copyright (c) 2013-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/test/modules/test_shm_mq/setup.c diff --git a/src/test/modules/test_shm_mq/test.c b/src/test/modules/test_shm_mq/test.c index cf2b0e27ac57b..e5e32abac2dd7 100644 --- a/src/test/modules/test_shm_mq/test.c +++ b/src/test/modules/test_shm_mq/test.c @@ -3,7 +3,7 @@ * test.c * Test harness code for shared memory message queues. * - * Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Copyright (c) 2013-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/test/modules/test_shm_mq/test.c diff --git a/src/test/modules/test_shm_mq/test_shm_mq.h b/src/test/modules/test_shm_mq/test_shm_mq.h index 576485246b9b3..a666121834768 100644 --- a/src/test/modules/test_shm_mq/test_shm_mq.h +++ b/src/test/modules/test_shm_mq/test_shm_mq.h @@ -3,7 +3,7 @@ * test_shm_mq.h * Definitions for shared memory message queues * - * Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Copyright (c) 2013-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/test/modules/test_shm_mq/test_shm_mq.h diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c index 3f2e9bf81299f..2180776a669a1 100644 --- a/src/test/modules/test_shm_mq/worker.c +++ b/src/test/modules/test_shm_mq/worker.c @@ -9,7 +9,7 @@ * but it should be possible to use much of the control logic just * as presented here. * - * Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Copyright (c) 2013-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/test/modules/test_shm_mq/worker.c diff --git a/src/test/modules/worker_spi/worker_spi.c b/src/test/modules/worker_spi/worker_spi.c index 71f955206ad6e..d0acef26528d8 100644 --- a/src/test/modules/worker_spi/worker_spi.c +++ b/src/test/modules/worker_spi/worker_spi.c @@ -13,7 +13,7 @@ * "delta" type. Delta rows will be deleted by this worker and their values * aggregated into the total. * - * Copyright (c) 2013-2020, PostgreSQL Global Development Group + * Copyright (c) 2013-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/test/modules/worker_spi/worker_spi.c diff --git a/src/test/perl/Makefile b/src/test/perl/Makefile index acdd160620f44..ee5e5dd72c053 100644 --- a/src/test/perl/Makefile +++ b/src/test/perl/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/test/perl # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/test/perl/Makefile diff --git a/src/test/recovery/Makefile b/src/test/recovery/Makefile index fa8e031526715..96442ceb4e8ba 100644 --- a/src/test/recovery/Makefile +++ b/src/test/recovery/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/test/recovery # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/test/recovery/Makefile diff --git a/src/test/regress/GNUmakefile b/src/test/regress/GNUmakefile index c830627b00096..3d85857bfa8d7 100644 --- a/src/test/regress/GNUmakefile +++ b/src/test/regress/GNUmakefile @@ -3,7 +3,7 @@ # GNUmakefile-- # Makefile for src/test/regress (the regression tests) # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/test/regress/GNUmakefile diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c index 866bc8c4704dd..5cfb4c4a491ff 100644 --- a/src/test/regress/pg_regress.c +++ b/src/test/regress/pg_regress.c @@ -8,7 +8,7 @@ * * This code is released under the terms of the PostgreSQL License. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/test/regress/pg_regress.c diff --git a/src/test/regress/pg_regress.h b/src/test/regress/pg_regress.h index 726f9c904898d..d04f7721aa8a1 100644 --- a/src/test/regress/pg_regress.h +++ b/src/test/regress/pg_regress.h @@ -1,7 +1,7 @@ /*------------------------------------------------------------------------- * pg_regress.h --- regression test driver * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/test/regress/pg_regress.h diff --git a/src/test/regress/pg_regress_main.c b/src/test/regress/pg_regress_main.c index 5e503efa4a7b3..a218bae247c00 100644 --- a/src/test/regress/pg_regress_main.c +++ b/src/test/regress/pg_regress_main.c @@ -8,7 +8,7 @@ * * This code is released under the terms of the PostgreSQL License. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/test/regress/pg_regress_main.c diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c index b8b3af4e956eb..32ab9ed6b537a 100644 --- a/src/test/regress/regress.c +++ b/src/test/regress/regress.c @@ -6,7 +6,7 @@ * * This code is released under the terms of the PostgreSQL License. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/test/regress/regress.c diff --git a/src/test/ssl/Makefile b/src/test/ssl/Makefile index 777ee39413021..93335b1ea25ac 100644 --- a/src/test/ssl/Makefile +++ b/src/test/ssl/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/test/ssl # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/test/ssl/Makefile diff --git a/src/test/subscription/Makefile b/src/test/subscription/Makefile index 3ac06aa3de7a1..28fd6f6ccaddf 100644 --- a/src/test/subscription/Makefile +++ b/src/test/subscription/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/test/subscription # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/test/subscription/Makefile diff --git a/src/timezone/pgtz.c b/src/timezone/pgtz.c index 4a360f50774ff..82f14ee4b59f0 100644 --- a/src/timezone/pgtz.c +++ b/src/timezone/pgtz.c @@ -3,7 +3,7 @@ * pgtz.c * Timezone Library Integration Functions * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/timezone/pgtz.c diff --git a/src/timezone/pgtz.h b/src/timezone/pgtz.h index fb0c0d1d5e154..ca01722ee98a8 100644 --- a/src/timezone/pgtz.h +++ b/src/timezone/pgtz.h @@ -6,7 +6,7 @@ * Note: this file contains only definitions that are private to the * timezone library. Public definitions are in pgtime.h. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * * IDENTIFICATION * src/timezone/pgtz.h diff --git a/src/tools/PerfectHash.pm b/src/tools/PerfectHash.pm index 964f79b71a27e..db06d0461c435 100644 --- a/src/tools/PerfectHash.pm +++ b/src/tools/PerfectHash.pm @@ -20,7 +20,7 @@ # not in the set. # # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/tools/PerfectHash.pm diff --git a/src/tools/check_bison_recursion.pl b/src/tools/check_bison_recursion.pl index fce717147a52f..5bb5722ead62e 100755 --- a/src/tools/check_bison_recursion.pl +++ b/src/tools/check_bison_recursion.pl @@ -16,7 +16,7 @@ # To use: run bison with the -v switch, then feed the produced y.output # file to this script. # -# Copyright (c) 2011-2020, PostgreSQL Global Development Group +# Copyright (c) 2011-2021, PostgreSQL Global Development Group # # src/tools/check_bison_recursion.pl ################################################################# diff --git a/src/tools/copyright.pl b/src/tools/copyright.pl index 35ee8468186ee..a55e6430c242f 100755 --- a/src/tools/copyright.pl +++ b/src/tools/copyright.pl @@ -2,7 +2,7 @@ ################################################################# # copyright.pl -- update copyright notices throughout the source tree, idempotently. # -# Copyright (c) 2011-2020, PostgreSQL Global Development Group +# Copyright (c) 2011-2021, PostgreSQL Global Development Group # # src/tools/copyright.pl # diff --git a/src/tools/findoidjoins/Makefile b/src/tools/findoidjoins/Makefile index aa6ca2f259bde..4de9d10c2ab04 100644 --- a/src/tools/findoidjoins/Makefile +++ b/src/tools/findoidjoins/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/tools/findoidjoins # -# Copyright (c) 2003-2020, PostgreSQL Global Development Group +# Copyright (c) 2003-2021, PostgreSQL Global Development Group # # src/tools/findoidjoins/Makefile # diff --git a/src/tools/findoidjoins/findoidjoins.c b/src/tools/findoidjoins/findoidjoins.c index 3d9ca26235765..a42c8a34da2fc 100644 --- a/src/tools/findoidjoins/findoidjoins.c +++ b/src/tools/findoidjoins/findoidjoins.c @@ -1,7 +1,7 @@ /* * findoidjoins.c * - * Copyright (c) 2002-2020, PostgreSQL Global Development Group + * Copyright (c) 2002-2021, PostgreSQL Global Development Group * * src/tools/findoidjoins/findoidjoins.c */ diff --git a/src/tools/fix-old-flex-code.pl b/src/tools/fix-old-flex-code.pl index 1bbb7cdb84163..62b89e0e84554 100644 --- a/src/tools/fix-old-flex-code.pl +++ b/src/tools/fix-old-flex-code.pl @@ -8,7 +8,7 @@ # let's suppress it by inserting a dummy reference to the variable. # (That's exactly what 2.5.36 and later do ...) # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/tools/fix-old-flex-code.pl diff --git a/src/tools/gen_keywordlist.pl b/src/tools/gen_keywordlist.pl index e9250b8fb2e2f..396d938ea05f0 100644 --- a/src/tools/gen_keywordlist.pl +++ b/src/tools/gen_keywordlist.pl @@ -21,7 +21,7 @@ # Note that case folding works correctly only for all-ASCII keywords! # # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/tools/gen_keywordlist.pl @@ -71,7 +71,7 @@ * %s.h * List of keywords represented as a ScanKeywordList. * - * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES diff --git a/src/tools/ifaddrs/Makefile b/src/tools/ifaddrs/Makefile index 3cd7da422e010..7cce9a5e6213c 100644 --- a/src/tools/ifaddrs/Makefile +++ b/src/tools/ifaddrs/Makefile @@ -2,7 +2,7 @@ # # Makefile for src/tools/ifaddrs # -# Copyright (c) 2003-2020, PostgreSQL Global Development Group +# Copyright (c) 2003-2021, PostgreSQL Global Development Group # # src/tools/ifaddrs/Makefile # diff --git a/src/tools/pginclude/cpluspluscheck b/src/tools/pginclude/cpluspluscheck index a5132cbadf2b1..e52d5e4240855 100755 --- a/src/tools/pginclude/cpluspluscheck +++ b/src/tools/pginclude/cpluspluscheck @@ -13,7 +13,7 @@ # No output if everything is OK, else compiler errors. # # src/tools/pginclude/cpluspluscheck -# Copyright (c) 2009-2020, PostgreSQL Global Development Group +# Copyright (c) 2009-2021, PostgreSQL Global Development Group if [ -z "$1" ]; then srcdir="." diff --git a/src/tools/pginclude/headerscheck b/src/tools/pginclude/headerscheck index 95f40820d3134..5dab555340afd 100755 --- a/src/tools/pginclude/headerscheck +++ b/src/tools/pginclude/headerscheck @@ -13,7 +13,7 @@ # No output if everything is OK, else compiler errors. # # src/tools/pginclude/headerscheck -# Copyright (c) 2009-2020, PostgreSQL Global Development Group +# Copyright (c) 2009-2021, PostgreSQL Global Development Group if [ -z "$1" ]; then srcdir="." diff --git a/src/tools/testint128.c b/src/tools/testint128.c index 6df518df51729..71c345969a854 100644 --- a/src/tools/testint128.c +++ b/src/tools/testint128.c @@ -6,7 +6,7 @@ * This is a standalone test program that compares the behavior of an * implementation in int128.h to an (assumed correct) int128 native type. * - * Copyright (c) 2017-2020, PostgreSQL Global Development Group + * Copyright (c) 2017-2021, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/tools/version_stamp.pl b/src/tools/version_stamp.pl index 36b18d514cf8d..ee8f314b3cda5 100755 --- a/src/tools/version_stamp.pl +++ b/src/tools/version_stamp.pl @@ -3,7 +3,7 @@ ################################################################# # version_stamp.pl -- update version stamps throughout the source tree # -# Copyright (c) 2008-2020, PostgreSQL Global Development Group +# Copyright (c) 2008-2021, PostgreSQL Global Development Group # # src/tools/version_stamp.pl ################################################################# diff --git a/src/tools/win32tzlist.pl b/src/tools/win32tzlist.pl index 9d9d08596e91f..3dd0aaae8e0e0 100755 --- a/src/tools/win32tzlist.pl +++ b/src/tools/win32tzlist.pl @@ -2,7 +2,7 @@ # # win32tzlist.pl -- compare Windows timezone information # -# Copyright (c) 2008-2020, PostgreSQL Global Development Group +# Copyright (c) 2008-2021, PostgreSQL Global Development Group # # src/tools/win32tzlist.pl ################################################################# diff --git a/src/tutorial/complex.source b/src/tutorial/complex.source index d849ec0d4b707..d1f61fdd2e91a 100644 --- a/src/tutorial/complex.source +++ b/src/tutorial/complex.source @@ -5,7 +5,7 @@ -- use this new type. -- -- --- Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +-- Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group -- Portions Copyright (c) 1994, Regents of the University of California -- -- src/tutorial/complex.source diff --git a/src/tutorial/syscat.source b/src/tutorial/syscat.source index 8a04d6a961f28..6b3031c4249f2 100644 --- a/src/tutorial/syscat.source +++ b/src/tutorial/syscat.source @@ -4,7 +4,7 @@ -- sample queries to the system catalogs -- -- --- Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +-- Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group -- Portions Copyright (c) 1994, Regents of the University of California -- -- src/tutorial/syscat.source From a271a1b50e9bec07e2ef3a05e38e7285113e4ce6 Mon Sep 17 00:00:00 2001 From: Amit Kapila Date: Mon, 4 Jan 2021 08:34:50 +0530 Subject: [PATCH 022/240] Allow decoding at prepare time in ReorderBuffer. This patch allows PREPARE-time decoding of two-phase transactions (if the output plugin supports this capability), in which case the transactions are replayed at PREPARE and then committed later when COMMIT PREPARED arrives. Now that we decode the changes before the commit, the concurrent aborts may cause failures when the output plugin consults catalogs (both system and user-defined). We detect such failures with a special sqlerrcode ERRCODE_TRANSACTION_ROLLBACK introduced by commit 7259736a6e and stop decoding the remaining changes. Then we rollback the changes when rollback prepared is encountered. Author: Ajin Cherian and Amit Kapila based on previous work by Nikhil Sontakke and Stas Kelvich Reviewed-by: Amit Kapila, Peter Smith, Sawada Masahiko, Arseny Sher, and Dilip Kumar Tested-by: Takamichi Osumi Discussion: https://postgr.es/m/02DA5F5E-CECE-4D9C-8B4B-418077E2C010@postgrespro.ru https://postgr.es/m/CAMGcDxeqEpWj3fTXwqhSwBdXd2RS9jzwWscO-XbeCfso6ts3+Q@mail.gmail.com --- contrib/test_decoding/Makefile | 2 +- contrib/test_decoding/expected/twophase.out | 235 ++++++++++ .../expected/twophase_stream.out | 147 ++++++ contrib/test_decoding/sql/twophase.sql | 112 +++++ contrib/test_decoding/sql/twophase_stream.sql | 45 ++ doc/src/sgml/logicaldecoding.sgml | 104 ++++- src/backend/replication/logical/decode.c | 286 ++++++++++-- src/backend/replication/logical/logical.c | 9 - .../replication/logical/reorderbuffer.c | 432 +++++++++++++++--- src/backend/replication/logical/snapbuild.c | 7 + src/include/replication/reorderbuffer.h | 33 +- 11 files changed, 1296 insertions(+), 116 deletions(-) create mode 100644 contrib/test_decoding/expected/twophase.out create mode 100644 contrib/test_decoding/expected/twophase_stream.out create mode 100644 contrib/test_decoding/sql/twophase.sql create mode 100644 contrib/test_decoding/sql/twophase_stream.sql diff --git a/contrib/test_decoding/Makefile b/contrib/test_decoding/Makefile index 9a4c76f013645..76d4a6977269a 100644 --- a/contrib/test_decoding/Makefile +++ b/contrib/test_decoding/Makefile @@ -5,7 +5,7 @@ PGFILEDESC = "test_decoding - example of a logical decoding output plugin" REGRESS = ddl xact rewrite toast permissions decoding_in_xact \ decoding_into_rel binary prepared replorigin time messages \ - spill slot truncate stream stats + spill slot truncate stream stats twophase twophase_stream ISOLATION = mxact delayed_startup ondisk_startup concurrent_ddl_dml \ oldest_xmin snapshot_transfer subxact_without_top concurrent_stream diff --git a/contrib/test_decoding/expected/twophase.out b/contrib/test_decoding/expected/twophase.out new file mode 100644 index 0000000000000..f9f6bedd1cffb --- /dev/null +++ b/contrib/test_decoding/expected/twophase.out @@ -0,0 +1,235 @@ +-- Test prepared transactions. When two-phase-commit is enabled, transactions are +-- decoded at PREPARE time rather than at COMMIT PREPARED time. +SET synchronous_commit = on; +SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding'); + ?column? +---------- + init +(1 row) + +CREATE TABLE test_prepared1(id integer primary key); +CREATE TABLE test_prepared2(id integer primary key); +-- Test that decoding happens at PREPARE time when two-phase-commit is enabled. +-- Decoding after COMMIT PREPARED must have all the commands in the transaction. +BEGIN; +INSERT INTO test_prepared1 VALUES (1); +INSERT INTO test_prepared1 VALUES (2); +-- should show nothing because the xact has not been prepared yet. +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); + data +------ +(0 rows) + +PREPARE TRANSACTION 'test_prepared#1'; +-- should show both the above inserts and the PREPARE TRANSACTION. +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); + data +---------------------------------------------------- + BEGIN + table public.test_prepared1: INSERT: id[integer]:1 + table public.test_prepared1: INSERT: id[integer]:2 + PREPARE TRANSACTION 'test_prepared#1' +(4 rows) + +COMMIT PREPARED 'test_prepared#1'; +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); + data +---------------------------------------------------- + BEGIN + table public.test_prepared1: INSERT: id[integer]:1 + table public.test_prepared1: INSERT: id[integer]:2 + PREPARE TRANSACTION 'test_prepared#1' + COMMIT PREPARED 'test_prepared#1' +(5 rows) + +-- Test that rollback of a prepared xact is decoded. +BEGIN; +INSERT INTO test_prepared1 VALUES (3); +PREPARE TRANSACTION 'test_prepared#2'; +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); + data +---------------------------------------------------- + BEGIN + table public.test_prepared1: INSERT: id[integer]:3 + PREPARE TRANSACTION 'test_prepared#2' +(3 rows) + +ROLLBACK PREPARED 'test_prepared#2'; +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); + data +------------------------------------- + ROLLBACK PREPARED 'test_prepared#2' +(1 row) + +-- Test prepare of a xact containing ddl. Leaving xact uncommitted for next test. +BEGIN; +ALTER TABLE test_prepared1 ADD COLUMN data text; +INSERT INTO test_prepared1 VALUES (4, 'frakbar'); +PREPARE TRANSACTION 'test_prepared#3'; +-- confirm that exclusive lock from the ALTER command is held on test_prepared1 table +SELECT 'test_prepared_1' AS relation, locktype, mode +FROM pg_locks +WHERE locktype = 'relation' + AND relation = 'test_prepared1'::regclass; + relation | locktype | mode +-----------------+----------+--------------------- + test_prepared_1 | relation | RowExclusiveLock + test_prepared_1 | relation | AccessExclusiveLock +(2 rows) + +-- The insert should show the newly altered column but not the DDL. +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); + data +------------------------------------------------------------------------- + BEGIN + table public.test_prepared1: INSERT: id[integer]:4 data[text]:'frakbar' + PREPARE TRANSACTION 'test_prepared#3' +(3 rows) + +-- Test that we decode correctly while an uncommitted prepared xact +-- with ddl exists. +-- +-- Use a separate table for the concurrent transaction because the lock from +-- the ALTER will stop us inserting into the other one. +-- +INSERT INTO test_prepared2 VALUES (5); +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); + data +---------------------------------------------------- + BEGIN + table public.test_prepared2: INSERT: id[integer]:5 + COMMIT +(3 rows) + +COMMIT PREPARED 'test_prepared#3'; +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); + data +------------------------------------------------------------------------- + BEGIN + table public.test_prepared1: INSERT: id[integer]:4 data[text]:'frakbar' + PREPARE TRANSACTION 'test_prepared#3' + COMMIT PREPARED 'test_prepared#3' +(4 rows) + +-- make sure stuff still works +INSERT INTO test_prepared1 VALUES (6); +INSERT INTO test_prepared2 VALUES (7); +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); + data +-------------------------------------------------------------------- + BEGIN + table public.test_prepared1: INSERT: id[integer]:6 data[text]:null + COMMIT + BEGIN + table public.test_prepared2: INSERT: id[integer]:7 + COMMIT +(6 rows) + +-- Check 'CLUSTER' (as operation that hold exclusive lock) doesn't block +-- logical decoding. +BEGIN; +INSERT INTO test_prepared1 VALUES (8, 'othercol'); +CLUSTER test_prepared1 USING test_prepared1_pkey; +INSERT INTO test_prepared1 VALUES (9, 'othercol2'); +PREPARE TRANSACTION 'test_prepared_lock'; +SELECT 'test_prepared1' AS relation, locktype, mode +FROM pg_locks +WHERE locktype = 'relation' + AND relation = 'test_prepared1'::regclass; + relation | locktype | mode +----------------+----------+--------------------- + test_prepared1 | relation | RowExclusiveLock + test_prepared1 | relation | ShareLock + test_prepared1 | relation | AccessExclusiveLock +(3 rows) + +-- The above CLUSTER command shouldn't cause a timeout on 2pc decoding. The +-- call should return within a second. +SET statement_timeout = '1s'; +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); + data +--------------------------------------------------------------------------- + BEGIN + table public.test_prepared1: INSERT: id[integer]:8 data[text]:'othercol' + table public.test_prepared1: INSERT: id[integer]:9 data[text]:'othercol2' + PREPARE TRANSACTION 'test_prepared_lock' +(4 rows) + +RESET statement_timeout; +COMMIT PREPARED 'test_prepared_lock'; +-- consume the commit +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); + data +--------------------------------------------------------------------------- + BEGIN + table public.test_prepared1: INSERT: id[integer]:8 data[text]:'othercol' + table public.test_prepared1: INSERT: id[integer]:9 data[text]:'othercol2' + PREPARE TRANSACTION 'test_prepared_lock' + COMMIT PREPARED 'test_prepared_lock' +(5 rows) + +-- Test savepoints and sub-xacts. Creating savepoints will create +-- sub-xacts implicitly. +BEGIN; +CREATE TABLE test_prepared_savepoint (a int); +INSERT INTO test_prepared_savepoint VALUES (1); +SAVEPOINT test_savepoint; +INSERT INTO test_prepared_savepoint VALUES (2); +ROLLBACK TO SAVEPOINT test_savepoint; +PREPARE TRANSACTION 'test_prepared_savepoint'; +-- should show only 1, not 2 +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); + data +------------------------------------------------------------ + BEGIN + table public.test_prepared_savepoint: INSERT: a[integer]:1 + PREPARE TRANSACTION 'test_prepared_savepoint' +(3 rows) + +COMMIT PREPARED 'test_prepared_savepoint'; +-- consume the commit +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); + data +------------------------------------------------------------ + BEGIN + table public.test_prepared_savepoint: INSERT: a[integer]:1 + PREPARE TRANSACTION 'test_prepared_savepoint' + COMMIT PREPARED 'test_prepared_savepoint' +(4 rows) + +-- Test that a GID containing "_nodecode" gets decoded at commit prepared time. +BEGIN; +INSERT INTO test_prepared1 VALUES (20); +PREPARE TRANSACTION 'test_prepared_nodecode'; +-- should show nothing +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); + data +------ +(0 rows) + +COMMIT PREPARED 'test_prepared_nodecode'; +-- should be decoded now +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); + data +--------------------------------------------------------------------- + BEGIN + table public.test_prepared1: INSERT: id[integer]:20 data[text]:null + COMMIT +(3 rows) + +-- Test 8: +-- cleanup and make sure results are also empty +DROP TABLE test_prepared1; +DROP TABLE test_prepared2; +-- show results. There should be nothing to show +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); + data +------ +(0 rows) + +SELECT pg_drop_replication_slot('regression_slot'); + pg_drop_replication_slot +-------------------------- + +(1 row) + diff --git a/contrib/test_decoding/expected/twophase_stream.out b/contrib/test_decoding/expected/twophase_stream.out new file mode 100644 index 0000000000000..3acc4acd3651d --- /dev/null +++ b/contrib/test_decoding/expected/twophase_stream.out @@ -0,0 +1,147 @@ +-- Test streaming of two-phase commits +SET synchronous_commit = on; +SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding'); + ?column? +---------- + init +(1 row) + +CREATE TABLE stream_test(data text); +-- consume DDL +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); + data +------ +(0 rows) + +-- streaming test with sub-transaction and PREPARE/COMMIT PREPARED +BEGIN; +SAVEPOINT s1; +SELECT 'msg5' FROM pg_logical_emit_message(true, 'test', repeat('a', 50)); + ?column? +---------- + msg5 +(1 row) + +INSERT INTO stream_test SELECT repeat('a', 2000) || g.i FROM generate_series(1, 35) g(i); +TRUNCATE table stream_test; +ROLLBACK TO s1; +INSERT INTO stream_test SELECT repeat('a', 10) || g.i FROM generate_series(1, 20) g(i); +PREPARE TRANSACTION 'test1'; +-- should show the inserts after a ROLLBACK +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1', 'stream-changes', '1'); + data +---------------------------------------------------------- + streaming message: transactional: 1 prefix: test, sz: 50 + opening a streamed block for transaction + streaming change for transaction + streaming change for transaction + streaming change for transaction + streaming change for transaction + streaming change for transaction + streaming change for transaction + streaming change for transaction + streaming change for transaction + streaming change for transaction + streaming change for transaction + streaming change for transaction + streaming change for transaction + streaming change for transaction + streaming change for transaction + streaming change for transaction + streaming change for transaction + streaming change for transaction + streaming change for transaction + streaming change for transaction + streaming change for transaction + closing a streamed block for transaction + preparing streamed transaction 'test1' +(24 rows) + +COMMIT PREPARED 'test1'; +--should show the COMMIT PREPARED and the other changes in the transaction +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1', 'stream-changes', '1'); + data +------------------------------------------------------------- + BEGIN + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa1' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa2' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa3' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa4' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa5' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa6' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa7' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa8' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa9' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa10' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa11' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa12' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa13' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa14' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa15' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa16' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa17' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa18' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa19' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa20' + PREPARE TRANSACTION 'test1' + COMMIT PREPARED 'test1' +(23 rows) + +-- streaming test with sub-transaction and PREPARE/COMMIT PREPARED but with +-- filtered gid. gids with '_nodecode' will not be decoded at prepare time. +BEGIN; +SAVEPOINT s1; +SELECT 'msg5' FROM pg_logical_emit_message(true, 'test', repeat('a', 50)); + ?column? +---------- + msg5 +(1 row) + +INSERT INTO stream_test SELECT repeat('a', 2000) || g.i FROM generate_series(1, 35) g(i); +TRUNCATE table stream_test; +ROLLBACK to s1; +INSERT INTO stream_test SELECT repeat('a', 10) || g.i FROM generate_series(1, 20) g(i); +PREPARE TRANSACTION 'test1_nodecode'; +-- should NOT show inserts after a ROLLBACK +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1', 'stream-changes', '1'); + data +---------------------------------------------------------- + streaming message: transactional: 1 prefix: test, sz: 50 +(1 row) + +COMMIT PREPARED 'test1_nodecode'; +-- should show the inserts but not show a COMMIT PREPARED but a COMMIT +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1', 'stream-changes', '1'); + data +------------------------------------------------------------- + BEGIN + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa1' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa2' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa3' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa4' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa5' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa6' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa7' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa8' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa9' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa10' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa11' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa12' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa13' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa14' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa15' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa16' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa17' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa18' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa19' + table public.stream_test: INSERT: data[text]:'aaaaaaaaaa20' + COMMIT +(22 rows) + +DROP TABLE stream_test; +SELECT pg_drop_replication_slot('regression_slot'); + pg_drop_replication_slot +-------------------------- + +(1 row) + diff --git a/contrib/test_decoding/sql/twophase.sql b/contrib/test_decoding/sql/twophase.sql new file mode 100644 index 0000000000000..894e4f5baf15e --- /dev/null +++ b/contrib/test_decoding/sql/twophase.sql @@ -0,0 +1,112 @@ +-- Test prepared transactions. When two-phase-commit is enabled, transactions are +-- decoded at PREPARE time rather than at COMMIT PREPARED time. +SET synchronous_commit = on; +SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding'); + +CREATE TABLE test_prepared1(id integer primary key); +CREATE TABLE test_prepared2(id integer primary key); + +-- Test that decoding happens at PREPARE time when two-phase-commit is enabled. +-- Decoding after COMMIT PREPARED must have all the commands in the transaction. +BEGIN; +INSERT INTO test_prepared1 VALUES (1); +INSERT INTO test_prepared1 VALUES (2); +-- should show nothing because the xact has not been prepared yet. +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); +PREPARE TRANSACTION 'test_prepared#1'; +-- should show both the above inserts and the PREPARE TRANSACTION. +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); +COMMIT PREPARED 'test_prepared#1'; +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); + +-- Test that rollback of a prepared xact is decoded. +BEGIN; +INSERT INTO test_prepared1 VALUES (3); +PREPARE TRANSACTION 'test_prepared#2'; +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); +ROLLBACK PREPARED 'test_prepared#2'; +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); + +-- Test prepare of a xact containing ddl. Leaving xact uncommitted for next test. +BEGIN; +ALTER TABLE test_prepared1 ADD COLUMN data text; +INSERT INTO test_prepared1 VALUES (4, 'frakbar'); +PREPARE TRANSACTION 'test_prepared#3'; +-- confirm that exclusive lock from the ALTER command is held on test_prepared1 table +SELECT 'test_prepared_1' AS relation, locktype, mode +FROM pg_locks +WHERE locktype = 'relation' + AND relation = 'test_prepared1'::regclass; +-- The insert should show the newly altered column but not the DDL. +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); + +-- Test that we decode correctly while an uncommitted prepared xact +-- with ddl exists. +-- +-- Use a separate table for the concurrent transaction because the lock from +-- the ALTER will stop us inserting into the other one. +-- +INSERT INTO test_prepared2 VALUES (5); +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); + +COMMIT PREPARED 'test_prepared#3'; +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); +-- make sure stuff still works +INSERT INTO test_prepared1 VALUES (6); +INSERT INTO test_prepared2 VALUES (7); +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); + +-- Check 'CLUSTER' (as operation that hold exclusive lock) doesn't block +-- logical decoding. +BEGIN; +INSERT INTO test_prepared1 VALUES (8, 'othercol'); +CLUSTER test_prepared1 USING test_prepared1_pkey; +INSERT INTO test_prepared1 VALUES (9, 'othercol2'); +PREPARE TRANSACTION 'test_prepared_lock'; + +SELECT 'test_prepared1' AS relation, locktype, mode +FROM pg_locks +WHERE locktype = 'relation' + AND relation = 'test_prepared1'::regclass; +-- The above CLUSTER command shouldn't cause a timeout on 2pc decoding. The +-- call should return within a second. +SET statement_timeout = '1s'; +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); +RESET statement_timeout; +COMMIT PREPARED 'test_prepared_lock'; +-- consume the commit +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); + +-- Test savepoints and sub-xacts. Creating savepoints will create +-- sub-xacts implicitly. +BEGIN; +CREATE TABLE test_prepared_savepoint (a int); +INSERT INTO test_prepared_savepoint VALUES (1); +SAVEPOINT test_savepoint; +INSERT INTO test_prepared_savepoint VALUES (2); +ROLLBACK TO SAVEPOINT test_savepoint; +PREPARE TRANSACTION 'test_prepared_savepoint'; +-- should show only 1, not 2 +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); +COMMIT PREPARED 'test_prepared_savepoint'; +-- consume the commit +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); + +-- Test that a GID containing "_nodecode" gets decoded at commit prepared time. +BEGIN; +INSERT INTO test_prepared1 VALUES (20); +PREPARE TRANSACTION 'test_prepared_nodecode'; +-- should show nothing +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); +COMMIT PREPARED 'test_prepared_nodecode'; +-- should be decoded now +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); + +-- Test 8: +-- cleanup and make sure results are also empty +DROP TABLE test_prepared1; +DROP TABLE test_prepared2; +-- show results. There should be nothing to show +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1'); + +SELECT pg_drop_replication_slot('regression_slot'); diff --git a/contrib/test_decoding/sql/twophase_stream.sql b/contrib/test_decoding/sql/twophase_stream.sql new file mode 100644 index 0000000000000..e9dd44fdb37bb --- /dev/null +++ b/contrib/test_decoding/sql/twophase_stream.sql @@ -0,0 +1,45 @@ +-- Test streaming of two-phase commits + +SET synchronous_commit = on; +SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding'); + +CREATE TABLE stream_test(data text); + +-- consume DDL +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); + +-- streaming test with sub-transaction and PREPARE/COMMIT PREPARED +BEGIN; +SAVEPOINT s1; +SELECT 'msg5' FROM pg_logical_emit_message(true, 'test', repeat('a', 50)); +INSERT INTO stream_test SELECT repeat('a', 2000) || g.i FROM generate_series(1, 35) g(i); +TRUNCATE table stream_test; +ROLLBACK TO s1; +INSERT INTO stream_test SELECT repeat('a', 10) || g.i FROM generate_series(1, 20) g(i); +PREPARE TRANSACTION 'test1'; +-- should show the inserts after a ROLLBACK +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1', 'stream-changes', '1'); + +COMMIT PREPARED 'test1'; +--should show the COMMIT PREPARED and the other changes in the transaction +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1', 'stream-changes', '1'); + +-- streaming test with sub-transaction and PREPARE/COMMIT PREPARED but with +-- filtered gid. gids with '_nodecode' will not be decoded at prepare time. +BEGIN; +SAVEPOINT s1; +SELECT 'msg5' FROM pg_logical_emit_message(true, 'test', repeat('a', 50)); +INSERT INTO stream_test SELECT repeat('a', 2000) || g.i FROM generate_series(1, 35) g(i); +TRUNCATE table stream_test; +ROLLBACK to s1; +INSERT INTO stream_test SELECT repeat('a', 10) || g.i FROM generate_series(1, 20) g(i); +PREPARE TRANSACTION 'test1_nodecode'; +-- should NOT show inserts after a ROLLBACK +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1', 'stream-changes', '1'); + +COMMIT PREPARED 'test1_nodecode'; +-- should show the inserts but not show a COMMIT PREPARED but a COMMIT +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL, 'two-phase-commit', '1', 'include-xids', '0', 'skip-empty-xacts', '1', 'stream-changes', '1'); + +DROP TABLE stream_test; +SELECT pg_drop_replication_slot('regression_slot'); diff --git a/doc/src/sgml/logicaldecoding.sgml b/doc/src/sgml/logicaldecoding.sgml index d63f90ff282b8..cf705ed9cda36 100644 --- a/doc/src/sgml/logicaldecoding.sgml +++ b/doc/src/sgml/logicaldecoding.sgml @@ -165,7 +165,58 @@ COMMIT 693 ControlC $ pg_recvlogical -d postgres --slot=test --drop-slot - + + + The following example shows SQL interface that can be used to decode prepared + transactions. Before you use two-phase commit commands, you must set + max_prepared_transactions to at least 1. You must also set + the option 'two-phase-commit' to 1 while calling + pg_logical_slot_get_changes. Note that we will stream + the entire transaction after the commit if it is not already decoded. + + +postgres=# BEGIN; +postgres=*# INSERT INTO data(data) VALUES('5'); +postgres=*# PREPARE TRANSACTION 'test_prepared1'; + +postgres=# SELECT * FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1'); + lsn | xid | data +-----------+-----+--------------------------------------------------------- + 0/1689DC0 | 529 | BEGIN 529 + 0/1689DC0 | 529 | table public.data: INSERT: id[integer]:3 data[text]:'5' + 0/1689FC0 | 529 | PREPARE TRANSACTION 'test_prepared1', txid 529 +(3 rows) + +postgres=# COMMIT PREPARED 'test_prepared1'; +postgres=# select * from pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1'); + lsn | xid | data +-----------+-----+-------------------------------------------- + 0/1689DC0 | 529 | BEGIN 529 + 0/1689DC0 | 529 | table public.data: INSERT: id[integer]:3 data[text]:'5' + 0/1689FC0 | 529 | PREPARE TRANSACTION 'test_prepared1', txid 529 + 0/168A060 | 529 | COMMIT PREPARED 'test_prepared1', txid 529 +(4 row) + +postgres=#-- you can also rollback a prepared transaction +postgres=# BEGIN; +postgres=*# INSERT INTO data(data) VALUES('6'); +postgres=*# PREPARE TRANSACTION 'test_prepared2'; +postgres=# select * from pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1'); + lsn | xid | data +-----------+-----+--------------------------------------------------------- + 0/168A180 | 530 | BEGIN 530 + 0/168A1E8 | 530 | table public.data: INSERT: id[integer]:4 data[text]:'6' + 0/168A430 | 530 | PREPARE TRANSACTION 'test_prepared2', txid 530 +(3 rows) + +postgres=# ROLLBACK PREPARED 'test_prepared2'; +postgres=# select * from pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1'); + lsn | xid | data +-----------+-----+---------------------------------------------- + 0/168A4B8 | 530 | ROLLBACK PREPARED 'test_prepared2', txid 530 +(1 row) + + Logical Decoding Concepts @@ -1126,4 +1177,55 @@ stream_commit_cb(...); <-- commit of the streamed transaction + + + Two-phase commit support for Logical Decoding + + + With the basic output plugin callbacks (eg., begin_cb, + change_cb, commit_cb and + message_cb) two-phase commit commands like + PREPARE TRANSACTION, COMMIT PREPARED + and ROLLBACK PREPARED are not decoded. While the + PREPARE TRANSACTION is ignored, + COMMIT PREPARED is decoded as a COMMIT + and ROLLBACK PREPARED is decoded as a + ROLLBACK. + + + + To support the streaming of two-phase commands, an output plugin needs to + provide additional callbacks. There are multiple two-phase commit callbacks + that are required, (begin_prepare_cb, + prepare_cb, commit_prepared_cb, + rollback_prepared_cb and + stream_prepare_cb) and an optional callback + (filter_prepare_cb). + + + + If the output plugin callbacks for decoding two-phase commit commands are + provided, then on PREPARE TRANSACTION, the changes of + that transaction are decoded, passed to the output plugin, and the + prepare_cb callback is invoked. This differs from the + basic decoding setup where changes are only passed to the output plugin + when a transaction is committed. The start of a prepared transaction is + indicated by the begin_prepare_cb callback. + + + + When a prepared transaction is rollbacked using the + ROLLBACK PREPARED, then the + rollback_prepared_cb callback is invoked and when the + prepared transaction is committed using COMMIT PREPARED, + then the commit_prepared_cb callback is invoked. + + + + Optionally the output plugin can specify a name pattern in the + filter_prepare_cb and transactions with gid containing + that name pattern will not be decoded as a two-phase commit transaction. + + + diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c index 1887ba79440ec..23ab3cf605246 100644 --- a/src/backend/replication/logical/decode.c +++ b/src/backend/replication/logical/decode.c @@ -67,13 +67,24 @@ static void DecodeMultiInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf static void DecodeSpecConfirm(LogicalDecodingContext *ctx, XLogRecordBuffer *buf); static void DecodeCommit(LogicalDecodingContext *ctx, XLogRecordBuffer *buf, - xl_xact_parsed_commit *parsed, TransactionId xid); + xl_xact_parsed_commit *parsed, TransactionId xid, + bool two_phase); static void DecodeAbort(LogicalDecodingContext *ctx, XLogRecordBuffer *buf, - xl_xact_parsed_abort *parsed, TransactionId xid); + xl_xact_parsed_abort *parsed, TransactionId xid, + bool two_phase); +static void DecodePrepare(LogicalDecodingContext *ctx, XLogRecordBuffer *buf, + xl_xact_parsed_prepare *parsed); + /* common function to decode tuples */ static void DecodeXLogTuple(char *data, Size len, ReorderBufferTupleBuf *tup); +/* helper functions for decoding transactions */ +static inline bool FilterPrepare(LogicalDecodingContext *ctx, const char *gid); +static bool DecodeTXNNeedSkip(LogicalDecodingContext *ctx, + XLogRecordBuffer *buf, Oid dbId, + RepOriginId origin_id); + /* * Take every XLogReadRecord()ed record and perform the actions required to * decode it using the output plugin already setup in the logical decoding @@ -244,6 +255,7 @@ DecodeXactOp(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) xl_xact_commit *xlrec; xl_xact_parsed_commit parsed; TransactionId xid; + bool two_phase = false; xlrec = (xl_xact_commit *) XLogRecGetData(r); ParseCommitRecord(XLogRecGetInfo(buf->record), xlrec, &parsed); @@ -253,7 +265,15 @@ DecodeXactOp(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) else xid = parsed.twophase_xid; - DecodeCommit(ctx, buf, &parsed, xid); + /* + * We would like to process the transaction in a two-phase + * manner iff output plugin supports two-phase commits and + * doesn't filter the transaction at prepare time. + */ + if (info == XLOG_XACT_COMMIT_PREPARED) + two_phase = !(FilterPrepare(ctx, parsed.twophase_gid)); + + DecodeCommit(ctx, buf, &parsed, xid, two_phase); break; } case XLOG_XACT_ABORT: @@ -262,6 +282,7 @@ DecodeXactOp(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) xl_xact_abort *xlrec; xl_xact_parsed_abort parsed; TransactionId xid; + bool two_phase = false; xlrec = (xl_xact_abort *) XLogRecGetData(r); ParseAbortRecord(XLogRecGetInfo(buf->record), xlrec, &parsed); @@ -271,7 +292,15 @@ DecodeXactOp(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) else xid = parsed.twophase_xid; - DecodeAbort(ctx, buf, &parsed, xid); + /* + * We would like to process the transaction in a two-phase + * manner iff output plugin supports two-phase commits and + * doesn't filter the transaction at prepare time. + */ + if (info == XLOG_XACT_ABORT_PREPARED) + two_phase = !(FilterPrepare(ctx, parsed.twophase_gid)); + + DecodeAbort(ctx, buf, &parsed, xid, two_phase); break; } case XLOG_XACT_ASSIGNMENT: @@ -312,17 +341,30 @@ DecodeXactOp(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) } break; case XLOG_XACT_PREPARE: + { + xl_xact_parsed_prepare parsed; + xl_xact_prepare *xlrec; - /* - * Currently decoding ignores PREPARE TRANSACTION and will just - * decode the transaction when the COMMIT PREPARED is sent or - * throw away the transaction's contents when a ROLLBACK PREPARED - * is received. In the future we could add code to expose prepared - * transactions in the changestream allowing for a kind of - * distributed 2PC. - */ - ReorderBufferProcessXid(reorder, XLogRecGetXid(r), buf->origptr); - break; + /* ok, parse it */ + xlrec = (xl_xact_prepare *) XLogRecGetData(r); + ParsePrepareRecord(XLogRecGetInfo(buf->record), + xlrec, &parsed); + + /* + * We would like to process the transaction in a two-phase + * manner iff output plugin supports two-phase commits and + * doesn't filter the transaction at prepare time. + */ + if (FilterPrepare(ctx, parsed.twophase_gid)) + { + ReorderBufferProcessXid(reorder, parsed.twophase_xid, + buf->origptr); + break; + } + + DecodePrepare(ctx, buf, &parsed); + break; + } default: elog(ERROR, "unexpected RM_XACT_ID record type: %u", info); } @@ -520,6 +562,32 @@ DecodeHeapOp(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) } } +/* + * Ask output plugin whether we want to skip this PREPARE and send + * this transaction as a regular commit later. + */ +static inline bool +FilterPrepare(LogicalDecodingContext *ctx, const char *gid) +{ + /* + * Skip if decoding of two-phase transactions at PREPARE time is not + * enabled. In that case, all two-phase transactions are considered + * filtered out and will be applied as regular transactions at COMMIT + * PREPARED. + */ + if (!ctx->twophase) + return true; + + /* + * The filter_prepare callback is optional. When not supplied, all + * prepared transactions should go through. + */ + if (ctx->callbacks.filter_prepare_cb == NULL) + return false; + + return filter_prepare_cb_wrapper(ctx, gid); +} + static inline bool FilterByOrigin(LogicalDecodingContext *ctx, RepOriginId origin_id) { @@ -582,10 +650,15 @@ DecodeLogicalMsgOp(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) /* * Consolidated commit record handling between the different form of commit * records. + * + * 'two_phase' indicates that caller wants to process the transaction in two + * phases, first process prepare if not already done and then process + * commit_prepared. */ static void DecodeCommit(LogicalDecodingContext *ctx, XLogRecordBuffer *buf, - xl_xact_parsed_commit *parsed, TransactionId xid) + xl_xact_parsed_commit *parsed, TransactionId xid, + bool two_phase) { XLogRecPtr origin_lsn = InvalidXLogRecPtr; TimestampTz commit_time = parsed->xact_time; @@ -606,15 +679,6 @@ DecodeCommit(LogicalDecodingContext *ctx, XLogRecordBuffer *buf, * the reorderbuffer to forget the content of the (sub-)transactions * if not. * - * There can be several reasons we might not be interested in this - * transaction: - * 1) We might not be interested in decoding transactions up to this - * LSN. This can happen because we previously decoded it and now just - * are restarting or if we haven't assembled a consistent snapshot yet. - * 2) The transaction happened in another database. - * 3) The output plugin is not interested in the origin. - * 4) We are doing fast-forwarding - * * We can't just use ReorderBufferAbort() here, because we need to execute * the transaction's invalidations. This currently won't be needed if * we're just skipping over the transaction because currently we only do @@ -627,9 +691,7 @@ DecodeCommit(LogicalDecodingContext *ctx, XLogRecordBuffer *buf, * relevant syscaches. * --- */ - if (SnapBuildXactNeedsSkip(ctx->snapshot_builder, buf->origptr) || - (parsed->dbId != InvalidOid && parsed->dbId != ctx->slot->data.database) || - ctx->fast_forward || FilterByOrigin(ctx, origin_id)) + if (DecodeTXNNeedSkip(ctx, buf, parsed->dbId, origin_id)) { for (i = 0; i < parsed->nsubxacts; i++) { @@ -647,34 +709,163 @@ DecodeCommit(LogicalDecodingContext *ctx, XLogRecordBuffer *buf, buf->origptr, buf->endptr); } + /* + * Send the final commit record if the transaction data is already + * decoded, otherwise, process the entire transaction. + */ + if (two_phase) + { + ReorderBufferFinishPrepared(ctx->reorder, xid, buf->origptr, buf->endptr, + commit_time, origin_id, origin_lsn, + parsed->twophase_gid, true); + } + else + { + ReorderBufferCommit(ctx->reorder, xid, buf->origptr, buf->endptr, + commit_time, origin_id, origin_lsn); + } + + /* + * Update the decoding stats at transaction prepare/commit/abort. It is + * not clear that sending more or less frequently than this would be + * better. + */ + UpdateDecodingStats(ctx); +} + +/* + * Decode PREPARE record. Similar logic as in DecodeCommit. + * + * Note that we don't skip prepare even if have detected concurrent abort + * because it is quite possible that we had already sent some changes before we + * detect abort in which case we need to abort those changes in the subscriber. + * To abort such changes, we do send the prepare and then the rollback prepared + * which is what happened on the publisher-side as well. Now, we can invent a + * new abort API wherein in such cases we send abort and skip sending prepared + * and rollback prepared but then it is not that straightforward because we + * might have streamed this transaction by that time in which case it is + * handled when the rollback is encountered. It is not impossible to optimize + * the concurrent abort case but it can introduce design complexity w.r.t + * handling different cases so leaving it for now as it doesn't seem worth it. + */ +static void +DecodePrepare(LogicalDecodingContext *ctx, XLogRecordBuffer *buf, + xl_xact_parsed_prepare *parsed) +{ + SnapBuild *builder = ctx->snapshot_builder; + XLogRecPtr origin_lsn = parsed->origin_lsn; + TimestampTz prepare_time = parsed->xact_time; + XLogRecPtr origin_id = XLogRecGetOrigin(buf->record); + int i; + TransactionId xid = parsed->twophase_xid; + + if (parsed->origin_timestamp != 0) + prepare_time = parsed->origin_timestamp; + + /* + * Remember the prepare info for a txn so that it can be used later in + * commit prepared if required. See ReorderBufferFinishPrepared. + */ + if (!ReorderBufferRememberPrepareInfo(ctx->reorder, xid, buf->origptr, + buf->endptr, prepare_time, origin_id, + origin_lsn)) + return; + + /* We can't start streaming unless a consistent state is reached. */ + if (SnapBuildCurrentState(builder) < SNAPBUILD_CONSISTENT) + { + ReorderBufferSkipPrepare(ctx->reorder, xid); + return; + } + + /* + * Check whether we need to process this transaction. See + * DecodeTXNNeedSkip for the reasons why we sometimes want to skip the + * transaction. + * + * We can't call ReorderBufferForget as we did in DecodeCommit as the txn + * hasn't yet been committed, removing this txn before a commit might + * result in the computation of an incorrect restart_lsn. See + * SnapBuildProcessRunningXacts. But we need to process cache + * invalidations if there are any for the reasons mentioned in + * DecodeCommit. + */ + if (DecodeTXNNeedSkip(ctx, buf, parsed->dbId, origin_id)) + { + ReorderBufferSkipPrepare(ctx->reorder, xid); + ReorderBufferInvalidate(ctx->reorder, xid, buf->origptr); + return; + } + + /* Tell the reorderbuffer about the surviving subtransactions. */ + for (i = 0; i < parsed->nsubxacts; i++) + { + ReorderBufferCommitChild(ctx->reorder, xid, parsed->subxacts[i], + buf->origptr, buf->endptr); + } + /* replay actions of all transaction + subtransactions in order */ - ReorderBufferCommit(ctx->reorder, xid, buf->origptr, buf->endptr, - commit_time, origin_id, origin_lsn); + ReorderBufferPrepare(ctx->reorder, xid, parsed->twophase_gid); /* - * Update the decoding stats at transaction commit/abort. It is not clear - * that sending more or less frequently than this would be better. + * Update the decoding stats at transaction prepare/commit/abort. It is + * not clear that sending more or less frequently than this would be + * better. */ UpdateDecodingStats(ctx); } + /* * Get the data from the various forms of abort records and pass it on to - * snapbuild.c and reorderbuffer.c + * snapbuild.c and reorderbuffer.c. + * + * 'two_phase' indicates to finish prepared transaction. */ static void DecodeAbort(LogicalDecodingContext *ctx, XLogRecordBuffer *buf, - xl_xact_parsed_abort *parsed, TransactionId xid) + xl_xact_parsed_abort *parsed, TransactionId xid, + bool two_phase) { int i; + XLogRecPtr origin_lsn = InvalidXLogRecPtr; + TimestampTz abort_time = parsed->xact_time; + XLogRecPtr origin_id = XLogRecGetOrigin(buf->record); + bool skip_xact; - for (i = 0; i < parsed->nsubxacts; i++) + if (parsed->xinfo & XACT_XINFO_HAS_ORIGIN) + { + origin_lsn = parsed->origin_lsn; + abort_time = parsed->origin_timestamp; + } + + /* + * Check whether we need to process this transaction. See + * DecodeTXNNeedSkip for the reasons why we sometimes want to skip the + * transaction. + */ + skip_xact = DecodeTXNNeedSkip(ctx, buf, parsed->dbId, origin_id); + + /* + * Send the final rollback record for a prepared transaction unless we + * need to skip it. For non-two-phase xacts, simply forget the xact. + */ + if (two_phase && !skip_xact) { - ReorderBufferAbort(ctx->reorder, parsed->subxacts[i], - buf->record->EndRecPtr); + ReorderBufferFinishPrepared(ctx->reorder, xid, buf->origptr, buf->endptr, + abort_time, origin_id, origin_lsn, + parsed->twophase_gid, false); } + else + { + for (i = 0; i < parsed->nsubxacts; i++) + { + ReorderBufferAbort(ctx->reorder, parsed->subxacts[i], + buf->record->EndRecPtr); + } - ReorderBufferAbort(ctx->reorder, xid, buf->record->EndRecPtr); + ReorderBufferAbort(ctx->reorder, xid, buf->record->EndRecPtr); + } /* update the decoding stats */ UpdateDecodingStats(ctx); @@ -1080,3 +1271,24 @@ DecodeXLogTuple(char *data, Size len, ReorderBufferTupleBuf *tuple) header->t_infomask2 = xlhdr.t_infomask2; header->t_hoff = xlhdr.t_hoff; } + +/* + * Check whether we are interested in this specific transaction. + * + * There can be several reasons we might not be interested in this + * transaction: + * 1) We might not be interested in decoding transactions up to this + * LSN. This can happen because we previously decoded it and now just + * are restarting or if we haven't assembled a consistent snapshot yet. + * 2) The transaction happened in another database. + * 3) The output plugin is not interested in the origin. + * 4) We are doing fast-forwarding + */ +static bool +DecodeTXNNeedSkip(LogicalDecodingContext *ctx, XLogRecordBuffer *buf, + Oid txn_dbid, RepOriginId origin_id) +{ + return (SnapBuildXactNeedsSkip(ctx->snapshot_builder, buf->origptr) || + (txn_dbid != InvalidOid && txn_dbid != ctx->slot->data.database) || + ctx->fast_forward || FilterByOrigin(ctx, origin_id)); +} diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c index e49b511517517..605ec0986caa3 100644 --- a/src/backend/replication/logical/logical.c +++ b/src/backend/replication/logical/logical.c @@ -1083,15 +1083,6 @@ filter_prepare_cb_wrapper(LogicalDecodingContext *ctx, const char *gid) Assert(!ctx->fast_forward); - /* - * Skip if decoding of two-phase transactions at PREPARE time is not - * enabled. In that case, all two-phase transactions are considered - * filtered out and will be applied as regular transactions at COMMIT - * PREPARED. - */ - if (!ctx->twophase) - return true; - /* Push callback + info on the error context stack */ state.ctx = ctx; state.callback_name = "filter_prepare"; diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c index df63b90a67a10..315bfe7cae27f 100644 --- a/src/backend/replication/logical/reorderbuffer.c +++ b/src/backend/replication/logical/reorderbuffer.c @@ -251,7 +251,8 @@ static Size ReorderBufferRestoreChanges(ReorderBuffer *rb, ReorderBufferTXN *txn static void ReorderBufferRestoreChange(ReorderBuffer *rb, ReorderBufferTXN *txn, char *change); static void ReorderBufferRestoreCleanup(ReorderBuffer *rb, ReorderBufferTXN *txn); -static void ReorderBufferTruncateTXN(ReorderBuffer *rb, ReorderBufferTXN *txn); +static void ReorderBufferTruncateTXN(ReorderBuffer *rb, ReorderBufferTXN *txn, + bool txn_prepared); static void ReorderBufferCleanupSerializedTXNs(const char *slotname); static void ReorderBufferSerializedPath(char *path, ReplicationSlot *slot, TransactionId xid, XLogSegNo segno); @@ -422,6 +423,12 @@ ReorderBufferReturnTXN(ReorderBuffer *rb, ReorderBufferTXN *txn) /* free data that's contained */ + if (txn->gid != NULL) + { + pfree(txn->gid); + txn->gid = NULL; + } + if (txn->tuplecid_hash != NULL) { hash_destroy(txn->tuplecid_hash); @@ -1516,12 +1523,18 @@ ReorderBufferCleanupTXN(ReorderBuffer *rb, ReorderBufferTXN *txn) } /* - * Discard changes from a transaction (and subtransactions), after streaming - * them. Keep the remaining info - transactions, tuplecids, invalidations and - * snapshots. + * Discard changes from a transaction (and subtransactions), either after + * streaming or decoding them at PREPARE. Keep the remaining info - + * transactions, tuplecids, invalidations and snapshots. + * + * We additionaly remove tuplecids after decoding the transaction at prepare + * time as we only need to perform invalidation at rollback or commit prepared. + * + * 'txn_prepared' indicates that we have decoded the transaction at prepare + * time. */ static void -ReorderBufferTruncateTXN(ReorderBuffer *rb, ReorderBufferTXN *txn) +ReorderBufferTruncateTXN(ReorderBuffer *rb, ReorderBufferTXN *txn, bool txn_prepared) { dlist_mutable_iter iter; @@ -1540,7 +1553,7 @@ ReorderBufferTruncateTXN(ReorderBuffer *rb, ReorderBufferTXN *txn) Assert(rbtxn_is_known_subxact(subtxn)); Assert(subtxn->nsubtxns == 0); - ReorderBufferTruncateTXN(rb, subtxn); + ReorderBufferTruncateTXN(rb, subtxn, txn_prepared); } /* cleanup changes in the txn */ @@ -1574,9 +1587,33 @@ ReorderBufferTruncateTXN(ReorderBuffer *rb, ReorderBufferTXN *txn) * about the toplevel xact (we send the XID in all messages), but we never * stream XIDs of empty subxacts. */ - if ((!txn->toptxn) || (txn->nentries_mem != 0)) + if ((!txn_prepared) && ((!txn->toptxn) || (txn->nentries_mem != 0))) txn->txn_flags |= RBTXN_IS_STREAMED; + if (txn_prepared) + { + /* + * If this is a prepared txn, cleanup the tuplecids we stored for + * decoding catalog snapshot access. They are always stored in the + * toplevel transaction. + */ + dlist_foreach_modify(iter, &txn->tuplecids) + { + ReorderBufferChange *change; + + change = dlist_container(ReorderBufferChange, node, iter.cur); + + /* Check we're not mixing changes from different transactions. */ + Assert(change->txn == txn); + Assert(change->action == REORDER_BUFFER_CHANGE_INTERNAL_TUPLECID); + + /* Remove the change from its containing list. */ + dlist_delete(&change->node); + + ReorderBufferReturnChange(rb, change, true); + } + } + /* * Destroy the (relfilenode, ctid) hashtable, so that we don't leak any * memory. We could also keep the hash table and update it with new ctid @@ -1756,9 +1793,10 @@ ReorderBufferFreeSnap(ReorderBuffer *rb, Snapshot snap) } /* - * If the transaction was (partially) streamed, we need to commit it in a - * 'streamed' way. That is, we first stream the remaining part of the - * transaction, and then invoke stream_commit message. + * If the transaction was (partially) streamed, we need to prepare or commit + * it in a 'streamed' way. That is, we first stream the remaining part of the + * transaction, and then invoke stream_prepare or stream_commit message as per + * the case. */ static void ReorderBufferStreamCommit(ReorderBuffer *rb, ReorderBufferTXN *txn) @@ -1768,29 +1806,49 @@ ReorderBufferStreamCommit(ReorderBuffer *rb, ReorderBufferTXN *txn) ReorderBufferStreamTXN(rb, txn); - rb->stream_commit(rb, txn, txn->final_lsn); + if (rbtxn_prepared(txn)) + { + /* + * Note, we send stream prepare even if a concurrent abort is + * detected. See DecodePrepare for more information. + */ + rb->stream_prepare(rb, txn, txn->final_lsn); - ReorderBufferCleanupTXN(rb, txn); + /* + * This is a PREPARED transaction, part of a two-phase commit. The + * full cleanup will happen as part of the COMMIT PREPAREDs, so now + * just truncate txn by removing changes and tuple_cids. + */ + ReorderBufferTruncateTXN(rb, txn, true); + /* Reset the CheckXidAlive */ + CheckXidAlive = InvalidTransactionId; + } + else + { + rb->stream_commit(rb, txn, txn->final_lsn); + ReorderBufferCleanupTXN(rb, txn); + } } /* * Set xid to detect concurrent aborts. * - * While streaming an in-progress transaction there is a possibility that the - * (sub)transaction might get aborted concurrently. In such case if the - * (sub)transaction has catalog update then we might decode the tuple using - * wrong catalog version. For example, suppose there is one catalog tuple with - * (xmin: 500, xmax: 0). Now, the transaction 501 updates the catalog tuple - * and after that we will have two tuples (xmin: 500, xmax: 501) and - * (xmin: 501, xmax: 0). Now, if 501 is aborted and some other transaction - * say 502 updates the same catalog tuple then the first tuple will be changed - * to (xmin: 500, xmax: 502). So, the problem is that when we try to decode - * the tuple inserted/updated in 501 after the catalog update, we will see the - * catalog tuple with (xmin: 500, xmax: 502) as visible because it will - * consider that the tuple is deleted by xid 502 which is not visible to our - * snapshot. And when we will try to decode with that catalog tuple, it can - * lead to a wrong result or a crash. So, it is necessary to detect - * concurrent aborts to allow streaming of in-progress transactions. + * While streaming an in-progress transaction or decoding a prepared + * transaction there is a possibility that the (sub)transaction might get + * aborted concurrently. In such case if the (sub)transaction has catalog + * update then we might decode the tuple using wrong catalog version. For + * example, suppose there is one catalog tuple with (xmin: 500, xmax: 0). Now, + * the transaction 501 updates the catalog tuple and after that we will have + * two tuples (xmin: 500, xmax: 501) and (xmin: 501, xmax: 0). Now, if 501 is + * aborted and some other transaction say 502 updates the same catalog tuple + * then the first tuple will be changed to (xmin: 500, xmax: 502). So, the + * problem is that when we try to decode the tuple inserted/updated in 501 + * after the catalog update, we will see the catalog tuple with (xmin: 500, + * xmax: 502) as visible because it will consider that the tuple is deleted by + * xid 502 which is not visible to our snapshot. And when we will try to + * decode with that catalog tuple, it can lead to a wrong result or a crash. + * So, it is necessary to detect concurrent aborts to allow streaming of + * in-progress transactions or decoding of prepared transactions. * * For detecting the concurrent abort we set CheckXidAlive to the current * (sub)transaction's xid for which this change belongs to. And, during @@ -1799,7 +1857,10 @@ ReorderBufferStreamCommit(ReorderBuffer *rb, ReorderBufferTXN *txn) * and discard the already streamed changes on such an error. We might have * already streamed some of the changes for the aborted (sub)transaction, but * that is fine because when we decode the abort we will stream abort message - * to truncate the changes in the subscriber. + * to truncate the changes in the subscriber. Similarly, for prepared + * transactions, we stop decoding if concurrent abort is detected and then + * rollback the changes when rollback prepared is encountered. See + * DecodePreare. */ static inline void SetupCheckXidLive(TransactionId xid) @@ -1901,7 +1962,7 @@ ReorderBufferResetTXN(ReorderBuffer *rb, ReorderBufferTXN *txn, ReorderBufferChange *specinsert) { /* Discard the changes that we just streamed */ - ReorderBufferTruncateTXN(rb, txn); + ReorderBufferTruncateTXN(rb, txn, rbtxn_prepared(txn)); /* Free all resources allocated for toast reconstruction */ ReorderBufferToastReset(rb, txn); @@ -1913,15 +1974,19 @@ ReorderBufferResetTXN(ReorderBuffer *rb, ReorderBufferTXN *txn, specinsert = NULL; } - /* Stop the stream. */ - rb->stream_stop(rb, txn, last_lsn); - - /* Remember the command ID and snapshot for the streaming run */ - ReorderBufferSaveTXNSnapshot(rb, txn, snapshot_now, command_id); + /* + * For the streaming case, stop the stream and remember the command ID and + * snapshot for the streaming run. + */ + if (rbtxn_is_streamed(txn)) + { + rb->stream_stop(rb, txn, last_lsn); + ReorderBufferSaveTXNSnapshot(rb, txn, snapshot_now, command_id); + } } /* - * Helper function for ReorderBufferCommit and ReorderBufferStreamTXN. + * Helper function for ReorderBufferReplay and ReorderBufferStreamTXN. * * Send data of a transaction (and its subtransactions) to the * output plugin. We iterate over the top and subtransactions (using a k-way @@ -1974,9 +2039,17 @@ ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn, else StartTransactionCommand(); - /* We only need to send begin/commit for non-streamed transactions. */ + /* + * We only need to send begin/begin-prepare for non-streamed + * transactions. + */ if (!streaming) - rb->begin(rb, txn); + { + if (rbtxn_prepared(txn)) + rb->begin_prepare(rb, txn); + else + rb->begin(rb, txn); + } ReorderBufferIterTXNInit(rb, txn, &iterstate); while ((change = ReorderBufferIterTXNNext(rb, iterstate)) != NULL) @@ -2007,8 +2080,12 @@ ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn, prev_lsn = change->lsn; - /* Set the current xid to detect concurrent aborts. */ - if (streaming) + /* + * Set the current xid to detect concurrent aborts. This is + * required for the cases when we decode the changes before the + * COMMIT record is processed. + */ + if (streaming || rbtxn_prepared(change->txn)) { curtxn = change->txn; SetupCheckXidLive(curtxn->xid); @@ -2299,7 +2376,16 @@ ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn, } } else - rb->commit(rb, txn, commit_lsn); + { + /* + * Call either PREPARE (for two-phase transactions) or COMMIT (for + * regular ones). + */ + if (rbtxn_prepared(txn)) + rb->prepare(rb, txn, commit_lsn); + else + rb->commit(rb, txn, commit_lsn); + } /* this is just a sanity check against bad output plugin behaviour */ if (GetCurrentTransactionIdIfAny() != InvalidTransactionId) @@ -2333,15 +2419,22 @@ ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn, RollbackAndReleaseCurrentSubTransaction(); /* - * If we are streaming the in-progress transaction then discard the - * changes that we just streamed, and mark the transactions as - * streamed (if they contained changes). Otherwise, remove all the - * changes and deallocate the ReorderBufferTXN. + * We are here due to one of the four reasons: 1. Decoding an + * in-progress txn. 2. Decoding a prepared txn. 3. Decoding of a + * prepared txn that was (partially) streamed. 4. Decoding a committed + * txn. + * + * For 1, we allow truncation of txn data by removing the changes + * already streamed but still keeping other things like invalidations, + * snapshot, and tuplecids. For 2 and 3, we indicate + * ReorderBufferTruncateTXN to do more elaborate truncation of txn + * data as the entire transaction has been decoded except for commit. + * For 4, as the entire txn has been decoded, we can fully clean up + * the TXN reorder buffer. */ - if (streaming) + if (streaming || rbtxn_prepared(txn)) { - ReorderBufferTruncateTXN(rb, txn); - + ReorderBufferTruncateTXN(rb, txn, rbtxn_prepared(txn)); /* Reset the CheckXidAlive */ CheckXidAlive = InvalidTransactionId; } @@ -2374,17 +2467,20 @@ ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn, /* * The error code ERRCODE_TRANSACTION_ROLLBACK indicates a concurrent - * abort of the (sub)transaction we are streaming. We need to do the - * cleanup and return gracefully on this error, see SetupCheckXidLive. + * abort of the (sub)transaction we are streaming or preparing. We + * need to do the cleanup and return gracefully on this error, see + * SetupCheckXidLive. */ if (errdata->sqlerrcode == ERRCODE_TRANSACTION_ROLLBACK) { /* - * This error can only occur when we are sending the data in - * streaming mode and the streaming is not finished yet. + * This error can occur either when we are sending the data in + * streaming mode and the streaming is not finished yet or when we + * are sending the data out on a PREPARE during a two-phase + * commit. */ - Assert(streaming); - Assert(stream_started); + Assert(streaming || rbtxn_prepared(txn)); + Assert(stream_started || rbtxn_prepared(txn)); /* Cleanup the temporary error state. */ FlushErrorState(); @@ -2414,26 +2510,19 @@ ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn, * ReorderBufferCommitChild(), even if previously assigned to the toplevel * transaction with ReorderBufferAssignChild. * - * This interface is called once a toplevel commit is read for both streamed - * as well as non-streamed transactions. + * This interface is called once a prepare or toplevel commit is read for both + * streamed as well as non-streamed transactions. */ -void -ReorderBufferCommit(ReorderBuffer *rb, TransactionId xid, +static void +ReorderBufferReplay(ReorderBufferTXN *txn, + ReorderBuffer *rb, TransactionId xid, XLogRecPtr commit_lsn, XLogRecPtr end_lsn, TimestampTz commit_time, RepOriginId origin_id, XLogRecPtr origin_lsn) { - ReorderBufferTXN *txn; Snapshot snapshot_now; CommandId command_id = FirstCommandId; - txn = ReorderBufferTXNByXid(rb, xid, false, NULL, InvalidXLogRecPtr, - false); - - /* unknown transaction, nothing to replay */ - if (txn == NULL) - return; - txn->final_lsn = commit_lsn; txn->end_lsn = end_lsn; txn->commit_time = commit_time; @@ -2463,7 +2552,13 @@ ReorderBufferCommit(ReorderBuffer *rb, TransactionId xid, if (txn->base_snapshot == NULL) { Assert(txn->ninvalidations == 0); - ReorderBufferCleanupTXN(rb, txn); + + /* + * Removing this txn before a commit might result in the computation + * of an incorrect restart_lsn. See SnapBuildProcessRunningXacts. + */ + if (!rbtxn_prepared(txn)) + ReorderBufferCleanupTXN(rb, txn); return; } @@ -2474,6 +2569,178 @@ ReorderBufferCommit(ReorderBuffer *rb, TransactionId xid, command_id, false); } +/* + * Commit a transaction. + * + * See comments for ReorderBufferReplay(). + */ +void +ReorderBufferCommit(ReorderBuffer *rb, TransactionId xid, + XLogRecPtr commit_lsn, XLogRecPtr end_lsn, + TimestampTz commit_time, + RepOriginId origin_id, XLogRecPtr origin_lsn) +{ + ReorderBufferTXN *txn; + + txn = ReorderBufferTXNByXid(rb, xid, false, NULL, InvalidXLogRecPtr, + false); + + /* unknown transaction, nothing to replay */ + if (txn == NULL) + return; + + ReorderBufferReplay(txn, rb, xid, commit_lsn, end_lsn, commit_time, + origin_id, origin_lsn); +} + +/* + * Record the prepare information for a transaction. + */ +bool +ReorderBufferRememberPrepareInfo(ReorderBuffer *rb, TransactionId xid, + XLogRecPtr prepare_lsn, XLogRecPtr end_lsn, + TimestampTz prepare_time, + RepOriginId origin_id, XLogRecPtr origin_lsn) +{ + ReorderBufferTXN *txn; + + txn = ReorderBufferTXNByXid(rb, xid, false, NULL, InvalidXLogRecPtr, false); + + /* unknown transaction, nothing to do */ + if (txn == NULL) + return false; + + /* + * Remember the prepare information to be later used by commit prepared in + * case we skip doing prepare. + */ + txn->final_lsn = prepare_lsn; + txn->end_lsn = end_lsn; + txn->commit_time = prepare_time; + txn->origin_id = origin_id; + txn->origin_lsn = origin_lsn; + + return true; +} + +/* Remember that we have skipped prepare */ +void +ReorderBufferSkipPrepare(ReorderBuffer *rb, TransactionId xid) +{ + ReorderBufferTXN *txn; + + txn = ReorderBufferTXNByXid(rb, xid, false, NULL, InvalidXLogRecPtr, false); + + /* unknown transaction, nothing to do */ + if (txn == NULL) + return; + + txn->txn_flags |= RBTXN_SKIPPED_PREPARE; +} + +/* + * Prepare a two-phase transaction. + * + * See comments for ReorderBufferReplay(). + */ +void +ReorderBufferPrepare(ReorderBuffer *rb, TransactionId xid, + char *gid) +{ + ReorderBufferTXN *txn; + + txn = ReorderBufferTXNByXid(rb, xid, false, NULL, InvalidXLogRecPtr, + false); + + /* unknown transaction, nothing to replay */ + if (txn == NULL) + return; + + txn->txn_flags |= RBTXN_PREPARE; + txn->gid = pstrdup(gid); + + /* The prepare info must have been updated in txn by now. */ + Assert(txn->final_lsn != InvalidXLogRecPtr); + + ReorderBufferReplay(txn, rb, xid, txn->final_lsn, txn->end_lsn, + txn->commit_time, txn->origin_id, txn->origin_lsn); +} + +/* + * This is used to handle COMMIT/ROLLBACK PREPARED. + */ +void +ReorderBufferFinishPrepared(ReorderBuffer *rb, TransactionId xid, + XLogRecPtr commit_lsn, XLogRecPtr end_lsn, + TimestampTz commit_time, RepOriginId origin_id, + XLogRecPtr origin_lsn, char *gid, bool is_commit) +{ + ReorderBufferTXN *txn; + XLogRecPtr prepare_end_lsn; + TimestampTz prepare_time; + + txn = ReorderBufferTXNByXid(rb, xid, true, NULL, commit_lsn, false); + + /* unknown transaction, nothing to do */ + if (txn == NULL) + return; + + /* + * By this time the txn has the prepare record information, remember it to + * be later used for rollback. + */ + prepare_end_lsn = txn->end_lsn; + prepare_time = txn->commit_time; + + /* add the gid in the txn */ + txn->gid = pstrdup(gid); + + /* + * It is possible that this transaction is not decoded at prepare time + * either because by that time we didn't have a consistent snapshot or it + * was decoded earlier but we have restarted. We can't distinguish between + * those two cases so we send the prepare in both the cases and let + * downstream decide whether to process or skip it. We don't need to + * decode the xact for aborts if it is not done already. + */ + if (!rbtxn_prepared(txn) && is_commit) + { + txn->txn_flags |= RBTXN_PREPARE; + + /* + * The prepare info must have been updated in txn even if we skip + * prepare. + */ + Assert(txn->final_lsn != InvalidXLogRecPtr); + + /* + * By this time the txn has the prepare record information and it is + * important to use that so that downstream gets the accurate + * information. If instead, we have passed commit information here + * then downstream can behave as it has already replayed commit + * prepared after the restart. + */ + ReorderBufferReplay(txn, rb, xid, txn->final_lsn, txn->end_lsn, + txn->commit_time, txn->origin_id, txn->origin_lsn); + } + + txn->final_lsn = commit_lsn; + txn->end_lsn = end_lsn; + txn->commit_time = commit_time; + txn->origin_id = origin_id; + txn->origin_lsn = origin_lsn; + + if (is_commit) + rb->commit_prepared(rb, txn, commit_lsn); + else + rb->rollback_prepared(rb, txn, prepare_end_lsn, prepare_time); + + /* cleanup: make sure there's no cache pollution */ + ReorderBufferExecuteInvalidations(txn->ninvalidations, + txn->invalidations); + ReorderBufferCleanupTXN(rb, txn); +} + /* * Abort a transaction that possibly has previous changes. Needs to be first * called for subtransactions and then for the toplevel xid. @@ -2605,6 +2872,39 @@ ReorderBufferForget(ReorderBuffer *rb, TransactionId xid, XLogRecPtr lsn) ReorderBufferCleanupTXN(rb, txn); } +/* + * Invalidate cache for those transactions that need to be skipped just in case + * catalogs were manipulated as part of the transaction. + * + * Note that this is a special-purpose function for prepared transactions where + * we don't want to clean up the TXN even when we decide to skip it. See + * DecodePrepare. + */ +void +ReorderBufferInvalidate(ReorderBuffer *rb, TransactionId xid, XLogRecPtr lsn) +{ + ReorderBufferTXN *txn; + + txn = ReorderBufferTXNByXid(rb, xid, false, NULL, InvalidXLogRecPtr, + false); + + /* unknown, nothing to do */ + if (txn == NULL) + return; + + /* + * Process cache invalidation messages if there are any. Even if we're not + * interested in the transaction's contents, it could have manipulated the + * catalog and we need to update the caches according to that. + */ + if (txn->base_snapshot != NULL && txn->ninvalidations > 0) + ReorderBufferImmediateInvalidation(rb, txn->ninvalidations, + txn->invalidations); + else + Assert(txn->ninvalidations == 0); +} + + /* * Execute invalidations happening outside the context of a decoded * transaction. That currently happens either for xid-less commits diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c index 6afc25e8d3d82..15b07a54c1172 100644 --- a/src/backend/replication/logical/snapbuild.c +++ b/src/backend/replication/logical/snapbuild.c @@ -834,6 +834,13 @@ SnapBuildDistributeNewCatalogSnapshot(SnapBuild *builder, XLogRecPtr lsn) if (!ReorderBufferXidHasBaseSnapshot(builder->reorder, txn->xid)) continue; + /* + * We don't need to add snapshot to prepared transactions as they + * should not see the new catalog contents. + */ + if (rbtxn_prepared(txn) || rbtxn_skip_prepared(txn)) + continue; + elog(DEBUG2, "adding a new snapshot to %u at %X/%X", txn->xid, (uint32) (lsn >> 32), (uint32) lsn); diff --git a/src/include/replication/reorderbuffer.h b/src/include/replication/reorderbuffer.h index 9f982137d9373..bab31bf7af71d 100644 --- a/src/include/replication/reorderbuffer.h +++ b/src/include/replication/reorderbuffer.h @@ -174,6 +174,8 @@ typedef struct ReorderBufferChange #define RBTXN_IS_STREAMED 0x0010 #define RBTXN_HAS_TOAST_INSERT 0x0020 #define RBTXN_HAS_SPEC_INSERT 0x0040 +#define RBTXN_PREPARE 0x0080 +#define RBTXN_SKIPPED_PREPARE 0x0100 /* Does the transaction have catalog changes? */ #define rbtxn_has_catalog_changes(txn) \ @@ -233,6 +235,18 @@ typedef struct ReorderBufferChange ((txn)->txn_flags & RBTXN_IS_STREAMED) != 0 \ ) +/* Has this transaction been prepared? */ +#define rbtxn_prepared(txn) \ +( \ + ((txn)->txn_flags & RBTXN_PREPARE) != 0 \ +) + +/* prepare for this transaction skipped? */ +#define rbtxn_skip_prepared(txn) \ +( \ + ((txn)->txn_flags & RBTXN_SKIPPED_PREPARE) != 0 \ +) + typedef struct ReorderBufferTXN { /* See above */ @@ -258,10 +272,11 @@ typedef struct ReorderBufferTXN XLogRecPtr first_lsn; /* ---- - * LSN of the record that lead to this xact to be committed or + * LSN of the record that lead to this xact to be prepared or committed or * aborted. This can be a * * plain commit record * * plain commit record, of a parent transaction + * * prepared tansaction * * prepared transaction commit * * plain abort record * * prepared transaction abort @@ -293,7 +308,8 @@ typedef struct ReorderBufferTXN XLogRecPtr origin_lsn; /* - * Commit time, only known when we read the actual commit record. + * Commit or Prepare time, only known when we read the actual commit or + * prepare record. */ TimestampTz commit_time; @@ -625,12 +641,18 @@ void ReorderBufferQueueMessage(ReorderBuffer *, TransactionId, Snapshot snapsho void ReorderBufferCommit(ReorderBuffer *, TransactionId, XLogRecPtr commit_lsn, XLogRecPtr end_lsn, TimestampTz commit_time, RepOriginId origin_id, XLogRecPtr origin_lsn); +void ReorderBufferFinishPrepared(ReorderBuffer *rb, TransactionId xid, + XLogRecPtr commit_lsn, XLogRecPtr end_lsn, + TimestampTz commit_time, + RepOriginId origin_id, XLogRecPtr origin_lsn, + char *gid, bool is_commit); void ReorderBufferAssignChild(ReorderBuffer *, TransactionId, TransactionId, XLogRecPtr commit_lsn); void ReorderBufferCommitChild(ReorderBuffer *, TransactionId, TransactionId, XLogRecPtr commit_lsn, XLogRecPtr end_lsn); void ReorderBufferAbort(ReorderBuffer *, TransactionId, XLogRecPtr lsn); void ReorderBufferAbortOld(ReorderBuffer *, TransactionId xid); void ReorderBufferForget(ReorderBuffer *, TransactionId, XLogRecPtr lsn); +void ReorderBufferInvalidate(ReorderBuffer *, TransactionId, XLogRecPtr lsn); void ReorderBufferSetBaseSnapshot(ReorderBuffer *, TransactionId, XLogRecPtr lsn, struct SnapshotData *snap); void ReorderBufferAddSnapshot(ReorderBuffer *, TransactionId, XLogRecPtr lsn, struct SnapshotData *snap); @@ -644,10 +666,17 @@ void ReorderBufferAddInvalidations(ReorderBuffer *, TransactionId, XLogRecPtr l void ReorderBufferImmediateInvalidation(ReorderBuffer *, uint32 ninvalidations, SharedInvalidationMessage *invalidations); void ReorderBufferProcessXid(ReorderBuffer *, TransactionId xid, XLogRecPtr lsn); + void ReorderBufferXidSetCatalogChanges(ReorderBuffer *, TransactionId xid, XLogRecPtr lsn); bool ReorderBufferXidHasCatalogChanges(ReorderBuffer *, TransactionId xid); bool ReorderBufferXidHasBaseSnapshot(ReorderBuffer *, TransactionId xid); +bool ReorderBufferRememberPrepareInfo(ReorderBuffer *rb, TransactionId xid, + XLogRecPtr prepare_lsn, XLogRecPtr end_lsn, + TimestampTz prepare_time, + RepOriginId origin_id, XLogRecPtr origin_lsn); +void ReorderBufferSkipPrepare(ReorderBuffer *rb, TransactionId xid); +void ReorderBufferPrepare(ReorderBuffer *rb, TransactionId xid, char *gid); ReorderBufferTXN *ReorderBufferGetOldestTXN(ReorderBuffer *); TransactionId ReorderBufferGetOldestXmin(ReorderBuffer *rb); From b49154b3b7a45523ce4081fdae8d65049342fcec Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Mon, 4 Jan 2021 19:47:58 +0900 Subject: [PATCH 023/240] Simplify some comments in xml.c Author: Justin Pryzby Discussion: https://postgr.es/m/X/Ff7jfnvJUab013@paquier.xyz --- src/backend/utils/adt/xml.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index ca38f961078c4..7350940b66dcd 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -4534,13 +4534,7 @@ XmlTableFetchRow(TableFuncScanState *state) xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableFetchRow"); - /* - * XmlTable returns table - set of composite values. The error context, is - * used for producement more values, between two calls, there can be - * created and used another libxml2 error context. It is libxml2 global - * value, so it should be refreshed any time before any libxml2 usage, - * that is finished by returning some value. - */ + /* Propagate our own error context to libxml2 */ xmlSetStructuredErrorFunc((void *) xtCxt->xmlerrcxt, xml_errorHandler); if (xtCxt->xpathobj == NULL) @@ -4594,7 +4588,7 @@ XmlTableGetValue(TableFuncScanState *state, int colnum, xtCxt->xpathobj->type == XPATH_NODESET && xtCxt->xpathobj->nodesetval != NULL); - /* Propagate context related error context to libxml2 */ + /* Propagate our own error context to libxml2 */ xmlSetStructuredErrorFunc((void *) xtCxt->xmlerrcxt, xml_errorHandler); *isnull = false; @@ -4737,7 +4731,7 @@ XmlTableDestroyOpaque(TableFuncScanState *state) xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableDestroyOpaque"); - /* Propagate context related error context to libxml2 */ + /* Propagate our own error context to libxml2 */ xmlSetStructuredErrorFunc((void *) xtCxt->xmlerrcxt, xml_errorHandler); if (xtCxt->xpathscomp != NULL) From 844fe9f159a948377907a63d0ef3fb16dc51ce50 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 4 Jan 2021 11:03:22 -0500 Subject: [PATCH 024/240] Add the ability for the core grammar to have more than one parse target. This patch essentially allows gram.y to implement a family of related syntax trees, rather than necessarily always parsing a list of SQL statements. raw_parser() gains a new argument, enum RawParseMode, to say what to do. As proof of concept, add a mode that just parses a TypeName without any other decoration, and use that to greatly simplify typeStringToTypeName(). In addition, invent a new SPI entry point SPI_prepare_extended() to allow SPI users (particularly plpgsql) to get at this new functionality. In hopes of making this the last variant of SPI_prepare(), set up its additional arguments as a struct rather than direct arguments, and promise that future additions to the struct can default to zero. SPI_prepare_cursor() and SPI_prepare_params() can perhaps go away at some point. Discussion: https://postgr.es/m/4165684.1607707277@sss.pgh.pa.us --- doc/src/sgml/spi.sgml | 126 +++++++++++++++++++++++++++ src/backend/commands/tablecmds.c | 2 +- src/backend/executor/spi.c | 52 ++++++++++- src/backend/parser/gram.y | 22 ++++- src/backend/parser/parse_coerce.c | 5 +- src/backend/parser/parse_type.c | 64 ++------------ src/backend/parser/parser.c | 27 ++++-- src/backend/tcop/postgres.c | 2 +- src/include/executor/spi.h | 13 ++- src/include/executor/spi_priv.h | 1 + src/include/parser/parser.h | 20 ++++- src/interfaces/ecpg/preproc/parse.pl | 2 +- src/pl/plpgsql/src/pl_exec.c | 13 +-- src/pl/plpgsql/src/pl_gram.y | 2 +- 14 files changed, 268 insertions(+), 83 deletions(-) diff --git a/doc/src/sgml/spi.sgml b/doc/src/sgml/spi.sgml index 6e92e15ca3b3f..f5e0a35da0645 100644 --- a/doc/src/sgml/spi.sgml +++ b/doc/src/sgml/spi.sgml @@ -1105,6 +1105,11 @@ SPIPlanPtr SPI_prepare_cursor(const char * command, int < for the options field of DeclareCursorStmt. SPI_prepare always takes the cursor options as zero. + + + This function is now deprecated in favor + of SPI_prepare_extended. + @@ -1176,6 +1181,122 @@ SPIPlanPtr SPI_prepare_cursor(const char * command, int < + + SPI_prepare_extended + + + SPI_prepare_extended + 3 + + + + SPI_prepare_extended + prepare a statement, without executing it yet + + + + +SPIPlanPtr SPI_prepare_extended(const char * command, + const SPIPrepareOptions * options) + + + + + Description + + + SPI_prepare_extended creates and returns a prepared + statement for the specified command, but doesn't execute the command. + This function is equivalent to SPI_prepare, + with the addition that the caller can specify options to control + the parsing of external parameter references, as well as other facets + of query parsing and planning. + + + + + Arguments + + + + const char * command + + + command string + + + + + + const SPIPrepareOptions * options + + + struct containing optional arguments + + + + + + + Callers should always zero out the entire options + struct, then fill whichever fields they want to set. This ensures forward + compatibility of code, since any fields that are added to the struct in + future will be defined to behave backwards-compatibly if they are zero. + The currently available options fields are: + + + + + ParserSetupHook parserSetup + + + Parser hook setup function + + + + + + void * parserSetupArg + + + pass-through argument for parserSetup + + + + + + RawParseMode parseMode + + + mode for raw parsing; RAW_PARSE_DEFAULT (zero) + produces default behavior + + + + + + int cursorOptions + + + integer bit mask of cursor options; zero produces default behavior + + + + + + + + Return Value + + + SPI_prepare_extended has the same return conventions as + SPI_prepare. + + + + + + SPI_prepare_params @@ -1208,6 +1329,11 @@ SPIPlanPtr SPI_prepare_params(const char * command, with the addition that the caller can specify parser hook functions to control the parsing of external parameter references. + + + This function is now deprecated in favor + of SPI_prepare_extended. + diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 11dae782fd2f5..993da56d437c9 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -12095,7 +12095,7 @@ ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd, * parse_analyze() or the rewriter, but instead we need to pass them * through parse_utilcmd.c to make them ready for execution. */ - raw_parsetree_list = raw_parser(cmd); + raw_parsetree_list = raw_parser(cmd, RAW_PARSE_DEFAULT); querytree_list = NIL; foreach(list_item, raw_parsetree_list) { diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 8368ead1ef6c1..6c0593686a957 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -508,6 +508,7 @@ SPI_execute(const char *src, bool read_only, long tcount) memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = RAW_PARSE_DEFAULT; plan.cursor_options = CURSOR_OPT_PARALLEL_OK; _SPI_prepare_oneshot_plan(src, &plan); @@ -681,6 +682,7 @@ SPI_execute_with_args(const char *src, memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = RAW_PARSE_DEFAULT; plan.cursor_options = CURSOR_OPT_PARALLEL_OK; plan.nargs = nargs; plan.argtypes = argtypes; @@ -726,6 +728,7 @@ SPI_execute_with_receiver(const char *src, memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = RAW_PARSE_DEFAULT; plan.cursor_options = CURSOR_OPT_PARALLEL_OK; if (params) { @@ -768,6 +771,7 @@ SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes, memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = RAW_PARSE_DEFAULT; plan.cursor_options = cursorOptions; plan.nargs = nargs; plan.argtypes = argtypes; @@ -784,6 +788,42 @@ SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes, return result; } +SPIPlanPtr +SPI_prepare_extended(const char *src, + const SPIPrepareOptions *options) +{ + _SPI_plan plan; + SPIPlanPtr result; + + if (src == NULL || options == NULL) + { + SPI_result = SPI_ERROR_ARGUMENT; + return NULL; + } + + SPI_result = _SPI_begin_call(true); + if (SPI_result < 0) + return NULL; + + memset(&plan, 0, sizeof(_SPI_plan)); + plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = options->parseMode; + plan.cursor_options = options->cursorOptions; + plan.nargs = 0; + plan.argtypes = NULL; + plan.parserSetup = options->parserSetup; + plan.parserSetupArg = options->parserSetupArg; + + _SPI_prepare_plan(src, &plan); + + /* copy plan to procedure context */ + result = _SPI_make_plan_non_temp(&plan); + + _SPI_end_call(true); + + return result; +} + SPIPlanPtr SPI_prepare_params(const char *src, ParserSetupHook parserSetup, @@ -805,6 +845,7 @@ SPI_prepare_params(const char *src, memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = RAW_PARSE_DEFAULT; plan.cursor_options = cursorOptions; plan.nargs = 0; plan.argtypes = NULL; @@ -1340,6 +1381,7 @@ SPI_cursor_open_with_args(const char *name, memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = RAW_PARSE_DEFAULT; plan.cursor_options = cursorOptions; plan.nargs = nargs; plan.argtypes = argtypes; @@ -1400,6 +1442,7 @@ SPI_cursor_parse_open_with_paramlist(const char *name, memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = RAW_PARSE_DEFAULT; plan.cursor_options = cursorOptions; if (params) { @@ -2036,7 +2079,8 @@ spi_printtup(TupleTableSlot *slot, DestReceiver *self) * Parse and analyze a querystring. * * At entry, plan->argtypes and plan->nargs (or alternatively plan->parserSetup - * and plan->parserSetupArg) must be valid, as must plan->cursor_options. + * and plan->parserSetupArg) must be valid, as must plan->parse_mode and + * plan->cursor_options. * * Results are stored into *plan (specifically, plan->plancache_list). * Note that the result data is all in CurrentMemoryContext or child contexts @@ -2063,7 +2107,7 @@ _SPI_prepare_plan(const char *src, SPIPlanPtr plan) /* * Parse the request string into a list of raw parse trees. */ - raw_parsetree_list = pg_parse_query(src); + raw_parsetree_list = raw_parser(src, plan->parse_mode); /* * Do parse analysis and rule rewrite for each raw parsetree, storing the @@ -2168,7 +2212,7 @@ _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan) /* * Parse the request string into a list of raw parse trees. */ - raw_parsetree_list = pg_parse_query(src); + raw_parsetree_list = raw_parser(src, plan->parse_mode); /* * Construct plancache entries, but don't do parse analysis yet. @@ -2866,6 +2910,7 @@ _SPI_make_plan_non_temp(SPIPlanPtr plan) newplan = (SPIPlanPtr) palloc0(sizeof(_SPI_plan)); newplan->magic = _SPI_PLAN_MAGIC; newplan->plancxt = plancxt; + newplan->parse_mode = plan->parse_mode; newplan->cursor_options = plan->cursor_options; newplan->nargs = plan->nargs; if (plan->nargs > 0) @@ -2930,6 +2975,7 @@ _SPI_save_plan(SPIPlanPtr plan) newplan = (SPIPlanPtr) palloc0(sizeof(_SPI_plan)); newplan->magic = _SPI_PLAN_MAGIC; newplan->plancxt = plancxt; + newplan->parse_mode = plan->parse_mode; newplan->cursor_options = plan->cursor_options; newplan->nargs = plan->nargs; if (plan->nargs > 0) diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 18e181d5005df..fb025f08a4eb4 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -384,7 +384,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type vacuum_relation %type opt_select_limit select_limit limit_clause -%type stmtblock stmtmulti +%type parse_toplevel stmtmulti OptTableElementList TableElementList OptInherit definition OptTypedTableElementList TypedTableElementList reloptions opt_reloptions @@ -723,6 +723,15 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); */ %token NOT_LA NULLS_LA WITH_LA +/* + * The grammar likewise thinks these tokens are keywords, but they are never + * generated by the scanner. Rather, they can be injected by parser.c as + * the initial token of the string (using the lookahead-token mechanism + * implemented there). This provides a way to tell the grammar to parse + * something other than the usual list of SQL commands. + */ +%token MODE_TYPE_NAME + /* Precedence: lowest to highest */ %nonassoc SET /* see relation_expr_opt_alias */ @@ -787,11 +796,20 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); /* * The target production for the whole parse. + * + * Ordinarily we parse a list of statements, but if we see one of the + * special MODE_XXX symbols as first token, we parse something else. + * The options here correspond to enum RawParseMode, which see for details. */ -stmtblock: stmtmulti +parse_toplevel: + stmtmulti { pg_yyget_extra(yyscanner)->parsetree = $1; } + | MODE_TYPE_NAME Typename + { + pg_yyget_extra(yyscanner)->parsetree = list_make1($2); + } ; /* diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 8d01fca6d2178..74eb39c0e4d8d 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -1541,7 +1541,7 @@ select_common_typmod(ParseState *pstate, List *exprs, Oid common_type) foreach(lc, exprs) { - Node *expr = (Node *) lfirst(lc); + Node *expr = (Node *) lfirst(lc); /* Types must match */ if (exprType(expr) != common_type) @@ -2380,7 +2380,8 @@ enforce_generic_type_consistency(const Oid *actual_arg_types, if (!OidIsValid(elem_typeid)) { /* - * if we don't have an element type yet, use the one we just got + * if we don't have an element type yet, use the one we just + * got */ elem_typeid = range_typelem; } diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c index 717125ad87388..abe131ebebfc2 100644 --- a/src/backend/parser/parse_type.c +++ b/src/backend/parser/parse_type.c @@ -719,13 +719,6 @@ pts_error_callback(void *arg) const char *str = (const char *) arg; errcontext("invalid type name \"%s\"", str); - - /* - * Currently we just suppress any syntax error position report, rather - * than transforming to an "internal query" error. It's unlikely that a - * type name is complex enough to need positioning. - */ - errposition(0); } /* @@ -737,11 +730,7 @@ pts_error_callback(void *arg) TypeName * typeStringToTypeName(const char *str) { - StringInfoData buf; List *raw_parsetree_list; - SelectStmt *stmt; - ResTarget *restarget; - TypeCast *typecast; TypeName *typeName; ErrorContextCallback ptserrcontext; @@ -749,9 +738,6 @@ typeStringToTypeName(const char *str) if (strspn(str, " \t\n\r\f") == strlen(str)) goto fail; - initStringInfo(&buf); - appendStringInfo(&buf, "SELECT NULL::%s", str); - /* * Setup error traceback support in case of ereport() during parse */ @@ -760,58 +746,18 @@ typeStringToTypeName(const char *str) ptserrcontext.previous = error_context_stack; error_context_stack = &ptserrcontext; - raw_parsetree_list = raw_parser(buf.data); + raw_parsetree_list = raw_parser(str, RAW_PARSE_TYPE_NAME); error_context_stack = ptserrcontext.previous; - /* - * Make sure we got back exactly what we expected and no more; paranoia is - * justified since the string might contain anything. - */ - if (list_length(raw_parsetree_list) != 1) - goto fail; - stmt = (SelectStmt *) linitial_node(RawStmt, raw_parsetree_list)->stmt; - if (stmt == NULL || - !IsA(stmt, SelectStmt) || - stmt->distinctClause != NIL || - stmt->intoClause != NULL || - stmt->fromClause != NIL || - stmt->whereClause != NULL || - stmt->groupClause != NIL || - stmt->havingClause != NULL || - stmt->windowClause != NIL || - stmt->valuesLists != NIL || - stmt->sortClause != NIL || - stmt->limitOffset != NULL || - stmt->limitCount != NULL || - stmt->lockingClause != NIL || - stmt->withClause != NULL || - stmt->op != SETOP_NONE) - goto fail; - if (list_length(stmt->targetList) != 1) - goto fail; - restarget = (ResTarget *) linitial(stmt->targetList); - if (restarget == NULL || - !IsA(restarget, ResTarget) || - restarget->name != NULL || - restarget->indirection != NIL) - goto fail; - typecast = (TypeCast *) restarget->val; - if (typecast == NULL || - !IsA(typecast, TypeCast) || - typecast->arg == NULL || - !IsA(typecast->arg, A_Const)) - goto fail; + /* We should get back exactly one TypeName node. */ + Assert(list_length(raw_parsetree_list) == 1); + typeName = linitial_node(TypeName, raw_parsetree_list); - typeName = typecast->typeName; - if (typeName == NULL || - !IsA(typeName, TypeName)) - goto fail; + /* The grammar allows SETOF in TypeName, but we don't want that here. */ if (typeName->setof) goto fail; - pfree(buf.data); - return typeName; fail: diff --git a/src/backend/parser/parser.c b/src/backend/parser/parser.c index b897a5160a22c..8eb8feb372ee6 100644 --- a/src/backend/parser/parser.c +++ b/src/backend/parser/parser.c @@ -35,11 +35,11 @@ static char *str_udeescape(const char *str, char escape, * raw_parser * Given a query in string form, do lexical and grammatical analysis. * - * Returns a list of raw (un-analyzed) parse trees. The immediate elements - * of the list are always RawStmt nodes. + * Returns a list of raw (un-analyzed) parse trees. The contents of the + * list have the form required by the specified RawParseMode. */ List * -raw_parser(const char *str) +raw_parser(const char *str, RawParseMode mode) { core_yyscan_t yyscanner; base_yy_extra_type yyextra; @@ -49,8 +49,22 @@ raw_parser(const char *str) yyscanner = scanner_init(str, &yyextra.core_yy_extra, &ScanKeywords, ScanKeywordTokens); - /* base_yylex() only needs this much initialization */ - yyextra.have_lookahead = false; + /* base_yylex() only needs us to initialize the lookahead token, if any */ + if (mode == RAW_PARSE_DEFAULT) + yyextra.have_lookahead = false; + else + { + /* this array is indexed by RawParseMode enum */ + static const int mode_token[] = { + 0, /* RAW_PARSE_DEFAULT */ + MODE_TYPE_NAME /* RAW_PARSE_TYPE_NAME */ + }; + + yyextra.have_lookahead = true; + yyextra.lookahead_token = mode_token[mode]; + yyextra.lookahead_yylloc = 0; + yyextra.lookahead_end = NULL; + } /* initialize the bison parser */ parser_init(&yyextra); @@ -104,7 +118,8 @@ base_yylex(YYSTYPE *lvalp, YYLTYPE *llocp, core_yyscan_t yyscanner) cur_token = yyextra->lookahead_token; lvalp->core_yystype = yyextra->lookahead_yylval; *llocp = yyextra->lookahead_yylloc; - *(yyextra->lookahead_end) = yyextra->lookahead_hold_char; + if (yyextra->lookahead_end) + *(yyextra->lookahead_end) = yyextra->lookahead_hold_char; yyextra->have_lookahead = false; } else diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index dfa0d685a837a..f5c14249d13db 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -635,7 +635,7 @@ pg_parse_query(const char *query_string) if (log_parser_stats) ResetUsage(); - raw_parsetree_list = raw_parser(query_string); + raw_parsetree_list = raw_parser(query_string, RAW_PARSE_DEFAULT); if (log_parser_stats) ShowUsage("PARSER STATISTICS"); diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h index 6e603d007d736..9c70603434a20 100644 --- a/src/include/executor/spi.h +++ b/src/include/executor/spi.h @@ -15,7 +15,7 @@ #include "commands/trigger.h" #include "lib/ilist.h" -#include "nodes/parsenodes.h" +#include "parser/parser.h" #include "utils/portal.h" @@ -33,6 +33,15 @@ typedef struct SPITupleTable SubTransactionId subid; /* subxact in which tuptable was created */ } SPITupleTable; +/* Optional arguments for SPI_prepare_extended */ +typedef struct SPIPrepareOptions +{ + ParserSetupHook parserSetup; + void *parserSetupArg; + RawParseMode parseMode; + int cursorOptions; +} SPIPrepareOptions; + /* Plans are opaque structs for standard users of SPI */ typedef struct _SPI_plan *SPIPlanPtr; @@ -113,6 +122,8 @@ extern int SPI_execute_with_receiver(const char *src, extern SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes); extern SPIPlanPtr SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes, int cursorOptions); +extern SPIPlanPtr SPI_prepare_extended(const char *src, + const SPIPrepareOptions *options); extern SPIPlanPtr SPI_prepare_params(const char *src, ParserSetupHook parserSetup, void *parserSetupArg, diff --git a/src/include/executor/spi_priv.h b/src/include/executor/spi_priv.h index 29a77781a9d57..ce0f58ce687b0 100644 --- a/src/include/executor/spi_priv.h +++ b/src/include/executor/spi_priv.h @@ -95,6 +95,7 @@ typedef struct _SPI_plan bool no_snapshots; /* let the caller handle the snapshots */ List *plancache_list; /* one CachedPlanSource per parsetree */ MemoryContext plancxt; /* Context containing _SPI_plan and data */ + RawParseMode parse_mode; /* raw_parser() mode */ int cursor_options; /* Cursor options used for planning */ int nargs; /* number of plan arguments */ Oid *argtypes; /* Argument types (NULL if nargs is 0) */ diff --git a/src/include/parser/parser.h b/src/include/parser/parser.h index 0973003044498..80d90027cc47b 100644 --- a/src/include/parser/parser.h +++ b/src/include/parser/parser.h @@ -18,6 +18,24 @@ #include "nodes/parsenodes.h" +/* + * RawParseMode determines the form of the string that raw_parser() accepts: + * + * RAW_PARSE_DEFAULT: parse a semicolon-separated list of SQL commands, + * and return a List of RawStmt nodes. + * + * RAW_PARSE_TYPE_NAME: parse a type name, and return a one-element List + * containing a TypeName node. + * + * ... more to come ... + */ +typedef enum +{ + RAW_PARSE_DEFAULT = 0, + RAW_PARSE_TYPE_NAME +} RawParseMode; + +/* Values for the backslash_quote GUC */ typedef enum { BACKSLASH_QUOTE_OFF, @@ -32,7 +50,7 @@ extern PGDLLIMPORT bool standard_conforming_strings; /* Primary entry point for the raw parsing functions */ -extern List *raw_parser(const char *str); +extern List *raw_parser(const char *str, RawParseMode mode); /* Utility functions exported by gram.y (perhaps these should be elsewhere) */ extern List *SystemFuncName(char *name); diff --git a/src/interfaces/ecpg/preproc/parse.pl b/src/interfaces/ecpg/preproc/parse.pl index f2731ea873a43..7f9be85eb66ed 100644 --- a/src/interfaces/ecpg/preproc/parse.pl +++ b/src/interfaces/ecpg/preproc/parse.pl @@ -63,7 +63,7 @@ 'opt_array_bounds' => '', # "ignore" means: do not create type and rules for this non-term-id - 'stmtblock' => 'ignore', + 'parse_toplevel' => 'ignore', 'stmtmulti' => 'ignore', 'CreateAsStmt' => 'ignore', 'DeallocateStmt' => 'ignore', diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index f966ddf0b5e37..4a51fb6d9f101 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -4168,6 +4168,7 @@ exec_prepare_plan(PLpgSQL_execstate *estate, bool keepplan) { SPIPlanPtr plan; + SPIPrepareOptions options; /* * The grammar can't conveniently set expr->func while building the parse @@ -4178,12 +4179,14 @@ exec_prepare_plan(PLpgSQL_execstate *estate, /* * Generate and save the plan */ - plan = SPI_prepare_params(expr->query, - (ParserSetupHook) plpgsql_parser_setup, - (void *) expr, - cursorOptions); + memset(&options, 0, sizeof(options)); + options.parserSetup = (ParserSetupHook) plpgsql_parser_setup; + options.parserSetupArg = (void *) expr; + options.parseMode = RAW_PARSE_DEFAULT; + options.cursorOptions = cursorOptions; + plan = SPI_prepare_extended(expr->query, &options); if (plan == NULL) - elog(ERROR, "SPI_prepare_params failed for \"%s\": %s", + elog(ERROR, "SPI_prepare_extended failed for \"%s\": %s", expr->query, SPI_result_code_string(SPI_result)); if (keepplan) SPI_keepplan(plan); diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y index a154b9841a65c..c09576efff501 100644 --- a/src/pl/plpgsql/src/pl_gram.y +++ b/src/pl/plpgsql/src/pl_gram.y @@ -3661,7 +3661,7 @@ check_sql_expr(const char *stmt, int location, int leaderlen) error_context_stack = &syntax_errcontext; oldCxt = MemoryContextSwitchTo(plpgsql_compile_tmp_cxt); - (void) raw_parser(stmt); + (void) raw_parser(stmt, RAW_PARSE_DEFAULT); MemoryContextSwitchTo(oldCxt); /* Restore former ereport callback */ From c9d5298485b78a37923a23f9af9aa0ade06762db Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 4 Jan 2021 11:52:00 -0500 Subject: [PATCH 025/240] Re-implement pl/pgsql's expression and assignment parsing. Invent new RawParseModes that allow the core grammar to handle pl/pgsql expressions and assignments directly, and thereby get rid of a lot of hackery in pl/pgsql's parser. This moves a good deal of knowledge about pl/pgsql into the core code: notably, we have to invent a CoercionContext that matches pl/pgsql's (rather dubious) historical behavior for assignment coercions. That's getting away from the original idea of pl/pgsql as an arm's-length extension of the core, but really we crossed that bridge a long time ago. The main advantage of doing this is that we can now use the core parser to generate FieldStore and/or SubscriptingRef nodes to handle assignments to pl/pgsql variables that are records or arrays. That fixes a number of cases that had never been implemented in pl/pgsql assignment, such as nested records and array slicing, and it allows pl/pgsql assignment to support the datatype-specific subscripting behaviors introduced in commit c7aba7c14. There are cosmetic benefits too: when a syntax error occurs in a pl/pgsql expression, the error report no longer includes the confusing "SELECT" keyword that used to get prefixed to the expression text. Also, there seem to be some small speed gains. Discussion: https://postgr.es/m/4165684.1607707277@sss.pgh.pa.us --- contrib/hstore/expected/hstore.out | 4 + contrib/hstore/sql/hstore.sql | 4 + doc/src/sgml/plpgsql.sgml | 21 +- src/backend/commands/functioncmds.c | 1 + src/backend/executor/spi.c | 54 +++- src/backend/nodes/copyfuncs.c | 17 ++ src/backend/nodes/equalfuncs.c | 15 ++ src/backend/nodes/nodeFuncs.c | 10 + src/backend/nodes/outfuncs.c | 15 ++ src/backend/parser/analyze.c | 240 ++++++++++++++++++ src/backend/parser/gram.y | 99 +++++++- src/backend/parser/parse_coerce.c | 8 + src/backend/parser/parse_target.c | 41 +-- src/backend/parser/parser.c | 6 +- src/backend/tcop/utility.c | 8 + src/include/nodes/nodes.h | 1 + src/include/nodes/parsenodes.h | 19 ++ src/include/nodes/primnodes.h | 1 + src/include/parser/parse_target.h | 12 + src/include/parser/parser.h | 13 +- src/interfaces/ecpg/preproc/parse.pl | 6 +- src/pl/plpgsql/src/Makefile | 2 +- src/pl/plpgsql/src/expected/plpgsql_array.out | 94 +++++++ .../plpgsql/src/expected/plpgsql_record.out | 91 ++++++- .../plpgsql/src/expected/plpgsql_varprops.out | 2 +- src/pl/plpgsql/src/pl_comp.c | 49 ++-- src/pl/plpgsql/src/pl_exec.c | 49 +++- src/pl/plpgsql/src/pl_gram.y | 196 ++++++++------ src/pl/plpgsql/src/plpgsql.h | 5 +- src/pl/plpgsql/src/sql/plpgsql_array.sql | 79 ++++++ src/pl/plpgsql/src/sql/plpgsql_record.sql | 42 +++ src/test/regress/expected/plpgsql.out | 36 +-- 32 files changed, 1081 insertions(+), 159 deletions(-) create mode 100644 src/pl/plpgsql/src/expected/plpgsql_array.out create mode 100644 src/pl/plpgsql/src/sql/plpgsql_array.sql diff --git a/contrib/hstore/expected/hstore.out b/contrib/hstore/expected/hstore.out index fdcc3920cecd8..64a3272b9cf45 100644 --- a/contrib/hstore/expected/hstore.out +++ b/contrib/hstore/expected/hstore.out @@ -1583,6 +1583,10 @@ select f2 from test_json_agg; "d"=>NULL, "x"=>"xyzzy" (3 rows) +-- Test subscripting in plpgsql +do $$ declare h hstore; +begin h['a'] := 'b'; raise notice 'h = %, h[a] = %', h, h['a']; end $$; +NOTICE: h = "a"=>"b", h[a] = b -- Check the hstore_hash() and hstore_hash_extended() function explicitly. SELECT v as value, hstore_hash(v)::bit(32) as standard, hstore_hash_extended(v, 0)::bit(32) as extended0, diff --git a/contrib/hstore/sql/hstore.sql b/contrib/hstore/sql/hstore.sql index 8d96e30403042..a59db66b0aee8 100644 --- a/contrib/hstore/sql/hstore.sql +++ b/contrib/hstore/sql/hstore.sql @@ -372,6 +372,10 @@ select f2['d':'e'] from test_json_agg; -- error update test_json_agg set f2['d'] = f2['e'], f2['x'] = 'xyzzy'; select f2 from test_json_agg; +-- Test subscripting in plpgsql +do $$ declare h hstore; +begin h['a'] := 'b'; raise notice 'h = %, h[a] = %', h, h['a']; end $$; + -- Check the hstore_hash() and hstore_hash_extended() function explicitly. SELECT v as value, hstore_hash(v)::bit(32) as standard, hstore_hash_extended(v, 0)::bit(32) as extended0, diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml index 11246aa65348c..45d3e43ed14e9 100644 --- a/doc/src/sgml/plpgsql.sgml +++ b/doc/src/sgml/plpgsql.sgml @@ -946,8 +946,8 @@ PREPARE statement_name(integer, integer) AS SELECT $1 database engine. The expression must yield a single value (possibly a row value, if the variable is a row or record variable). The target variable can be a simple variable (optionally qualified with a block - name), a field of a row or record variable, or an element of an array - that is a simple variable or field. Equal (=) can be + name), a field of a row or record target, or an element or slice of + an array target. Equal (=) can be used instead of PL/SQL-compliant :=. @@ -968,8 +968,25 @@ PREPARE statement_name(integer, integer) AS SELECT $1 tax := subtotal * 0.06; my_record.user_id := 20; +my_array[j] := 20; +my_array[1:3] := array[1,2,3]; +complex_array[n].realpart = 12.3; + + + It's useful to know that what follows the assignment operator is + essentially treated as a SELECT command; as long + as it returns a single row and column, it will work. Thus for example + one can write something like + +total_sales := sum(quantity) from sales; + + This provides an effect similar to the single-row SELECT + ... INTO syntax described in + . However, that syntax + is more portable. + diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index 55950e754d20f..7a4e104623bef 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -1628,6 +1628,7 @@ CreateCast(CreateCastStmt *stmt) case COERCION_ASSIGNMENT: castcontext = COERCION_CODE_ASSIGNMENT; break; + /* COERCION_PLPGSQL is intentionally not covered here */ case COERCION_EXPLICIT: castcontext = COERCION_CODE_EXPLICIT; break; diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 6c0593686a957..e28d2429222f0 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -51,6 +51,12 @@ static _SPI_connection *_SPI_current = NULL; static int _SPI_stack_depth = 0; /* allocated size of _SPI_stack */ static int _SPI_connected = -1; /* current stack index */ +typedef struct SPICallbackArg +{ + const char *query; + RawParseMode mode; +} SPICallbackArg; + static Portal SPI_cursor_open_internal(const char *name, SPIPlanPtr plan, ParamListInfo paramLI, bool read_only); @@ -1479,6 +1485,7 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan, Snapshot snapshot; MemoryContext oldcontext; Portal portal; + SPICallbackArg spicallbackarg; ErrorContextCallback spierrcontext; /* @@ -1533,8 +1540,10 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan, * Setup error traceback support for ereport(), in case GetCachedPlan * throws an error. */ + spicallbackarg.query = plansource->query_string; + spicallbackarg.mode = plan->parse_mode; spierrcontext.callback = _SPI_error_callback; - spierrcontext.arg = unconstify(char *, plansource->query_string); + spierrcontext.arg = &spicallbackarg; spierrcontext.previous = error_context_stack; error_context_stack = &spierrcontext; @@ -1952,6 +1961,7 @@ SPI_plan_get_cached_plan(SPIPlanPtr plan) { CachedPlanSource *plansource; CachedPlan *cplan; + SPICallbackArg spicallbackarg; ErrorContextCallback spierrcontext; Assert(plan->magic == _SPI_PLAN_MAGIC); @@ -1966,8 +1976,10 @@ SPI_plan_get_cached_plan(SPIPlanPtr plan) plansource = (CachedPlanSource *) linitial(plan->plancache_list); /* Setup error traceback support for ereport() */ + spicallbackarg.query = plansource->query_string; + spicallbackarg.mode = plan->parse_mode; spierrcontext.callback = _SPI_error_callback; - spierrcontext.arg = unconstify(char *, plansource->query_string); + spierrcontext.arg = &spicallbackarg; spierrcontext.previous = error_context_stack; error_context_stack = &spierrcontext; @@ -2094,13 +2106,16 @@ _SPI_prepare_plan(const char *src, SPIPlanPtr plan) List *raw_parsetree_list; List *plancache_list; ListCell *list_item; + SPICallbackArg spicallbackarg; ErrorContextCallback spierrcontext; /* * Setup error traceback support for ereport() */ + spicallbackarg.query = src; + spicallbackarg.mode = plan->parse_mode; spierrcontext.callback = _SPI_error_callback; - spierrcontext.arg = unconstify(char *, src); + spierrcontext.arg = &spicallbackarg; spierrcontext.previous = error_context_stack; error_context_stack = &spierrcontext; @@ -2199,13 +2214,16 @@ _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan) List *raw_parsetree_list; List *plancache_list; ListCell *list_item; + SPICallbackArg spicallbackarg; ErrorContextCallback spierrcontext; /* * Setup error traceback support for ereport() */ + spicallbackarg.query = src; + spicallbackarg.mode = plan->parse_mode; spierrcontext.callback = _SPI_error_callback; - spierrcontext.arg = unconstify(char *, src); + spierrcontext.arg = &spicallbackarg; spierrcontext.previous = error_context_stack; error_context_stack = &spierrcontext; @@ -2263,6 +2281,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, SPITupleTable *my_tuptable = NULL; int res = 0; bool pushed_active_snap = false; + SPICallbackArg spicallbackarg; ErrorContextCallback spierrcontext; CachedPlan *cplan = NULL; ListCell *lc1; @@ -2270,8 +2289,10 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, /* * Setup error traceback support for ereport() */ + spicallbackarg.query = NULL; /* we'll fill this below */ + spicallbackarg.mode = plan->parse_mode; spierrcontext.callback = _SPI_error_callback; - spierrcontext.arg = NULL; /* we'll fill this below */ + spierrcontext.arg = &spicallbackarg; spierrcontext.previous = error_context_stack; error_context_stack = &spierrcontext; @@ -2318,7 +2339,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, List *stmt_list; ListCell *lc2; - spierrcontext.arg = unconstify(char *, plansource->query_string); + spicallbackarg.query = plansource->query_string; /* * If this is a one-shot plan, we still need to do parse analysis. @@ -2722,7 +2743,8 @@ _SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, uint64 tcount) static void _SPI_error_callback(void *arg) { - const char *query = (const char *) arg; + SPICallbackArg *carg = (SPICallbackArg *) arg; + const char *query = carg->query; int syntaxerrposition; if (query == NULL) /* in case arg wasn't set yet */ @@ -2740,7 +2762,23 @@ _SPI_error_callback(void *arg) internalerrquery(query); } else - errcontext("SQL statement \"%s\"", query); + { + /* Use the parse mode to decide how to describe the query */ + switch (carg->mode) + { + case RAW_PARSE_PLPGSQL_EXPR: + errcontext("SQL expression \"%s\"", query); + break; + case RAW_PARSE_PLPGSQL_ASSIGN1: + case RAW_PARSE_PLPGSQL_ASSIGN2: + case RAW_PARSE_PLPGSQL_ASSIGN3: + errcontext("PL/pgSQL assignment \"%s\"", query); + break; + default: + errcontext("SQL statement \"%s\"", query); + break; + } + } } /* diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 67d45418662a4..ba3ccc712c888 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -3199,6 +3199,20 @@ _copySetOperationStmt(const SetOperationStmt *from) return newnode; } +static PLAssignStmt * +_copyPLAssignStmt(const PLAssignStmt *from) +{ + PLAssignStmt *newnode = makeNode(PLAssignStmt); + + COPY_STRING_FIELD(name); + COPY_NODE_FIELD(indirection); + COPY_SCALAR_FIELD(nnames); + COPY_NODE_FIELD(val); + COPY_LOCATION_FIELD(location); + + return newnode; +} + static AlterTableStmt * _copyAlterTableStmt(const AlterTableStmt *from) { @@ -5220,6 +5234,9 @@ copyObjectImpl(const void *from) case T_SetOperationStmt: retval = _copySetOperationStmt(from); break; + case T_PLAssignStmt: + retval = _copyPLAssignStmt(from); + break; case T_AlterTableStmt: retval = _copyAlterTableStmt(from); break; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 4d4258b0cb2ce..a2ef853dc2a02 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1085,6 +1085,18 @@ _equalSetOperationStmt(const SetOperationStmt *a, const SetOperationStmt *b) return true; } +static bool +_equalPLAssignStmt(const PLAssignStmt *a, const PLAssignStmt *b) +{ + COMPARE_STRING_FIELD(name); + COMPARE_NODE_FIELD(indirection); + COMPARE_SCALAR_FIELD(nnames); + COMPARE_NODE_FIELD(val); + COMPARE_LOCATION_FIELD(location); + + return true; +} + static bool _equalAlterTableStmt(const AlterTableStmt *a, const AlterTableStmt *b) { @@ -3275,6 +3287,9 @@ equal(const void *a, const void *b) case T_SetOperationStmt: retval = _equalSetOperationStmt(a, b); break; + case T_PLAssignStmt: + retval = _equalPLAssignStmt(a, b); + break; case T_AlterTableStmt: retval = _equalAlterTableStmt(a, b); break; diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index a011bc7b98d7c..6be19916fced7 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -3669,6 +3669,16 @@ raw_expression_tree_walker(Node *node, return true; } break; + case T_PLAssignStmt: + { + PLAssignStmt *stmt = (PLAssignStmt *) node; + + if (walker(stmt->indirection, context)) + return true; + if (walker(stmt->val, context)) + return true; + } + break; case T_A_Expr: { A_Expr *expr = (A_Expr *) node; diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 6b8ec03fa7738..8392be6d44a33 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -2775,6 +2775,18 @@ _outSelectStmt(StringInfo str, const SelectStmt *node) WRITE_NODE_FIELD(rarg); } +static void +_outPLAssignStmt(StringInfo str, const PLAssignStmt *node) +{ + WRITE_NODE_TYPE("PLASSIGN"); + + WRITE_STRING_FIELD(name); + WRITE_NODE_FIELD(indirection); + WRITE_INT_FIELD(nnames); + WRITE_NODE_FIELD(val); + WRITE_LOCATION_FIELD(location); +} + static void _outFuncCall(StringInfo str, const FuncCall *node) { @@ -4211,6 +4223,9 @@ outNode(StringInfo str, const void *obj) case T_SelectStmt: _outSelectStmt(str, obj); break; + case T_PLAssignStmt: + _outPLAssignStmt(str, obj); + break; case T_ColumnDef: _outColumnDef(str, obj); break; diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 1066f9458f389..28e192f51c851 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -42,8 +42,10 @@ #include "parser/parse_param.h" #include "parser/parse_relation.h" #include "parser/parse_target.h" +#include "parser/parse_type.h" #include "parser/parsetree.h" #include "rewrite/rewriteManip.h" +#include "utils/builtins.h" #include "utils/rel.h" @@ -70,6 +72,8 @@ static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt); static List *transformReturningList(ParseState *pstate, List *returningList); static List *transformUpdateTargetList(ParseState *pstate, List *targetList); +static Query *transformPLAssignStmt(ParseState *pstate, + PLAssignStmt *stmt); static Query *transformDeclareCursorStmt(ParseState *pstate, DeclareCursorStmt *stmt); static Query *transformExplainStmt(ParseState *pstate, @@ -304,6 +308,11 @@ transformStmt(ParseState *pstate, Node *parseTree) } break; + case T_PLAssignStmt: + result = transformPLAssignStmt(pstate, + (PLAssignStmt *) parseTree); + break; + /* * Special cases */ @@ -367,6 +376,7 @@ analyze_requires_snapshot(RawStmt *parseTree) case T_DeleteStmt: case T_UpdateStmt: case T_SelectStmt: + case T_PLAssignStmt: result = true; break; @@ -2393,6 +2403,236 @@ transformReturningList(ParseState *pstate, List *returningList) } +/* + * transformPLAssignStmt - + * transform a PL/pgSQL assignment statement + * + * If there is no opt_indirection, the transformed statement looks like + * "SELECT a_expr ...", except the expression has been cast to the type of + * the target. With indirection, it's still a SELECT, but the expression will + * incorporate FieldStore and/or assignment SubscriptingRef nodes to compute a + * new value for a container-type variable represented by the target. The + * expression references the target as the container source. + */ +static Query * +transformPLAssignStmt(ParseState *pstate, PLAssignStmt *stmt) +{ + Query *qry = makeNode(Query); + ColumnRef *cref = makeNode(ColumnRef); + List *indirection = stmt->indirection; + int nnames = stmt->nnames; + SelectStmt *sstmt = stmt->val; + Node *target; + Oid targettype; + int32 targettypmod; + Oid targetcollation; + List *tlist; + TargetEntry *tle; + Oid type_id; + Node *qual; + ListCell *l; + + /* + * First, construct a ColumnRef for the target variable. If the target + * has more than one dotted name, we have to pull the extra names out of + * the indirection list. + */ + cref->fields = list_make1(makeString(stmt->name)); + cref->location = stmt->location; + if (nnames > 1) + { + /* avoid munging the raw parsetree */ + indirection = list_copy(indirection); + while (--nnames > 0 && indirection != NIL) + { + Node *ind = (Node *) linitial(indirection); + + if (!IsA(ind, String)) + elog(ERROR, "invalid name count in PLAssignStmt"); + cref->fields = lappend(cref->fields, ind); + indirection = list_delete_first(indirection); + } + } + + /* + * Transform the target reference. Typically we will get back a Param + * node, but there's no reason to be too picky about its type. + */ + target = transformExpr(pstate, (Node *) cref, + EXPR_KIND_UPDATE_TARGET); + targettype = exprType(target); + targettypmod = exprTypmod(target); + targetcollation = exprCollation(target); + + /* + * The rest mostly matches transformSelectStmt, except that we needn't + * consider WITH or DISTINCT, and we build a targetlist our own way. + */ + qry->commandType = CMD_SELECT; + pstate->p_is_insert = false; + + /* make FOR UPDATE/FOR SHARE info available to addRangeTableEntry */ + pstate->p_locking_clause = sstmt->lockingClause; + + /* make WINDOW info available for window functions, too */ + pstate->p_windowdefs = sstmt->windowClause; + + /* process the FROM clause */ + transformFromClause(pstate, sstmt->fromClause); + + /* initially transform the targetlist as if in SELECT */ + tlist = transformTargetList(pstate, sstmt->targetList, + EXPR_KIND_SELECT_TARGET); + + /* we should have exactly one targetlist item */ + if (list_length(tlist) != 1) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg_plural("assignment source returned %d column", + "assignment source returned %d columns", + list_length(tlist), + list_length(tlist)))); + + tle = linitial_node(TargetEntry, tlist); + + /* + * This next bit is similar to transformAssignedExpr; the key difference + * is we use COERCION_PLPGSQL not COERCION_ASSIGNMENT. + */ + type_id = exprType((Node *) tle->expr); + + pstate->p_expr_kind = EXPR_KIND_UPDATE_TARGET; + + if (indirection) + { + tle->expr = (Expr *) + transformAssignmentIndirection(pstate, + target, + stmt->name, + false, + targettype, + targettypmod, + targetcollation, + indirection, + list_head(indirection), + (Node *) tle->expr, + COERCION_PLPGSQL, + exprLocation(target)); + } + else if (targettype != type_id && + (targettype == RECORDOID || ISCOMPLEX(targettype)) && + (type_id == RECORDOID || ISCOMPLEX(type_id))) + { + /* + * Hack: do not let coerce_to_target_type() deal with inconsistent + * composite types. Just pass the expression result through as-is, + * and let the PL/pgSQL executor do the conversion its way. This is + * rather bogus, but it's needed for backwards compatibility. + */ + } + else + { + /* + * For normal non-qualified target column, do type checking and + * coercion. + */ + Node *orig_expr = (Node *) tle->expr; + + tle->expr = (Expr *) + coerce_to_target_type(pstate, + orig_expr, type_id, + targettype, targettypmod, + COERCION_PLPGSQL, + COERCE_IMPLICIT_CAST, + -1); + /* With COERCION_PLPGSQL, this error is probably unreachable */ + if (tle->expr == NULL) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("variable \"%s\" is of type %s" + " but expression is of type %s", + stmt->name, + format_type_be(targettype), + format_type_be(type_id)), + errhint("You will need to rewrite or cast the expression."), + parser_errposition(pstate, exprLocation(orig_expr)))); + } + + pstate->p_expr_kind = EXPR_KIND_NONE; + + qry->targetList = list_make1(tle); + + /* transform WHERE */ + qual = transformWhereClause(pstate, sstmt->whereClause, + EXPR_KIND_WHERE, "WHERE"); + + /* initial processing of HAVING clause is much like WHERE clause */ + qry->havingQual = transformWhereClause(pstate, sstmt->havingClause, + EXPR_KIND_HAVING, "HAVING"); + + /* + * Transform sorting/grouping stuff. Do ORDER BY first because both + * transformGroupClause and transformDistinctClause need the results. Note + * that these functions can also change the targetList, so it's passed to + * them by reference. + */ + qry->sortClause = transformSortClause(pstate, + sstmt->sortClause, + &qry->targetList, + EXPR_KIND_ORDER_BY, + false /* allow SQL92 rules */ ); + + qry->groupClause = transformGroupClause(pstate, + sstmt->groupClause, + &qry->groupingSets, + &qry->targetList, + qry->sortClause, + EXPR_KIND_GROUP_BY, + false /* allow SQL92 rules */ ); + + /* No DISTINCT clause */ + Assert(!sstmt->distinctClause); + qry->distinctClause = NIL; + qry->hasDistinctOn = false; + + /* transform LIMIT */ + qry->limitOffset = transformLimitClause(pstate, sstmt->limitOffset, + EXPR_KIND_OFFSET, "OFFSET", + sstmt->limitOption); + qry->limitCount = transformLimitClause(pstate, sstmt->limitCount, + EXPR_KIND_LIMIT, "LIMIT", + sstmt->limitOption); + qry->limitOption = sstmt->limitOption; + + /* transform window clauses after we have seen all window functions */ + qry->windowClause = transformWindowDefinitions(pstate, + pstate->p_windowdefs, + &qry->targetList); + + qry->rtable = pstate->p_rtable; + qry->jointree = makeFromExpr(pstate->p_joinlist, qual); + + qry->hasSubLinks = pstate->p_hasSubLinks; + qry->hasWindowFuncs = pstate->p_hasWindowFuncs; + qry->hasTargetSRFs = pstate->p_hasTargetSRFs; + qry->hasAggs = pstate->p_hasAggs; + + foreach(l, sstmt->lockingClause) + { + transformLockingClause(pstate, qry, + (LockingClause *) lfirst(l), false); + } + + assign_query_collations(pstate, qry); + + /* this must be done after collations, for reliable comparison of exprs */ + if (pstate->p_hasAggs || qry->groupClause || qry->groupingSets || qry->havingQual) + parseCheckAggregates(pstate, qry); + + return qry; +} + + /* * transformDeclareCursorStmt - * transform a DECLARE CURSOR Statement diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index fb025f08a4eb4..31c95443a5bf4 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -294,6 +294,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type select_no_parens select_with_parens select_clause simple_select values_clause + PLpgSQL_Expr PLAssignStmt %type alter_column_default opclass_item opclass_drop alter_using %type add_drop opt_asc_desc opt_nulls_order @@ -535,7 +536,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type ColId ColLabel BareColLabel %type NonReservedWord NonReservedWord_or_Sconst %type var_name type_function_name param_name -%type createdb_opt_name +%type createdb_opt_name plassign_target %type var_value zone_value %type auth_ident RoleSpec opt_granted_by @@ -731,6 +732,10 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); * something other than the usual list of SQL commands. */ %token MODE_TYPE_NAME +%token MODE_PLPGSQL_EXPR +%token MODE_PLPGSQL_ASSIGN1 +%token MODE_PLPGSQL_ASSIGN2 +%token MODE_PLPGSQL_ASSIGN3 /* Precedence: lowest to highest */ @@ -810,6 +815,32 @@ parse_toplevel: { pg_yyget_extra(yyscanner)->parsetree = list_make1($2); } + | MODE_PLPGSQL_EXPR PLpgSQL_Expr + { + pg_yyget_extra(yyscanner)->parsetree = + list_make1(makeRawStmt($2, 0)); + } + | MODE_PLPGSQL_ASSIGN1 PLAssignStmt + { + PLAssignStmt *n = (PLAssignStmt *) $2; + n->nnames = 1; + pg_yyget_extra(yyscanner)->parsetree = + list_make1(makeRawStmt((Node *) n, 0)); + } + | MODE_PLPGSQL_ASSIGN2 PLAssignStmt + { + PLAssignStmt *n = (PLAssignStmt *) $2; + n->nnames = 2; + pg_yyget_extra(yyscanner)->parsetree = + list_make1(makeRawStmt((Node *) n, 0)); + } + | MODE_PLPGSQL_ASSIGN3 PLAssignStmt + { + PLAssignStmt *n = (PLAssignStmt *) $2; + n->nnames = 3; + pg_yyget_extra(yyscanner)->parsetree = + list_make1(makeRawStmt((Node *) n, 0)); + } ; /* @@ -15024,6 +15055,72 @@ role_list: RoleSpec { $$ = lappend($1, $3); } ; + +/***************************************************************************** + * + * PL/pgSQL extensions + * + * You'd think a PL/pgSQL "expression" should be just an a_expr, but + * historically it can include just about anything that can follow SELECT. + * Therefore the returned struct is a SelectStmt. + *****************************************************************************/ + +PLpgSQL_Expr: opt_target_list + from_clause where_clause + group_clause having_clause window_clause + opt_sort_clause opt_select_limit opt_for_locking_clause + { + SelectStmt *n = makeNode(SelectStmt); + + n->targetList = $1; + n->fromClause = $2; + n->whereClause = $3; + n->groupClause = $4; + n->havingClause = $5; + n->windowClause = $6; + n->sortClause = $7; + if ($8) + { + n->limitOffset = $8->limitOffset; + n->limitCount = $8->limitCount; + if (!n->sortClause && + $8->limitOption == LIMIT_OPTION_WITH_TIES) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("WITH TIES cannot be specified without ORDER BY clause"))); + n->limitOption = $8->limitOption; + } + n->lockingClause = $9; + $$ = (Node *) n; + } + ; + +/* + * PL/pgSQL Assignment statement: name opt_indirection := PLpgSQL_Expr + */ + +PLAssignStmt: plassign_target opt_indirection plassign_equals PLpgSQL_Expr + { + PLAssignStmt *n = makeNode(PLAssignStmt); + + n->name = $1; + n->indirection = check_indirection($2, yyscanner); + /* nnames will be filled by calling production */ + n->val = (SelectStmt *) $4; + n->location = @1; + $$ = (Node *) n; + } + ; + +plassign_target: ColId { $$ = $1; } + | PARAM { $$ = psprintf("$%d", $1); } + ; + +plassign_equals: COLON_EQUALS + | '=' + ; + + /* * Name classification hierarchy. * diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 74eb39c0e4d8d..d5310f27db1d2 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -3098,6 +3098,14 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, } } + /* + * When parsing PL/pgSQL assignments, allow an I/O cast to be used + * whenever no normal coercion is available. + */ + if (result == COERCION_PATH_NONE && + ccontext == COERCION_PLPGSQL) + result = COERCION_PATH_COERCEVIAIO; + return result; } diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index fdf5500bf2003..7eaa076771a95 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -34,17 +34,6 @@ static void markTargetListOrigin(ParseState *pstate, TargetEntry *tle, Var *var, int levelsup); -static Node *transformAssignmentIndirection(ParseState *pstate, - Node *basenode, - const char *targetName, - bool targetIsSubscripting, - Oid targetTypeId, - int32 targetTypMod, - Oid targetCollation, - List *indirection, - ListCell *indirection_cell, - Node *rhs, - int location); static Node *transformAssignmentSubscripts(ParseState *pstate, Node *basenode, const char *targetName, @@ -56,6 +45,7 @@ static Node *transformAssignmentSubscripts(ParseState *pstate, List *indirection, ListCell *next_indirection, Node *rhs, + CoercionContext ccontext, int location); static List *ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref, bool make_target_entry); @@ -561,6 +551,7 @@ transformAssignedExpr(ParseState *pstate, indirection, list_head(indirection), (Node *) expr, + COERCION_ASSIGNMENT, location); } else @@ -642,15 +633,15 @@ updateTargetListEntry(ParseState *pstate, /* * Process indirection (field selection or subscripting) of the target - * column in INSERT/UPDATE. This routine recurses for multiple levels - * of indirection --- but note that several adjacent A_Indices nodes in - * the indirection list are treated as a single multidimensional subscript + * column in INSERT/UPDATE/assignment. This routine recurses for multiple + * levels of indirection --- but note that several adjacent A_Indices nodes + * in the indirection list are treated as a single multidimensional subscript * operation. * * In the initial call, basenode is a Var for the target column in UPDATE, - * or a null Const of the target's type in INSERT. In recursive calls, - * basenode is NULL, indicating that a substitute node should be consed up if - * needed. + * or a null Const of the target's type in INSERT, or a Param for the target + * variable in PL/pgSQL assignment. In recursive calls, basenode is NULL, + * indicating that a substitute node should be consed up if needed. * * targetName is the name of the field or subfield we're assigning to, and * targetIsSubscripting is true if we're subscripting it. These are just for @@ -667,12 +658,16 @@ updateTargetListEntry(ParseState *pstate, * rhs is the already-transformed value to be assigned; note it has not been * coerced to any particular type. * + * ccontext is the coercion level to use while coercing the rhs. For + * normal statements it'll be COERCION_ASSIGNMENT, but PL/pgSQL uses + * a special value. + * * location is the cursor error position for any errors. (Note: this points * to the head of the target clause, eg "foo" in "foo.bar[baz]". Later we * might want to decorate indirection cells with their own location info, * in which case the location argument could probably be dropped.) */ -static Node * +Node * transformAssignmentIndirection(ParseState *pstate, Node *basenode, const char *targetName, @@ -683,6 +678,7 @@ transformAssignmentIndirection(ParseState *pstate, List *indirection, ListCell *indirection_cell, Node *rhs, + CoercionContext ccontext, int location) { Node *result; @@ -757,6 +753,7 @@ transformAssignmentIndirection(ParseState *pstate, indirection, i, rhs, + ccontext, location); } @@ -807,6 +804,7 @@ transformAssignmentIndirection(ParseState *pstate, indirection, lnext(indirection, i), rhs, + ccontext, location); /* and build a FieldStore node */ @@ -845,6 +843,7 @@ transformAssignmentIndirection(ParseState *pstate, indirection, NULL, rhs, + ccontext, location); } @@ -853,7 +852,7 @@ transformAssignmentIndirection(ParseState *pstate, result = coerce_to_target_type(pstate, rhs, exprType(rhs), targetTypeId, targetTypMod, - COERCION_ASSIGNMENT, + ccontext, COERCE_IMPLICIT_CAST, -1); if (result == NULL) @@ -898,6 +897,7 @@ transformAssignmentSubscripts(ParseState *pstate, List *indirection, ListCell *next_indirection, Node *rhs, + CoercionContext ccontext, int location) { Node *result; @@ -949,6 +949,7 @@ transformAssignmentSubscripts(ParseState *pstate, indirection, next_indirection, rhs, + ccontext, location); /* @@ -969,7 +970,7 @@ transformAssignmentSubscripts(ParseState *pstate, result = coerce_to_target_type(pstate, result, resulttype, targetTypeId, targetTypMod, - COERCION_ASSIGNMENT, + ccontext, COERCE_IMPLICIT_CAST, -1); /* can fail if we had int2vector/oidvector, but not for true domains */ diff --git a/src/backend/parser/parser.c b/src/backend/parser/parser.c index 8eb8feb372ee6..875de7ba28fe0 100644 --- a/src/backend/parser/parser.c +++ b/src/backend/parser/parser.c @@ -57,7 +57,11 @@ raw_parser(const char *str, RawParseMode mode) /* this array is indexed by RawParseMode enum */ static const int mode_token[] = { 0, /* RAW_PARSE_DEFAULT */ - MODE_TYPE_NAME /* RAW_PARSE_TYPE_NAME */ + MODE_TYPE_NAME, /* RAW_PARSE_TYPE_NAME */ + MODE_PLPGSQL_EXPR, /* RAW_PARSE_PLPGSQL_EXPR */ + MODE_PLPGSQL_ASSIGN1, /* RAW_PARSE_PLPGSQL_ASSIGN1 */ + MODE_PLPGSQL_ASSIGN2, /* RAW_PARSE_PLPGSQL_ASSIGN2 */ + MODE_PLPGSQL_ASSIGN3 /* RAW_PARSE_PLPGSQL_ASSIGN3 */ }; yyextra.have_lookahead = true; diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 5825d3d81428e..53a511f1da81e 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -2313,6 +2313,10 @@ CreateCommandTag(Node *parsetree) tag = CMDTAG_SELECT; break; + case T_PLAssignStmt: + tag = CMDTAG_SELECT; + break; + /* utility statements --- same whether raw or cooked */ case T_TransactionStmt: { @@ -3181,6 +3185,10 @@ GetCommandLogLevel(Node *parsetree) lev = LOGSTMT_ALL; break; + case T_PLAssignStmt: + lev = LOGSTMT_ALL; + break; + /* utility statements --- same whether raw or cooked */ case T_TransactionStmt: lev = LOGSTMT_ALL; diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index fa28b21821fa4..caed683ba92a8 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -314,6 +314,7 @@ typedef enum NodeTag T_DeleteStmt, T_UpdateStmt, T_SelectStmt, + T_PLAssignStmt, T_AlterTableStmt, T_AlterTableCmd, T_AlterDomainStmt, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index a0f37e52687af..dc2bb40926a4a 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1675,6 +1675,25 @@ typedef struct SetOperationStmt } SetOperationStmt; +/* ---------------------- + * PL/pgSQL Assignment Statement + * + * Like SelectStmt, this is transformed into a SELECT Query. + * However, the targetlist of the result looks more like an UPDATE. + * ---------------------- + */ +typedef struct PLAssignStmt +{ + NodeTag type; + + char *name; /* initial column name */ + List *indirection; /* subscripts and field names, if any */ + int nnames; /* number of names to use in ColumnRef */ + SelectStmt *val; /* the PL/pgSQL expression to assign */ + int location; /* name's token location, or -1 if unknown */ +} PLAssignStmt; + + /***************************************************************************** * Other Statements (no optimizations required) * diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index e51be4bce8f9f..d4ce037088444 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -457,6 +457,7 @@ typedef enum CoercionContext { COERCION_IMPLICIT, /* coercion in context of expression */ COERCION_ASSIGNMENT, /* coercion in context of assignment */ + COERCION_PLPGSQL, /* if no assignment cast, use CoerceViaIO */ COERCION_EXPLICIT /* explicit cast operation */ } CoercionContext; diff --git a/src/include/parser/parse_target.h b/src/include/parser/parse_target.h index 9d3637747d4f0..1a7b1a92776bf 100644 --- a/src/include/parser/parse_target.h +++ b/src/include/parser/parse_target.h @@ -36,6 +36,18 @@ extern void updateTargetListEntry(ParseState *pstate, TargetEntry *tle, char *colname, int attrno, List *indirection, int location); +extern Node *transformAssignmentIndirection(ParseState *pstate, + Node *basenode, + const char *targetName, + bool targetIsSubscripting, + Oid targetTypeId, + int32 targetTypMod, + Oid targetCollation, + List *indirection, + ListCell *indirection_cell, + Node *rhs, + CoercionContext ccontext, + int location); extern List *checkInsertTargets(ParseState *pstate, List *cols, List **attrnos); extern TupleDesc expandRecordVariable(ParseState *pstate, Var *var, diff --git a/src/include/parser/parser.h b/src/include/parser/parser.h index 80d90027cc47b..853b0f1606189 100644 --- a/src/include/parser/parser.h +++ b/src/include/parser/parser.h @@ -27,12 +27,21 @@ * RAW_PARSE_TYPE_NAME: parse a type name, and return a one-element List * containing a TypeName node. * - * ... more to come ... + * RAW_PARSE_PLPGSQL_EXPR: parse a PL/pgSQL expression, and return + * a one-element List containing a RawStmt node. + * + * RAW_PARSE_PLPGSQL_ASSIGNn: parse a PL/pgSQL assignment statement, + * and return a one-element List containing a RawStmt node. "n" + * gives the number of dotted names comprising the target ColumnRef. */ typedef enum { RAW_PARSE_DEFAULT = 0, - RAW_PARSE_TYPE_NAME + RAW_PARSE_TYPE_NAME, + RAW_PARSE_PLPGSQL_EXPR, + RAW_PARSE_PLPGSQL_ASSIGN1, + RAW_PARSE_PLPGSQL_ASSIGN2, + RAW_PARSE_PLPGSQL_ASSIGN3 } RawParseMode; /* Values for the backslash_quote GUC */ diff --git a/src/interfaces/ecpg/preproc/parse.pl b/src/interfaces/ecpg/preproc/parse.pl index 7f9be85eb66ed..a84243fc8f0e7 100644 --- a/src/interfaces/ecpg/preproc/parse.pl +++ b/src/interfaces/ecpg/preproc/parse.pl @@ -70,7 +70,11 @@ 'ColId' => 'ignore', 'type_function_name' => 'ignore', 'ColLabel' => 'ignore', - 'Sconst' => 'ignore',); + 'Sconst' => 'ignore', + 'PLpgSQL_Expr' => 'ignore', + 'PLAssignStmt' => 'ignore', + 'plassign_target' => 'ignore', + 'plassign_equals' => 'ignore',); # these replace_line commands excise certain keywords from the core keyword # lists. Be sure to account for these in ColLabel and related productions. diff --git a/src/pl/plpgsql/src/Makefile b/src/pl/plpgsql/src/Makefile index 193df8a01083d..9946abbc1de65 100644 --- a/src/pl/plpgsql/src/Makefile +++ b/src/pl/plpgsql/src/Makefile @@ -32,7 +32,7 @@ DATA = plpgsql.control plpgsql--1.0.sql REGRESS_OPTS = --dbname=$(PL_TESTDB) -REGRESS = plpgsql_call plpgsql_control plpgsql_copy plpgsql_domain \ +REGRESS = plpgsql_array plpgsql_call plpgsql_control plpgsql_copy plpgsql_domain \ plpgsql_record plpgsql_cache plpgsql_simple plpgsql_transaction \ plpgsql_trap plpgsql_trigger plpgsql_varprops diff --git a/src/pl/plpgsql/src/expected/plpgsql_array.out b/src/pl/plpgsql/src/expected/plpgsql_array.out new file mode 100644 index 0000000000000..5f28b4f685b11 --- /dev/null +++ b/src/pl/plpgsql/src/expected/plpgsql_array.out @@ -0,0 +1,94 @@ +-- +-- Tests for PL/pgSQL handling of array variables +-- +-- We also check arrays of composites here, so this has some overlap +-- with the plpgsql_record tests. +-- +create type complex as (r float8, i float8); +create type quadarray as (c1 complex[], c2 complex); +do $$ declare a int[]; +begin a := array[1,2]; a[3] := 4; raise notice 'a = %', a; end$$; +NOTICE: a = {1,2,4} +do $$ declare a int[]; +begin a[3] := 4; raise notice 'a = %', a; end$$; +NOTICE: a = [3:3]={4} +do $$ declare a int[]; +begin a[1][4] := 4; raise notice 'a = %', a; end$$; +NOTICE: a = [1:1][4:4]={{4}} +do $$ declare a int[]; +begin a[1] := 23::text; raise notice 'a = %', a; end$$; -- lax typing +NOTICE: a = {23} +do $$ declare a int[]; +begin a := array[1,2]; a[2:3] := array[3,4]; raise notice 'a = %', a; end$$; +NOTICE: a = {1,3,4} +do $$ declare a int[]; +begin a := array[1,2]; a[2] := a[2] + 1; raise notice 'a = %', a; end$$; +NOTICE: a = {1,3} +do $$ declare a int[]; +begin a[1:2] := array[3,4]; raise notice 'a = %', a; end$$; +NOTICE: a = {3,4} +do $$ declare a int[]; +begin a[1:2] := 4; raise notice 'a = %', a; end$$; -- error +ERROR: malformed array literal: "4" +DETAIL: Array value must start with "{" or dimension information. +CONTEXT: PL/pgSQL function inline_code_block line 2 at assignment +do $$ declare a complex[]; +begin a[1] := (1,2); a[1].i := 11; raise notice 'a = %', a; end$$; +NOTICE: a = {"(1,11)"} +do $$ declare a complex[]; +begin a[1].i := 11; raise notice 'a = %, a[1].i = %', a, a[1].i; end$$; +NOTICE: a = {"(,11)"}, a[1].i = 11 +-- perhaps this ought to work, but for now it doesn't: +do $$ declare a complex[]; +begin a[1:2].i := array[11,12]; raise notice 'a = %', a; end$$; +ERROR: cannot assign to field "i" of column "a" because its type complex[] is not a composite type +LINE 1: a[1:2].i := array[11,12] + ^ +QUERY: a[1:2].i := array[11,12] +CONTEXT: PL/pgSQL function inline_code_block line 2 at assignment +do $$ declare a quadarray; +begin a.c1[1].i := 11; raise notice 'a = %, a.c1[1].i = %', a, a.c1[1].i; end$$; +NOTICE: a = ("{""(,11)""}",), a.c1[1].i = 11 +do $$ declare a int[]; +begin a := array_agg(x) from (values(1),(2),(3)) v(x); raise notice 'a = %', a; end$$; +NOTICE: a = {1,2,3} +create temp table onecol as select array[1,2] as f1; +do $$ declare a int[]; +begin a := f1 from onecol; raise notice 'a = %', a; end$$; +NOTICE: a = {1,2} +do $$ declare a int[]; +begin a := * from onecol for update; raise notice 'a = %', a; end$$; +NOTICE: a = {1,2} +-- error cases: +do $$ declare a int[]; +begin a := from onecol; raise notice 'a = %', a; end$$; +ERROR: assignment source returned 0 columns +CONTEXT: PL/pgSQL assignment "a := from onecol" +PL/pgSQL function inline_code_block line 2 at assignment +do $$ declare a int[]; +begin a := f1, f1 from onecol; raise notice 'a = %', a; end$$; +ERROR: assignment source returned 2 columns +CONTEXT: PL/pgSQL assignment "a := f1, f1 from onecol" +PL/pgSQL function inline_code_block line 2 at assignment +insert into onecol values(array[11]); +do $$ declare a int[]; +begin a := f1 from onecol; raise notice 'a = %', a; end$$; +ERROR: query "a := f1 from onecol" returned more than one row +CONTEXT: PL/pgSQL function inline_code_block line 2 at assignment +do $$ declare a int[]; +begin a := f1 from onecol limit 1; raise notice 'a = %', a; end$$; +NOTICE: a = {1,2} +do $$ declare a real; +begin a[1] := 2; raise notice 'a = %', a; end$$; +ERROR: cannot subscript type real because it does not support subscripting +LINE 1: a[1] := 2 + ^ +QUERY: a[1] := 2 +CONTEXT: PL/pgSQL function inline_code_block line 2 at assignment +do $$ declare a complex; +begin a.r[1] := 2; raise notice 'a = %', a; end$$; +ERROR: cannot subscript type double precision because it does not support subscripting +LINE 1: a.r[1] := 2 + ^ +QUERY: a.r[1] := 2 +CONTEXT: PL/pgSQL function inline_code_block line 2 at assignment diff --git a/src/pl/plpgsql/src/expected/plpgsql_record.out b/src/pl/plpgsql/src/expected/plpgsql_record.out index cf6089cbb2192..6e835c0751b22 100644 --- a/src/pl/plpgsql/src/expected/plpgsql_record.out +++ b/src/pl/plpgsql/src/expected/plpgsql_record.out @@ -3,6 +3,7 @@ -- create type two_int4s as (f1 int4, f2 int4); create type two_int8s as (q1 int8, q2 int8); +create type nested_int8s as (c1 two_int8s, c2 two_int8s); -- base-case return of a composite type create function retc(int) returns two_int8s language plpgsql as $$ begin return row($1,1)::two_int8s; end $$; @@ -82,6 +83,88 @@ begin end$$; NOTICE: c4 = (1,2) NOTICE: c8 = (1,2) +do $$ declare c two_int8s; d nested_int8s; +begin + c := row(1,2); + d := row(c, row(c.q1, c.q2+1)); + raise notice 'c = %, d = %', c, d; + c.q1 := 10; + d.c1 := row(11,12); + d.c2.q2 := 42; + raise notice 'c = %, d = %', c, d; + raise notice 'c.q1 = %, d.c2 = %', c.q1, d.c2; + raise notice '(d).c2.q2 = %', (d).c2.q2; -- doesn't work without parens + raise notice '(d.c2).q2 = %', (d.c2).q2; -- doesn't work without parens +end$$; +NOTICE: c = (1,2), d = ("(1,2)","(1,3)") +NOTICE: c = (10,2), d = ("(11,12)","(1,42)") +NOTICE: c.q1 = 10, d.c2 = (1,42) +NOTICE: (d).c2.q2 = 42 +NOTICE: (d.c2).q2 = 42 +-- block-qualified naming +do $$ <> declare c two_int8s; d nested_int8s; +begin + b.c := row(1,2); + b.d := row(b.c, row(b.c.q1, b.c.q2+1)); + raise notice 'b.c = %, b.d = %', b.c, b.d; + b.c.q1 := 10; + b.d.c1 := row(11,12); + b.d.c2.q2 := 42; + raise notice 'b.c = %, b.d = %', b.c, b.d; + raise notice 'b.c.q1 = %, b.d.c2 = %', b.c.q1, b.d.c2; + raise notice '(b.d).c2.q2 = %', (b.d).c2.q2; -- doesn't work without parens + raise notice '(b.d.c2).q2 = %', (b.d.c2).q2; -- doesn't work without parens +end$$; +NOTICE: b.c = (1,2), b.d = ("(1,2)","(1,3)") +NOTICE: b.c = (10,2), b.d = ("(11,12)","(1,42)") +NOTICE: b.c.q1 = 10, b.d.c2 = (1,42) +NOTICE: (b.d).c2.q2 = 42 +NOTICE: (b.d.c2).q2 = 42 +-- error cases +do $$ declare c two_int8s; begin c.x = 1; end $$; +ERROR: record "c" has no field "x" +CONTEXT: PL/pgSQL assignment "c.x = 1" +PL/pgSQL function inline_code_block line 1 at assignment +do $$ declare c nested_int8s; begin c.x = 1; end $$; +ERROR: record "c" has no field "x" +CONTEXT: PL/pgSQL assignment "c.x = 1" +PL/pgSQL function inline_code_block line 1 at assignment +do $$ declare c nested_int8s; begin c.x.q1 = 1; end $$; +ERROR: record "c" has no field "x" +CONTEXT: PL/pgSQL assignment "c.x.q1 = 1" +PL/pgSQL function inline_code_block line 1 at assignment +do $$ declare c nested_int8s; begin c.c2.x = 1; end $$; +ERROR: cannot assign to field "x" of column "c" because there is no such column in data type two_int8s +LINE 1: c.c2.x = 1 + ^ +QUERY: c.c2.x = 1 +CONTEXT: PL/pgSQL function inline_code_block line 1 at assignment +do $$ declare c nested_int8s; begin d.c2.x = 1; end $$; +ERROR: "d.c2.x" is not a known variable +LINE 1: do $$ declare c nested_int8s; begin d.c2.x = 1; end $$; + ^ +do $$ <> declare c two_int8s; begin b.c.x = 1; end $$; +ERROR: record "c" has no field "x" +CONTEXT: PL/pgSQL assignment "b.c.x = 1" +PL/pgSQL function inline_code_block line 1 at assignment +do $$ <> declare c nested_int8s; begin b.c.x = 1; end $$; +ERROR: record "c" has no field "x" +CONTEXT: PL/pgSQL assignment "b.c.x = 1" +PL/pgSQL function inline_code_block line 1 at assignment +do $$ <> declare c nested_int8s; begin b.c.x.q1 = 1; end $$; +ERROR: record "c" has no field "x" +CONTEXT: PL/pgSQL assignment "b.c.x.q1 = 1" +PL/pgSQL function inline_code_block line 1 at assignment +do $$ <> declare c nested_int8s; begin b.c.c2.x = 1; end $$; +ERROR: cannot assign to field "x" of column "b" because there is no such column in data type two_int8s +LINE 1: b.c.c2.x = 1 + ^ +QUERY: b.c.c2.x = 1 +CONTEXT: PL/pgSQL function inline_code_block line 1 at assignment +do $$ <> declare c nested_int8s; begin b.d.c2.x = 1; end $$; +ERROR: "b.d.c2" is not a known variable +LINE 1: do $$ <> declare c nested_int8s; begin b.d.c2.x = 1; end ... + ^ -- check passing composite result to another function create function getq1(two_int8s) returns int8 language plpgsql as $$ declare r two_int8s; begin r := $1; return r.q1; end $$; @@ -188,7 +271,7 @@ NOTICE: r1.q1 = NOTICE: r1.q2 = NOTICE: r1 = ERROR: record "r1" has no field "nosuchfield" -CONTEXT: SQL statement "SELECT r1.nosuchfield" +CONTEXT: SQL expression "r1.nosuchfield" PL/pgSQL function inline_code_block line 7 at RAISE -- records, not so much do $$ @@ -202,7 +285,7 @@ end$$; NOTICE: r1 = ERROR: record "r1" is not assigned yet DETAIL: The tuple structure of a not-yet-assigned record is indeterminate. -CONTEXT: SQL statement "SELECT r1.f1" +CONTEXT: SQL expression "r1.f1" PL/pgSQL function inline_code_block line 5 at RAISE -- but OK if you assign first do $$ @@ -220,7 +303,7 @@ NOTICE: r1.f1 = 1 NOTICE: r1.f2 = 2 NOTICE: r1 = (1,2) ERROR: record "r1" has no field "nosuchfield" -CONTEXT: SQL statement "SELECT r1.nosuchfield" +CONTEXT: SQL expression "r1.nosuchfield" PL/pgSQL function inline_code_block line 9 at RAISE -- check repeated assignments to composite fields create table some_table (id int, data text); @@ -431,7 +514,7 @@ create function getf3(x mutable) returns int language plpgsql as $$ begin return x.f3; end $$; select getf3(null::mutable); -- doesn't work yet ERROR: record "x" has no field "f3" -CONTEXT: SQL statement "SELECT x.f3" +CONTEXT: SQL expression "x.f3" PL/pgSQL function getf3(mutable) line 1 at RETURN alter table mutable add column f3 int; select getf3(null::mutable); -- now it works diff --git a/src/pl/plpgsql/src/expected/plpgsql_varprops.out b/src/pl/plpgsql/src/expected/plpgsql_varprops.out index 18f03d75b4268..3801dccc95a96 100644 --- a/src/pl/plpgsql/src/expected/plpgsql_varprops.out +++ b/src/pl/plpgsql/src/expected/plpgsql_varprops.out @@ -76,7 +76,7 @@ begin raise notice 'x = %', x; end$$; ERROR: division by zero -CONTEXT: SQL statement "SELECT 1/0" +CONTEXT: SQL expression "1/0" PL/pgSQL function inline_code_block line 3 during statement block local variable initialization do $$ declare x bigint[] := array[1,3,5]; diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 81979c2961b33..5336793a9335e 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -1458,7 +1458,8 @@ plpgsql_parse_dblword(char *word1, char *word2, /* * We should do nothing in DECLARE sections. In SQL expressions, we * really only need to make sure that RECFIELD datums are created when - * needed. + * needed. In all the cases handled by this function, returning a T_DATUM + * with a two-word idents string is the right thing. */ if (plpgsql_IdentifierLookup != IDENTIFIER_LOOKUP_DECLARE) { @@ -1532,40 +1533,53 @@ plpgsql_parse_tripword(char *word1, char *word2, char *word3, List *idents; int nnames; - idents = list_make3(makeString(word1), - makeString(word2), - makeString(word3)); - /* - * We should do nothing in DECLARE sections. In SQL expressions, we - * really only need to make sure that RECFIELD datums are created when - * needed. + * We should do nothing in DECLARE sections. In SQL expressions, we need + * to make sure that RECFIELD datums are created when needed, and we need + * to be careful about how many names are reported as belonging to the + * T_DATUM: the third word could be a sub-field reference, which we don't + * care about here. */ if (plpgsql_IdentifierLookup != IDENTIFIER_LOOKUP_DECLARE) { /* - * Do a lookup in the current namespace stack. Must find a qualified + * Do a lookup in the current namespace stack. Must find a record * reference, else ignore. */ ns = plpgsql_ns_lookup(plpgsql_ns_top(), false, word1, word2, word3, &nnames); - if (ns != NULL && nnames == 2) + if (ns != NULL) { switch (ns->itemtype) { case PLPGSQL_NSTYPE_REC: { - /* - * words 1/2 are a record name, so third word could be - * a field in this record. - */ PLpgSQL_rec *rec; PLpgSQL_recfield *new; rec = (PLpgSQL_rec *) (plpgsql_Datums[ns->itemno]); - new = plpgsql_build_recfield(rec, word3); - + if (nnames == 1) + { + /* + * First word is a record name, so second word + * could be a field in this record (and the third, + * a sub-field). We build a RECFIELD datum + * whether it is or not --- any error will be + * detected later. + */ + new = plpgsql_build_recfield(rec, word2); + idents = list_make2(makeString(word1), + makeString(word2)); + } + else + { + /* Block-qualified reference to record variable. */ + new = plpgsql_build_recfield(rec, word3); + idents = list_make3(makeString(word1), + makeString(word2), + makeString(word3)); + } wdatum->datum = (PLpgSQL_datum *) new; wdatum->ident = NULL; wdatum->quoted = false; /* not used */ @@ -1580,6 +1594,9 @@ plpgsql_parse_tripword(char *word1, char *word2, char *word3, } /* Nothing found */ + idents = list_make3(makeString(word1), + makeString(word2), + makeString(word3)); cword->idents = idents; return false; } diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 4a51fb6d9f101..5e4dbd25a2a77 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -4182,7 +4182,7 @@ exec_prepare_plan(PLpgSQL_execstate *estate, memset(&options, 0, sizeof(options)); options.parserSetup = (ParserSetupHook) plpgsql_parser_setup; options.parserSetupArg = (void *) expr; - options.parseMode = RAW_PARSE_DEFAULT; + options.parseMode = expr->parseMode; options.cursorOptions = cursorOptions; plan = SPI_prepare_extended(expr->query, &options); if (plan == NULL) @@ -8006,10 +8006,14 @@ get_cast_hashentry(PLpgSQL_execstate *estate, placeholder->collation = get_typcollation(srctype); /* - * Apply coercion. We use ASSIGNMENT coercion because that's the - * closest match to plpgsql's historical behavior; in particular, - * EXPLICIT coercion would allow silent truncation to a destination - * varchar/bpchar's length, which we do not want. + * Apply coercion. We use the special coercion context + * COERCION_PLPGSQL to match plpgsql's historical behavior, namely + * that any cast not available at ASSIGNMENT level will be implemented + * as an I/O coercion. (It's somewhat dubious that we prefer I/O + * coercion over cast pathways that exist at EXPLICIT level. Changing + * that would cause assorted minor behavioral differences though, and + * a user who wants the explicit-cast behavior can always write an + * explicit cast.) * * If source type is UNKNOWN, coerce_to_target_type will fail (it only * expects to see that for Const input nodes), so don't call it; we'll @@ -8022,7 +8026,7 @@ get_cast_hashentry(PLpgSQL_execstate *estate, cast_expr = coerce_to_target_type(NULL, (Node *) placeholder, srctype, dsttype, dsttypmod, - COERCION_ASSIGNMENT, + COERCION_PLPGSQL, COERCE_IMPLICIT_CAST, -1); @@ -8030,7 +8034,8 @@ get_cast_hashentry(PLpgSQL_execstate *estate, * If there's no cast path according to the parser, fall back to using * an I/O coercion; this is semantically dubious but matches plpgsql's * historical behavior. We would need something of the sort for - * UNKNOWN literals in any case. + * UNKNOWN literals in any case. (This is probably now only reachable + * in the case where srctype is UNKNOWN/RECORD.) */ if (cast_expr == NULL) { @@ -8339,7 +8344,8 @@ exec_check_rw_parameter(PLpgSQL_expr *expr, int target_dno) return; /* - * Top level of expression must be a simple FuncExpr or OpExpr. + * Top level of expression must be a simple FuncExpr, OpExpr, or + * SubscriptingRef. */ if (IsA(expr->expr_simple_expr, FuncExpr)) { @@ -8355,6 +8361,33 @@ exec_check_rw_parameter(PLpgSQL_expr *expr, int target_dno) funcid = opexpr->opfuncid; fargs = opexpr->args; } + else if (IsA(expr->expr_simple_expr, SubscriptingRef)) + { + SubscriptingRef *sbsref = (SubscriptingRef *) expr->expr_simple_expr; + + /* We only trust standard varlena arrays to be safe */ + if (get_typsubscript(sbsref->refcontainertype, NULL) != + F_ARRAY_SUBSCRIPT_HANDLER) + return; + + /* refexpr can be a simple Param, otherwise must not contain target */ + if (!(sbsref->refexpr && IsA(sbsref->refexpr, Param)) && + contains_target_param((Node *) sbsref->refexpr, &target_dno)) + return; + + /* the other subexpressions must not contain target */ + if (contains_target_param((Node *) sbsref->refupperindexpr, + &target_dno) || + contains_target_param((Node *) sbsref->reflowerindexpr, + &target_dno) || + contains_target_param((Node *) sbsref->refassgnexpr, + &target_dno)) + return; + + /* OK, we can pass target as a read-write parameter */ + expr->rwparam = target_dno; + return; + } else return; diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y index c09576efff501..ad248bc7648c9 100644 --- a/src/pl/plpgsql/src/pl_gram.y +++ b/src/pl/plpgsql/src/pl_gram.y @@ -51,7 +51,6 @@ typedef struct { int location; - int leaderlen; } sql_error_callback_arg; #define parser_errposition(pos) plpgsql_scanner_errposition(pos) @@ -67,7 +66,7 @@ static PLpgSQL_expr *read_sql_construct(int until, int until2, int until3, const char *expected, - const char *sqlstart, + RawParseMode parsemode, bool isexpression, bool valid_sql, bool trim, @@ -78,7 +77,7 @@ static PLpgSQL_expr *read_sql_expression(int until, static PLpgSQL_expr *read_sql_expression2(int until, int until2, const char *expected, int *endtoken); -static PLpgSQL_expr *read_sql_stmt(const char *sqlstart); +static PLpgSQL_expr *read_sql_stmt(void); static PLpgSQL_type *read_datatype(int tok); static PLpgSQL_stmt *make_execsql_stmt(int firsttoken, int location); static PLpgSQL_stmt_fetch *read_fetch_direction(void); @@ -99,8 +98,8 @@ static PLpgSQL_row *read_into_scalar_list(char *initial_name, static PLpgSQL_row *make_scalar_list1(char *initial_name, PLpgSQL_datum *initial_datum, int lineno, int location); -static void check_sql_expr(const char *stmt, int location, - int leaderlen); +static void check_sql_expr(const char *stmt, + RawParseMode parseMode, int location); static void plpgsql_sql_error_callback(void *arg); static PLpgSQL_type *parse_datatype(const char *string, int location); static void check_labels(const char *start_label, @@ -540,7 +539,7 @@ decl_statement : decl_varname decl_const decl_datatype decl_collate decl_notnull { PLpgSQL_var *new; PLpgSQL_expr *curname_def; - char buf[1024]; + char buf[NAMEDATALEN * 2 + 64]; char *cp1; char *cp2; @@ -557,9 +556,9 @@ decl_statement : decl_varname decl_const decl_datatype decl_collate decl_notnull curname_def = palloc0(sizeof(PLpgSQL_expr)); - strcpy(buf, "SELECT "); + /* Note: refname has been truncated to NAMEDATALEN */ cp1 = new->refname; - cp2 = buf + strlen(buf); + cp2 = buf; /* * Don't trust standard_conforming_strings here; * it might change before we use the string. @@ -575,6 +574,7 @@ decl_statement : decl_varname decl_const decl_datatype decl_collate decl_notnull } strcpy(cp2, "'::pg_catalog.refcursor"); curname_def->query = pstrdup(buf); + curname_def->parseMode = RAW_PARSE_PLPGSQL_EXPR; new->default_val = curname_def; new->cursor_explicit_expr = $7; @@ -602,7 +602,7 @@ opt_scrollable : decl_cursor_query : { - $$ = read_sql_stmt(""); + $$ = read_sql_stmt(); } ; @@ -904,15 +904,37 @@ proc_stmt : pl_block ';' { $$ = $1; } ; -stmt_perform : K_PERFORM expr_until_semi +stmt_perform : K_PERFORM { PLpgSQL_stmt_perform *new; + int startloc; new = palloc0(sizeof(PLpgSQL_stmt_perform)); new->cmd_type = PLPGSQL_STMT_PERFORM; new->lineno = plpgsql_location_to_lineno(@1); new->stmtid = ++plpgsql_curr_compile->nstatements; - new->expr = $2; + plpgsql_push_back_token(K_PERFORM); + + /* + * Since PERFORM isn't legal SQL, we have to cheat to + * the extent of substituting "SELECT" for "PERFORM" + * in the parsed text. It does not seem worth + * inventing a separate parse mode for this one case. + * We can't do syntax-checking until after we make the + * substitution. + */ + new->expr = read_sql_construct(';', 0, 0, ";", + RAW_PARSE_DEFAULT, + false, false, true, + &startloc, NULL); + /* overwrite "perform" ... */ + memcpy(new->expr->query, " SELECT", 7); + /* left-justify to get rid of the leading space */ + memmove(new->expr->query, new->expr->query + 1, + strlen(new->expr->query)); + /* offset syntax error position to account for that */ + check_sql_expr(new->expr->query, new->expr->parseMode, + startloc + 1); $$ = (PLpgSQL_stmt *)new; } @@ -926,7 +948,8 @@ stmt_call : K_CALL new->cmd_type = PLPGSQL_STMT_CALL; new->lineno = plpgsql_location_to_lineno(@1); new->stmtid = ++plpgsql_curr_compile->nstatements; - new->expr = read_sql_stmt("CALL "); + plpgsql_push_back_token(K_CALL); + new->expr = read_sql_stmt(); new->is_call = true; $$ = (PLpgSQL_stmt *)new; @@ -941,7 +964,8 @@ stmt_call : K_CALL new->cmd_type = PLPGSQL_STMT_CALL; new->lineno = plpgsql_location_to_lineno(@1); new->stmtid = ++plpgsql_curr_compile->nstatements; - new->expr = read_sql_stmt("DO "); + plpgsql_push_back_token(K_DO); + new->expr = read_sql_stmt(); new->is_call = false; $$ = (PLpgSQL_stmt *)new; @@ -949,16 +973,40 @@ stmt_call : K_CALL } ; -stmt_assign : assign_var assign_operator expr_until_semi +stmt_assign : T_DATUM { PLpgSQL_stmt_assign *new; + RawParseMode pmode; + + /* see how many names identify the datum */ + switch ($1.ident ? 1 : list_length($1.idents)) + { + case 1: + pmode = RAW_PARSE_PLPGSQL_ASSIGN1; + break; + case 2: + pmode = RAW_PARSE_PLPGSQL_ASSIGN2; + break; + case 3: + pmode = RAW_PARSE_PLPGSQL_ASSIGN3; + break; + default: + elog(ERROR, "unexpected number of names"); + pmode = 0; /* keep compiler quiet */ + } + check_assignable($1.datum, @1); new = palloc0(sizeof(PLpgSQL_stmt_assign)); new->cmd_type = PLPGSQL_STMT_ASSIGN; new->lineno = plpgsql_location_to_lineno(@1); new->stmtid = ++plpgsql_curr_compile->nstatements; - new->varno = $1->dno; - new->expr = $3; + new->varno = $1.datum->dno; + /* Push back the head name to include it in the stmt */ + plpgsql_push_back_token(T_DATUM); + new->expr = read_sql_construct(';', 0, 0, ";", + pmode, + false, true, true, + NULL, NULL); $$ = (PLpgSQL_stmt *)new; } @@ -1452,16 +1500,16 @@ for_control : for_variable K_IN /* * Read tokens until we see either a ".." - * or a LOOP. The text we read may not - * necessarily be a well-formed SQL - * statement, so we need to invoke - * read_sql_construct directly. + * or a LOOP. The text we read may be either + * an expression or a whole SQL statement, so + * we need to invoke read_sql_construct directly, + * and tell it not to check syntax yet. */ expr1 = read_sql_construct(DOT_DOT, K_LOOP, 0, "LOOP", - "SELECT ", + RAW_PARSE_DEFAULT, true, false, true, @@ -1476,8 +1524,13 @@ for_control : for_variable K_IN PLpgSQL_var *fvar; PLpgSQL_stmt_fori *new; - /* Check first expression is well-formed */ - check_sql_expr(expr1->query, expr1loc, 7); + /* + * Relabel first expression as an expression; + * then we can check its syntax. + */ + expr1->parseMode = RAW_PARSE_PLPGSQL_EXPR; + check_sql_expr(expr1->query, expr1->parseMode, + expr1loc); /* Read and check the second one */ expr2 = read_sql_expression2(K_LOOP, K_BY, @@ -1522,12 +1575,8 @@ for_control : for_variable K_IN else { /* - * No "..", so it must be a query loop. We've - * prefixed an extra SELECT to the query text, - * so we need to remove that before performing - * syntax checking. + * No "..", so it must be a query loop. */ - char *tmp_query; PLpgSQL_stmt_fors *new; if (reverse) @@ -1536,12 +1585,9 @@ for_control : for_variable K_IN errmsg("cannot specify REVERSE in query FOR loop"), parser_errposition(tokloc))); - Assert(strncmp(expr1->query, "SELECT ", 7) == 0); - tmp_query = pstrdup(expr1->query + 7); - pfree(expr1->query); - expr1->query = tmp_query; - - check_sql_expr(expr1->query, expr1loc, 0); + /* Check syntax as a regular query */ + check_sql_expr(expr1->query, expr1->parseMode, + expr1loc); new = palloc0(sizeof(PLpgSQL_stmt_fors)); new->cmd_type = PLPGSQL_STMT_FORS; @@ -1870,7 +1916,7 @@ stmt_raise : K_RAISE expr = read_sql_construct(',', ';', K_USING, ", or ; or USING", - "SELECT ", + RAW_PARSE_PLPGSQL_EXPR, true, true, true, NULL, &tok); new->params = lappend(new->params, expr); @@ -1958,7 +2004,7 @@ loop_body : proc_sect K_END K_LOOP opt_label ';' * variable. (The composite case is probably a syntax error, but we'll let * the core parser decide that.) Normally, we should assume that such a * word is a SQL statement keyword that isn't also a plpgsql keyword. - * However, if the next token is assignment or '[', it can't be a valid + * However, if the next token is assignment or '[' or '.', it can't be a valid * SQL statement, and what we're probably looking at is an intended variable * assignment. Give an appropriate complaint for that, instead of letting * the core parser throw an unhelpful "syntax error". @@ -1977,7 +2023,8 @@ stmt_execsql : K_IMPORT tok = yylex(); plpgsql_push_back_token(tok); - if (tok == '=' || tok == COLON_EQUALS || tok == '[') + if (tok == '=' || tok == COLON_EQUALS || + tok == '[' || tok == '.') word_is_not_variable(&($1), @1); $$ = make_execsql_stmt(T_WORD, @1); } @@ -1987,7 +2034,8 @@ stmt_execsql : K_IMPORT tok = yylex(); plpgsql_push_back_token(tok); - if (tok == '=' || tok == COLON_EQUALS || tok == '[') + if (tok == '=' || tok == COLON_EQUALS || + tok == '[' || tok == '.') cword_is_not_variable(&($1), @1); $$ = make_execsql_stmt(T_CWORD, @1); } @@ -2001,7 +2049,7 @@ stmt_dynexecute : K_EXECUTE expr = read_sql_construct(K_INTO, K_USING, ';', "INTO or USING or ;", - "SELECT ", + RAW_PARSE_PLPGSQL_EXPR, true, true, true, NULL, &endtoken); @@ -2040,7 +2088,7 @@ stmt_dynexecute : K_EXECUTE { expr = read_sql_construct(',', ';', K_INTO, ", or ; or INTO", - "SELECT ", + RAW_PARSE_PLPGSQL_EXPR, true, true, true, NULL, &endtoken); new->params = lappend(new->params, expr); @@ -2122,7 +2170,7 @@ stmt_open : K_OPEN cursor_variable else { plpgsql_push_back_token(tok); - new->query = read_sql_stmt(""); + new->query = read_sql_stmt(); } } else @@ -2246,8 +2294,8 @@ stmt_set : K_SET new->cmd_type = PLPGSQL_STMT_SET; new->lineno = plpgsql_location_to_lineno(@1); new->stmtid = ++plpgsql_curr_compile->nstatements; - - new->expr = read_sql_stmt("SET "); + plpgsql_push_back_token(K_SET); + new->expr = read_sql_stmt(); $$ = (PLpgSQL_stmt *)new; } @@ -2259,7 +2307,8 @@ stmt_set : K_SET new->cmd_type = PLPGSQL_STMT_SET; new->lineno = plpgsql_location_to_lineno(@1); new->stmtid = ++plpgsql_curr_compile->nstatements; - new->expr = read_sql_stmt("RESET "); + plpgsql_push_back_token(K_RESET); + new->expr = read_sql_stmt(); $$ = (PLpgSQL_stmt *)new; } @@ -2656,7 +2705,8 @@ static PLpgSQL_expr * read_sql_expression(int until, const char *expected) { return read_sql_construct(until, 0, 0, expected, - "SELECT ", true, true, true, NULL, NULL); + RAW_PARSE_PLPGSQL_EXPR, + true, true, true, NULL, NULL); } /* Convenience routine to read an expression with two possible terminators */ @@ -2665,15 +2715,17 @@ read_sql_expression2(int until, int until2, const char *expected, int *endtoken) { return read_sql_construct(until, until2, 0, expected, - "SELECT ", true, true, true, NULL, endtoken); + RAW_PARSE_PLPGSQL_EXPR, + true, true, true, NULL, endtoken); } /* Convenience routine to read a SQL statement that must end with ';' */ static PLpgSQL_expr * -read_sql_stmt(const char *sqlstart) +read_sql_stmt(void) { return read_sql_construct(';', 0, 0, ";", - sqlstart, false, true, true, NULL, NULL); + RAW_PARSE_DEFAULT, + false, true, true, NULL, NULL); } /* @@ -2683,9 +2735,9 @@ read_sql_stmt(const char *sqlstart) * until2: token code for alternate terminator (pass 0 if none) * until3: token code for another alternate terminator (pass 0 if none) * expected: text to use in complaining that terminator was not found - * sqlstart: text to prefix to the accumulated SQL text + * parsemode: raw_parser() mode to use * isexpression: whether to say we're reading an "expression" or a "statement" - * valid_sql: whether to check the syntax of the expr (prefixed with sqlstart) + * valid_sql: whether to check the syntax of the expr * trim: trim trailing whitespace * startloc: if not NULL, location of first token is stored at *startloc * endtoken: if not NULL, ending token is stored at *endtoken @@ -2696,7 +2748,7 @@ read_sql_construct(int until, int until2, int until3, const char *expected, - const char *sqlstart, + RawParseMode parsemode, bool isexpression, bool valid_sql, bool trim, @@ -2711,7 +2763,6 @@ read_sql_construct(int until, PLpgSQL_expr *expr; initStringInfo(&ds); - appendStringInfoString(&ds, sqlstart); /* special lookup mode for identifiers within the SQL text */ save_IdentifierLookup = plpgsql_IdentifierLookup; @@ -2787,6 +2838,7 @@ read_sql_construct(int until, expr = palloc0(sizeof(PLpgSQL_expr)); expr->query = pstrdup(ds.data); + expr->parseMode = parsemode; expr->plan = NULL; expr->paramnos = NULL; expr->rwparam = -1; @@ -2794,7 +2846,7 @@ read_sql_construct(int until, pfree(ds.data); if (valid_sql) - check_sql_expr(expr->query, startlocation, strlen(sqlstart)); + check_sql_expr(expr->query, expr->parseMode, startlocation); return expr; } @@ -3033,13 +3085,14 @@ make_execsql_stmt(int firsttoken, int location) expr = palloc0(sizeof(PLpgSQL_expr)); expr->query = pstrdup(ds.data); + expr->parseMode = RAW_PARSE_DEFAULT; expr->plan = NULL; expr->paramnos = NULL; expr->rwparam = -1; expr->ns = plpgsql_ns_top(); pfree(ds.data); - check_sql_expr(expr->query, location, 0); + check_sql_expr(expr->query, expr->parseMode, location); execsql = palloc(sizeof(PLpgSQL_stmt_execsql)); execsql->cmd_type = PLPGSQL_STMT_EXECSQL; @@ -3382,7 +3435,7 @@ make_return_query_stmt(int location) { /* ordinary static query */ plpgsql_push_back_token(tok); - new->query = read_sql_stmt(""); + new->query = read_sql_stmt(); } else { @@ -3637,13 +3690,12 @@ make_scalar_list1(char *initial_name, * borders. So it is best to bail out as early as we can. * * It is assumed that "stmt" represents a copy of the function source text - * beginning at offset "location", with leader text of length "leaderlen" - * (typically "SELECT ") prefixed to the source text. We use this assumption - * to transpose any error cursor position back to the function source text. + * beginning at offset "location". We use this assumption to transpose + * any error cursor position back to the function source text. * If no error cursor is provided, we'll just point at "location". */ static void -check_sql_expr(const char *stmt, int location, int leaderlen) +check_sql_expr(const char *stmt, RawParseMode parseMode, int location) { sql_error_callback_arg cbarg; ErrorContextCallback syntax_errcontext; @@ -3653,7 +3705,6 @@ check_sql_expr(const char *stmt, int location, int leaderlen) return; cbarg.location = location; - cbarg.leaderlen = leaderlen; syntax_errcontext.callback = plpgsql_sql_error_callback; syntax_errcontext.arg = &cbarg; @@ -3661,7 +3712,7 @@ check_sql_expr(const char *stmt, int location, int leaderlen) error_context_stack = &syntax_errcontext; oldCxt = MemoryContextSwitchTo(plpgsql_compile_tmp_cxt); - (void) raw_parser(stmt, RAW_PARSE_DEFAULT); + (void) raw_parser(stmt, parseMode); MemoryContextSwitchTo(oldCxt); /* Restore former ereport callback */ @@ -3686,12 +3737,12 @@ plpgsql_sql_error_callback(void *arg) * Note we are dealing with 1-based character numbers at this point. */ errpos = geterrposition(); - if (errpos > cbarg->leaderlen) + if (errpos > 0) { int myerrpos = getinternalerrposition(); if (myerrpos > 0) /* safety check */ - internalerrposition(myerrpos + errpos - cbarg->leaderlen - 1); + internalerrposition(myerrpos + errpos - 1); } /* In any case, flush errposition --- we want internalerrposition only */ @@ -3717,7 +3768,6 @@ parse_datatype(const char *string, int location) ErrorContextCallback syntax_errcontext; cbarg.location = location; - cbarg.leaderlen = 0; syntax_errcontext.callback = plpgsql_sql_error_callback; syntax_errcontext.arg = &cbarg; @@ -3780,7 +3830,6 @@ read_cursor_args(PLpgSQL_var *cursor, int until) int argc; char **argv; StringInfoData ds; - char *sqlstart = "SELECT "; bool any_named = false; tok = yylex(); @@ -3881,12 +3930,12 @@ read_cursor_args(PLpgSQL_var *cursor, int until) */ item = read_sql_construct(',', ')', 0, ",\" or \")", - sqlstart, + RAW_PARSE_PLPGSQL_EXPR, true, true, false, /* do not trim */ NULL, &endtoken); - argv[argpos] = item->query + strlen(sqlstart); + argv[argpos] = item->query; if (endtoken == ')' && !(argc == row->nfields - 1)) ereport(ERROR, @@ -3905,7 +3954,6 @@ read_cursor_args(PLpgSQL_var *cursor, int until) /* Make positional argument list */ initStringInfo(&ds); - appendStringInfoString(&ds, sqlstart); for (argc = 0; argc < row->nfields; argc++) { Assert(argv[argc] != NULL); @@ -3921,10 +3969,10 @@ read_cursor_args(PLpgSQL_var *cursor, int until) if (argc < row->nfields - 1) appendStringInfoString(&ds, ", "); } - appendStringInfoChar(&ds, ';'); expr = palloc0(sizeof(PLpgSQL_expr)); expr->query = pstrdup(ds.data); + expr->parseMode = RAW_PARSE_PLPGSQL_EXPR; expr->plan = NULL; expr->paramnos = NULL; expr->rwparam = -1; @@ -4097,14 +4145,14 @@ make_case(int location, PLpgSQL_expr *t_expr, PLpgSQL_expr *expr = cwt->expr; StringInfoData ds; - /* copy expression query without SELECT keyword (expr->query + 7) */ - Assert(strncmp(expr->query, "SELECT ", 7) == 0); + /* We expect to have expressions not statements */ + Assert(expr->parseMode == RAW_PARSE_PLPGSQL_EXPR); - /* And do the string hacking */ + /* Do the string hacking */ initStringInfo(&ds); - appendStringInfo(&ds, "SELECT \"%s\" IN (%s)", - varname, expr->query + 7); + appendStringInfo(&ds, "\"%s\" IN (%s)", + varname, expr->query); pfree(expr->query); expr->query = pstrdup(ds.data); diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index dee175b7bf65a..f80d023a5ad55 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -218,8 +218,9 @@ typedef struct PLpgSQL_type */ typedef struct PLpgSQL_expr { - char *query; - SPIPlanPtr plan; + char *query; /* query string, verbatim from function body */ + RawParseMode parseMode; /* raw_parser() mode to use */ + SPIPlanPtr plan; /* plan, or NULL if not made yet */ Bitmapset *paramnos; /* all dnos referenced by this query */ int rwparam; /* dno of read/write param, or -1 if none */ diff --git a/src/pl/plpgsql/src/sql/plpgsql_array.sql b/src/pl/plpgsql/src/sql/plpgsql_array.sql new file mode 100644 index 0000000000000..4c3f26be1011d --- /dev/null +++ b/src/pl/plpgsql/src/sql/plpgsql_array.sql @@ -0,0 +1,79 @@ +-- +-- Tests for PL/pgSQL handling of array variables +-- +-- We also check arrays of composites here, so this has some overlap +-- with the plpgsql_record tests. +-- + +create type complex as (r float8, i float8); +create type quadarray as (c1 complex[], c2 complex); + +do $$ declare a int[]; +begin a := array[1,2]; a[3] := 4; raise notice 'a = %', a; end$$; + +do $$ declare a int[]; +begin a[3] := 4; raise notice 'a = %', a; end$$; + +do $$ declare a int[]; +begin a[1][4] := 4; raise notice 'a = %', a; end$$; + +do $$ declare a int[]; +begin a[1] := 23::text; raise notice 'a = %', a; end$$; -- lax typing + +do $$ declare a int[]; +begin a := array[1,2]; a[2:3] := array[3,4]; raise notice 'a = %', a; end$$; + +do $$ declare a int[]; +begin a := array[1,2]; a[2] := a[2] + 1; raise notice 'a = %', a; end$$; + +do $$ declare a int[]; +begin a[1:2] := array[3,4]; raise notice 'a = %', a; end$$; + +do $$ declare a int[]; +begin a[1:2] := 4; raise notice 'a = %', a; end$$; -- error + +do $$ declare a complex[]; +begin a[1] := (1,2); a[1].i := 11; raise notice 'a = %', a; end$$; + +do $$ declare a complex[]; +begin a[1].i := 11; raise notice 'a = %, a[1].i = %', a, a[1].i; end$$; + +-- perhaps this ought to work, but for now it doesn't: +do $$ declare a complex[]; +begin a[1:2].i := array[11,12]; raise notice 'a = %', a; end$$; + +do $$ declare a quadarray; +begin a.c1[1].i := 11; raise notice 'a = %, a.c1[1].i = %', a, a.c1[1].i; end$$; + +do $$ declare a int[]; +begin a := array_agg(x) from (values(1),(2),(3)) v(x); raise notice 'a = %', a; end$$; + +create temp table onecol as select array[1,2] as f1; + +do $$ declare a int[]; +begin a := f1 from onecol; raise notice 'a = %', a; end$$; + +do $$ declare a int[]; +begin a := * from onecol for update; raise notice 'a = %', a; end$$; + +-- error cases: + +do $$ declare a int[]; +begin a := from onecol; raise notice 'a = %', a; end$$; + +do $$ declare a int[]; +begin a := f1, f1 from onecol; raise notice 'a = %', a; end$$; + +insert into onecol values(array[11]); + +do $$ declare a int[]; +begin a := f1 from onecol; raise notice 'a = %', a; end$$; + +do $$ declare a int[]; +begin a := f1 from onecol limit 1; raise notice 'a = %', a; end$$; + +do $$ declare a real; +begin a[1] := 2; raise notice 'a = %', a; end$$; + +do $$ declare a complex; +begin a.r[1] := 2; raise notice 'a = %', a; end$$; diff --git a/src/pl/plpgsql/src/sql/plpgsql_record.sql b/src/pl/plpgsql/src/sql/plpgsql_record.sql index 128846e610823..be10f00b1e6e4 100644 --- a/src/pl/plpgsql/src/sql/plpgsql_record.sql +++ b/src/pl/plpgsql/src/sql/plpgsql_record.sql @@ -4,6 +4,7 @@ create type two_int4s as (f1 int4, f2 int4); create type two_int8s as (q1 int8, q2 int8); +create type nested_int8s as (c1 two_int8s, c2 two_int8s); -- base-case return of a composite type create function retc(int) returns two_int8s language plpgsql as @@ -59,6 +60,47 @@ begin raise notice 'c8 = %', c8; end$$; +do $$ declare c two_int8s; d nested_int8s; +begin + c := row(1,2); + d := row(c, row(c.q1, c.q2+1)); + raise notice 'c = %, d = %', c, d; + c.q1 := 10; + d.c1 := row(11,12); + d.c2.q2 := 42; + raise notice 'c = %, d = %', c, d; + raise notice 'c.q1 = %, d.c2 = %', c.q1, d.c2; + raise notice '(d).c2.q2 = %', (d).c2.q2; -- doesn't work without parens + raise notice '(d.c2).q2 = %', (d.c2).q2; -- doesn't work without parens +end$$; + +-- block-qualified naming +do $$ <> declare c two_int8s; d nested_int8s; +begin + b.c := row(1,2); + b.d := row(b.c, row(b.c.q1, b.c.q2+1)); + raise notice 'b.c = %, b.d = %', b.c, b.d; + b.c.q1 := 10; + b.d.c1 := row(11,12); + b.d.c2.q2 := 42; + raise notice 'b.c = %, b.d = %', b.c, b.d; + raise notice 'b.c.q1 = %, b.d.c2 = %', b.c.q1, b.d.c2; + raise notice '(b.d).c2.q2 = %', (b.d).c2.q2; -- doesn't work without parens + raise notice '(b.d.c2).q2 = %', (b.d.c2).q2; -- doesn't work without parens +end$$; + +-- error cases +do $$ declare c two_int8s; begin c.x = 1; end $$; +do $$ declare c nested_int8s; begin c.x = 1; end $$; +do $$ declare c nested_int8s; begin c.x.q1 = 1; end $$; +do $$ declare c nested_int8s; begin c.c2.x = 1; end $$; +do $$ declare c nested_int8s; begin d.c2.x = 1; end $$; +do $$ <> declare c two_int8s; begin b.c.x = 1; end $$; +do $$ <> declare c nested_int8s; begin b.c.x = 1; end $$; +do $$ <> declare c nested_int8s; begin b.c.x.q1 = 1; end $$; +do $$ <> declare c nested_int8s; begin b.c.c2.x = 1; end $$; +do $$ <> declare c nested_int8s; begin b.d.c2.x = 1; end $$; + -- check passing composite result to another function create function getq1(two_int8s) returns int8 language plpgsql as $$ declare r two_int8s; begin r := $1; return r.q1; end $$; diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out index d55006d8c950a..0c6c9ba1f59ff 100644 --- a/src/test/regress/expected/plpgsql.out +++ b/src/test/regress/expected/plpgsql.out @@ -1761,10 +1761,10 @@ select f1(42) as int, f1(4.5) as num; select f1(point(3,4)); -- fail for lack of + operator ERROR: operator does not exist: point + integer -LINE 1: SELECT x + 1 - ^ +LINE 1: x + 1 + ^ HINT: No operator matches the given name and argument types. You might need to add explicit type casts. -QUERY: SELECT x + 1 +QUERY: x + 1 CONTEXT: PL/pgSQL function f1(anyelement) line 3 at RETURN drop function f1(x anyelement); create function f1(x anyelement) returns anyarray as $$ @@ -2361,7 +2361,7 @@ begin end $$ language plpgsql; select namedparmcursor_test7(); ERROR: division by zero -CONTEXT: SQL statement "SELECT 42/0 AS p1, 77 AS p2;" +CONTEXT: SQL expression "42/0 AS p1, 77 AS p2" PL/pgSQL function namedparmcursor_test7() line 6 at OPEN -- check that line comments work correctly within the argument list (there -- is some special handling of this case in the code: the newline after the @@ -2574,9 +2574,9 @@ end; $$ language plpgsql; -- blocks select excpt_test1(); ERROR: column "sqlstate" does not exist -LINE 1: SELECT sqlstate - ^ -QUERY: SELECT sqlstate +LINE 1: sqlstate + ^ +QUERY: sqlstate CONTEXT: PL/pgSQL function excpt_test1() line 3 at RAISE create function excpt_test2() returns void as $$ begin @@ -2589,9 +2589,9 @@ end; $$ language plpgsql; -- should fail select excpt_test2(); ERROR: column "sqlstate" does not exist -LINE 1: SELECT sqlstate - ^ -QUERY: SELECT sqlstate +LINE 1: sqlstate + ^ +QUERY: sqlstate CONTEXT: PL/pgSQL function excpt_test2() line 5 at RAISE create function excpt_test3() returns void as $$ begin @@ -4467,11 +4467,11 @@ end $$; select fail(); ERROR: division by zero -CONTEXT: SQL statement "SELECT 1/0" +CONTEXT: SQL expression "1/0" PL/pgSQL function fail() line 3 at RETURN select fail(); ERROR: division by zero -CONTEXT: SQL statement "SELECT 1/0" +CONTEXT: SQL expression "1/0" PL/pgSQL function fail() line 3 at RETURN drop function fail(); -- Test handling of string literals. @@ -4497,10 +4497,10 @@ HINT: Use the escape string syntax for backslashes, e.g., E'\\'. select strtest(); NOTICE: foo\bar!baz WARNING: nonstandard use of \\ in a string literal -LINE 1: SELECT 'foo\\bar\041baz' - ^ +LINE 1: 'foo\\bar\041baz' + ^ HINT: Use the escape string syntax for backslashes, e.g., E'\\'. -QUERY: SELECT 'foo\\bar\041baz' +QUERY: 'foo\\bar\041baz' strtest ------------- foo\bar!baz @@ -5621,9 +5621,9 @@ ALTER TABLE alter_table_under_transition_tables UPDATE alter_table_under_transition_tables SET id = id; ERROR: column "name" does not exist -LINE 1: SELECT (SELECT string_agg(id || '=' || name, ',') FROM d) - ^ -QUERY: SELECT (SELECT string_agg(id || '=' || name, ',') FROM d) +LINE 1: (SELECT string_agg(id || '=' || name, ',') FROM d) + ^ +QUERY: (SELECT string_agg(id || '=' || name, ',') FROM d) CONTEXT: PL/pgSQL function alter_table_under_transition_tables_upd_func() line 3 at RAISE -- -- Test multiple reference to a transition table From 1788828d33516809fa2d842bf6e273d78e21d957 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 4 Jan 2021 12:14:37 -0500 Subject: [PATCH 026/240] Remove PLPGSQL_DTYPE_ARRAYELEM datum type within pl/pgsql. In the wake of the previous commit, we don't really need this anymore, since array assignment is primarily handled by the core code. The only way that that code could still be reached is that a GET DIAGNOSTICS target variable could be an array element. But that doesn't seem like a particularly essential feature. I'd added it in commit 55caaaeba, but just because it was easy not because anyone had actually asked for it. Hence, revert that patch and then remove the now-unreachable stuff. (If we really had to, we could probably reimplement GET DIAGNOSTICS using the new assignment machinery; but the cost/benefit ratio looks very poor, and it'd likely be a bit slower.) Note that PLPGSQL_DTYPE_RECFIELD remains. It's possible that we could get rid of that too, but maintaining the existing behaviors for RECORD-type variables seems like it might be difficult. Since there's not any functional limitation in those code paths as there was in the ARRAYELEM code, I've not pursued the idea. Discussion: https://postgr.es/m/4165684.1607707277@sss.pgh.pa.us --- src/pl/plpgsql/src/pl_exec.c | 204 +------------------------- src/pl/plpgsql/src/pl_funcs.c | 9 -- src/pl/plpgsql/src/pl_gram.y | 52 ++----- src/pl/plpgsql/src/plpgsql.h | 27 +--- src/test/regress/expected/plpgsql.out | 10 +- src/test/regress/sql/plpgsql.sql | 10 +- 6 files changed, 26 insertions(+), 286 deletions(-) diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 5e4dbd25a2a77..95f0adc81d9f4 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -1311,12 +1311,11 @@ copy_plpgsql_datums(PLpgSQL_execstate *estate, case PLPGSQL_DTYPE_ROW: case PLPGSQL_DTYPE_RECFIELD: - case PLPGSQL_DTYPE_ARRAYELEM: /* * These datum records are read-only at runtime, so no need to - * copy them (well, RECFIELD and ARRAYELEM contain cached - * data, but we'd just as soon centralize the caching anyway). + * copy them (well, RECFIELD contains cached data, but we'd + * just as soon centralize the caching anyway). */ outdatum = indatum; break; @@ -4136,9 +4135,6 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate, * * NB: the result of the evaluation is no longer valid after this is done, * unless it is a pass-by-value datatype. - * - * NB: if you change this code, see also the hacks in exec_assign_value's - * PLPGSQL_DTYPE_ARRAYELEM case for partial cleanup after subscript evals. * ---------- */ static void @@ -5288,198 +5284,6 @@ exec_assign_value(PLpgSQL_execstate *estate, break; } - case PLPGSQL_DTYPE_ARRAYELEM: - { - /* - * Target is an element of an array - */ - PLpgSQL_arrayelem *arrayelem; - int nsubscripts; - int i; - PLpgSQL_expr *subscripts[MAXDIM]; - int subscriptvals[MAXDIM]; - Datum oldarraydatum, - newarraydatum, - coerced_value; - bool oldarrayisnull; - Oid parenttypoid; - int32 parenttypmod; - SPITupleTable *save_eval_tuptable; - MemoryContext oldcontext; - - /* - * We need to do subscript evaluation, which might require - * evaluating general expressions; and the caller might have - * done that too in order to prepare the input Datum. We have - * to save and restore the caller's SPI_execute result, if - * any. - */ - save_eval_tuptable = estate->eval_tuptable; - estate->eval_tuptable = NULL; - - /* - * To handle constructs like x[1][2] := something, we have to - * be prepared to deal with a chain of arrayelem datums. Chase - * back to find the base array datum, and save the subscript - * expressions as we go. (We are scanning right to left here, - * but want to evaluate the subscripts left-to-right to - * minimize surprises.) Note that arrayelem is left pointing - * to the leftmost arrayelem datum, where we will cache the - * array element type data. - */ - nsubscripts = 0; - do - { - arrayelem = (PLpgSQL_arrayelem *) target; - if (nsubscripts >= MAXDIM) - ereport(ERROR, - (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), - errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)", - nsubscripts + 1, MAXDIM))); - subscripts[nsubscripts++] = arrayelem->subscript; - target = estate->datums[arrayelem->arrayparentno]; - } while (target->dtype == PLPGSQL_DTYPE_ARRAYELEM); - - /* Fetch current value of array datum */ - exec_eval_datum(estate, target, - &parenttypoid, &parenttypmod, - &oldarraydatum, &oldarrayisnull); - - /* Update cached type data if necessary */ - if (arrayelem->parenttypoid != parenttypoid || - arrayelem->parenttypmod != parenttypmod) - { - Oid arraytypoid; - int32 arraytypmod = parenttypmod; - int16 arraytyplen; - Oid elemtypoid; - int16 elemtyplen; - bool elemtypbyval; - char elemtypalign; - - /* If target is domain over array, reduce to base type */ - arraytypoid = getBaseTypeAndTypmod(parenttypoid, - &arraytypmod); - - /* ... and identify the element type */ - elemtypoid = get_element_type(arraytypoid); - if (!OidIsValid(elemtypoid)) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("subscripted object is not an array"))); - - /* Collect needed data about the types */ - arraytyplen = get_typlen(arraytypoid); - - get_typlenbyvalalign(elemtypoid, - &elemtyplen, - &elemtypbyval, - &elemtypalign); - - /* Now safe to update the cached data */ - arrayelem->parenttypoid = parenttypoid; - arrayelem->parenttypmod = parenttypmod; - arrayelem->arraytypoid = arraytypoid; - arrayelem->arraytypmod = arraytypmod; - arrayelem->arraytyplen = arraytyplen; - arrayelem->elemtypoid = elemtypoid; - arrayelem->elemtyplen = elemtyplen; - arrayelem->elemtypbyval = elemtypbyval; - arrayelem->elemtypalign = elemtypalign; - } - - /* - * Evaluate the subscripts, switch into left-to-right order. - * Like the expression built by ExecInitSubscriptingRef(), - * complain if any subscript is null. - */ - for (i = 0; i < nsubscripts; i++) - { - bool subisnull; - - subscriptvals[i] = - exec_eval_integer(estate, - subscripts[nsubscripts - 1 - i], - &subisnull); - if (subisnull) - ereport(ERROR, - (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("array subscript in assignment must not be null"))); - - /* - * Clean up in case the subscript expression wasn't - * simple. We can't do exec_eval_cleanup, but we can do - * this much (which is safe because the integer subscript - * value is surely pass-by-value), and we must do it in - * case the next subscript expression isn't simple either. - */ - if (estate->eval_tuptable != NULL) - SPI_freetuptable(estate->eval_tuptable); - estate->eval_tuptable = NULL; - } - - /* Now we can restore caller's SPI_execute result if any. */ - Assert(estate->eval_tuptable == NULL); - estate->eval_tuptable = save_eval_tuptable; - - /* Coerce source value to match array element type. */ - coerced_value = exec_cast_value(estate, - value, - &isNull, - valtype, - valtypmod, - arrayelem->elemtypoid, - arrayelem->arraytypmod); - - /* - * If the original array is null, cons up an empty array so - * that the assignment can proceed; we'll end with a - * one-element array containing just the assigned-to - * subscript. This only works for varlena arrays, though; for - * fixed-length array types we skip the assignment. We can't - * support assignment of a null entry into a fixed-length - * array, either, so that's a no-op too. This is all ugly but - * corresponds to the current behavior of execExpr*.c. - */ - if (arrayelem->arraytyplen > 0 && /* fixed-length array? */ - (oldarrayisnull || isNull)) - return; - - /* empty array, if any, and newarraydatum are short-lived */ - oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); - - if (oldarrayisnull) - oldarraydatum = PointerGetDatum(construct_empty_array(arrayelem->elemtypoid)); - - /* - * Build the modified array value. - */ - newarraydatum = array_set_element(oldarraydatum, - nsubscripts, - subscriptvals, - coerced_value, - isNull, - arrayelem->arraytyplen, - arrayelem->elemtyplen, - arrayelem->elemtypbyval, - arrayelem->elemtypalign); - - MemoryContextSwitchTo(oldcontext); - - /* - * Assign the new array to the base variable. It's never NULL - * at this point. Note that if the target is a domain, - * coercing the base array type back up to the domain will - * happen within exec_assign_value. - */ - exec_assign_value(estate, target, - newarraydatum, - false, - arrayelem->arraytypoid, - arrayelem->arraytypmod); - break; - } - default: elog(ERROR, "unrecognized dtype: %d", target->dtype); } @@ -5490,8 +5294,8 @@ exec_assign_value(PLpgSQL_execstate *estate, * * The type oid, typmod, value in Datum format, and null flag are returned. * - * At present this doesn't handle PLpgSQL_expr or PLpgSQL_arrayelem datums; - * that's not needed because we never pass references to such datums to SPI. + * At present this doesn't handle PLpgSQL_expr datums; that's not needed + * because we never pass references to such datums to SPI. * * NOTE: the returned Datum points right at the stored value in the case of * pass-by-reference datatypes. Generally callers should take care not to diff --git a/src/pl/plpgsql/src/pl_funcs.c b/src/pl/plpgsql/src/pl_funcs.c index ac72bfa8c03d0..919b968826c04 100644 --- a/src/pl/plpgsql/src/pl_funcs.c +++ b/src/pl/plpgsql/src/pl_funcs.c @@ -768,9 +768,6 @@ plpgsql_free_function_memory(PLpgSQL_function *func) break; case PLPGSQL_DTYPE_RECFIELD: break; - case PLPGSQL_DTYPE_ARRAYELEM: - free_expr(((PLpgSQL_arrayelem *) d)->subscript); - break; default: elog(ERROR, "unrecognized data type: %d", d->dtype); } @@ -1704,12 +1701,6 @@ plpgsql_dumptree(PLpgSQL_function *func) ((PLpgSQL_recfield *) d)->fieldname, ((PLpgSQL_recfield *) d)->recparentno); break; - case PLPGSQL_DTYPE_ARRAYELEM: - printf("ARRAYELEM of VAR %d subscript ", - ((PLpgSQL_arrayelem *) d)->arrayparentno); - dump_expr(((PLpgSQL_arrayelem *) d)->subscript); - printf("\n"); - break; default: printf("??? unknown data type %d\n", d->dtype); } diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y index ad248bc7648c9..0fdbaa5eab86e 100644 --- a/src/pl/plpgsql/src/pl_gram.y +++ b/src/pl/plpgsql/src/pl_gram.y @@ -177,11 +177,10 @@ static void check_raise_parameters(PLpgSQL_stmt_raise *stmt); %type decl_cursor_arglist %type decl_aliasitem -%type expr_until_semi expr_until_rightbracket +%type expr_until_semi %type expr_until_then expr_until_loop opt_expr_until_when %type opt_exitcond -%type assign_var %type cursor_variable %type decl_cursor_arg %type for_variable @@ -1155,16 +1154,23 @@ getdiag_item : } ; -getdiag_target : assign_var +getdiag_target : T_DATUM { - if ($1->dtype == PLPGSQL_DTYPE_ROW || - $1->dtype == PLPGSQL_DTYPE_REC) + /* + * In principle we should support a getdiag_target + * that is an array element, but for now we don't, so + * just throw an error if next token is '['. + */ + if ($1.datum->dtype == PLPGSQL_DTYPE_ROW || + $1.datum->dtype == PLPGSQL_DTYPE_REC || + plpgsql_peek() == '[') ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("\"%s\" is not a scalar variable", - ((PLpgSQL_variable *) $1)->refname), + NameOfDatum(&($1))), parser_errposition(@1))); - $$ = $1; + check_assignable($1.datum, @1); + $$ = $1.datum; } | T_WORD { @@ -1178,29 +1184,6 @@ getdiag_target : assign_var } ; - -assign_var : T_DATUM - { - check_assignable($1.datum, @1); - $$ = $1.datum; - } - | assign_var '[' expr_until_rightbracket - { - PLpgSQL_arrayelem *new; - - new = palloc0(sizeof(PLpgSQL_arrayelem)); - new->dtype = PLPGSQL_DTYPE_ARRAYELEM; - new->subscript = $3; - new->arrayparentno = $1->dno; - /* initialize cached type data to "not valid" */ - new->parenttypoid = InvalidOid; - - plpgsql_adddatum((PLpgSQL_datum *) new); - - $$ = (PLpgSQL_datum *) new; - } - ; - stmt_if : K_IF expr_until_then proc_sect stmt_elsifs stmt_else K_END K_IF ';' { PLpgSQL_stmt_if *new; @@ -2471,10 +2454,6 @@ expr_until_semi : { $$ = read_sql_expression(';', ";"); } ; -expr_until_rightbracket : - { $$ = read_sql_expression(']', "]"); } - ; - expr_until_then : { $$ = read_sql_expression(K_THEN, "THEN"); } ; @@ -3493,11 +3472,6 @@ check_assignable(PLpgSQL_datum *datum, int location) check_assignable(plpgsql_Datums[((PLpgSQL_recfield *) datum)->recparentno], location); break; - case PLPGSQL_DTYPE_ARRAYELEM: - /* assignable if parent array is */ - check_assignable(plpgsql_Datums[((PLpgSQL_arrayelem *) datum)->arrayparentno], - location); - break; default: elog(ERROR, "unrecognized dtype: %d", datum->dtype); break; diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index f80d023a5ad55..32061e54e00a2 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -64,7 +64,6 @@ typedef enum PLpgSQL_datum_type PLPGSQL_DTYPE_ROW, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECFIELD, - PLPGSQL_DTYPE_ARRAYELEM, PLPGSQL_DTYPE_PROMISE } PLpgSQL_datum_type; @@ -261,7 +260,7 @@ typedef struct PLpgSQL_expr * Generic datum array item * * PLpgSQL_datum is the common supertype for PLpgSQL_var, PLpgSQL_row, - * PLpgSQL_rec, PLpgSQL_recfield, and PLpgSQL_arrayelem. + * PLpgSQL_rec, and PLpgSQL_recfield. */ typedef struct PLpgSQL_datum { @@ -422,30 +421,6 @@ typedef struct PLpgSQL_recfield /* if rectupledescid == INVALID_TUPLEDESC_IDENTIFIER, finfo isn't valid */ } PLpgSQL_recfield; -/* - * Element of array variable - */ -typedef struct PLpgSQL_arrayelem -{ - PLpgSQL_datum_type dtype; - int dno; - /* end of PLpgSQL_datum fields */ - - PLpgSQL_expr *subscript; - int arrayparentno; /* dno of parent array variable */ - - /* Remaining fields are cached info about the array variable's type */ - Oid parenttypoid; /* type of array variable; 0 if not yet set */ - int32 parenttypmod; /* typmod of array variable */ - Oid arraytypoid; /* OID of actual array type */ - int32 arraytypmod; /* typmod of array (and its elements too) */ - int16 arraytyplen; /* typlen of array type */ - Oid elemtypoid; /* OID of array element type */ - int16 elemtyplen; /* typlen of element type */ - bool elemtypbyval; /* element type is pass-by-value? */ - char elemtypalign; /* typalign of element type */ -} PLpgSQL_arrayelem; - /* * Item in the compilers namespace tree */ diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out index 0c6c9ba1f59ff..6ea169d9add54 100644 --- a/src/test/regress/expected/plpgsql.out +++ b/src/test/regress/expected/plpgsql.out @@ -4230,7 +4230,6 @@ drop function tftest(int); create or replace function rttest() returns setof int as $$ declare rc int; - rca int[]; begin return query values(10),(20); get diagnostics rc = row_count; @@ -4239,12 +4238,11 @@ begin get diagnostics rc = row_count; raise notice '% %', found, rc; return query execute 'values(10),(20)'; - -- just for fun, let's use array elements as targets - get diagnostics rca[1] = row_count; - raise notice '% %', found, rca[1]; + get diagnostics rc = row_count; + raise notice '% %', found, rc; return query execute 'select * from (values(10),(20)) f(a) where false'; - get diagnostics rca[2] = row_count; - raise notice '% %', found, rca[2]; + get diagnostics rc = row_count; + raise notice '% %', found, rc; end; $$ language plpgsql; select * from rttest(); diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql index 07c60c80e482a..781666a83a15d 100644 --- a/src/test/regress/sql/plpgsql.sql +++ b/src/test/regress/sql/plpgsql.sql @@ -3497,7 +3497,6 @@ drop function tftest(int); create or replace function rttest() returns setof int as $$ declare rc int; - rca int[]; begin return query values(10),(20); get diagnostics rc = row_count; @@ -3506,12 +3505,11 @@ begin get diagnostics rc = row_count; raise notice '% %', found, rc; return query execute 'values(10),(20)'; - -- just for fun, let's use array elements as targets - get diagnostics rca[1] = row_count; - raise notice '% %', found, rca[1]; + get diagnostics rc = row_count; + raise notice '% %', found, rc; return query execute 'select * from (values(10),(20)) f(a) where false'; - get diagnostics rca[2] = row_count; - raise notice '% %', found, rca[2]; + get diagnostics rc = row_count; + raise notice '% %', found, rc; end; $$ language plpgsql; From 1c1cbe279b3c6e8038c8f8079402f069bb4cea4c Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 4 Jan 2021 12:39:27 -0500 Subject: [PATCH 027/240] Rethink the "read/write parameter" mechanism in pl/pgsql. Performance issues with the preceding patch to re-implement array element assignment within pl/pgsql led me to realize that the read/write parameter mechanism is misdesigned. Instead of requiring the assignment source expression to be such that *all* its references to the target variable could be passed as R/W, we really want to identify *one* reference to the target variable to be passed as R/W, allowing any other ones to be passed read/only as they would be by default. As long as the R/W reference is a direct argument to the top-level (hence last to be executed) function in the expression, there is no harm in R/O references being passed to other lower parts of the expression. Nor is there any use-case for more than one argument of the top-level function being R/W. Hence, rewrite that logic to identify one single Param that references the target variable, and make only that Param pass a read/write reference, not any other Params referencing the target variable. Discussion: https://postgr.es/m/4165684.1607707277@sss.pgh.pa.us --- src/backend/utils/adt/arrayfuncs.c | 7 +- src/pl/plpgsql/src/pl_exec.c | 177 ++++++++++++++--------------- src/pl/plpgsql/src/pl_gram.y | 6 +- src/pl/plpgsql/src/plpgsql.h | 12 +- 4 files changed, 106 insertions(+), 96 deletions(-) diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 1b618356606ff..f7012cc5d9876 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -2582,8 +2582,11 @@ array_set_element_expanded(Datum arraydatum, /* * Copy new element into array's context, if needed (we assume it's - * already detoasted, so no junk should be created). If we fail further - * down, this memory is leaked, but that's reasonably harmless. + * already detoasted, so no junk should be created). Doing this before + * we've made any significant changes ensures that our behavior is sane + * even when the source is a reference to some element of this same array. + * If we fail further down, this memory is leaked, but that's reasonably + * harmless. */ if (!eah->typbyval && !isNull) { diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 95f0adc81d9f4..3a9349b724261 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -333,8 +333,7 @@ static void exec_prepare_plan(PLpgSQL_execstate *estate, bool keepplan); static void exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr); static void exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan); -static void exec_check_rw_parameter(PLpgSQL_expr *expr, int target_dno); -static bool contains_target_param(Node *node, int *target_dno); +static void exec_check_rw_parameter(PLpgSQL_expr *expr); static bool exec_eval_simple_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, Datum *result, @@ -4190,13 +4189,6 @@ exec_prepare_plan(PLpgSQL_execstate *estate, /* Check to see if it's a simple expression */ exec_simple_check_plan(estate, expr); - - /* - * Mark expression as not using a read-write param. exec_assign_value has - * to take steps to override this if appropriate; that seems cleaner than - * adding parameters to all other callers. - */ - expr->rwparam = -1; } @@ -5024,16 +5016,23 @@ exec_assign_expr(PLpgSQL_execstate *estate, PLpgSQL_datum *target, int32 valtypmod; /* - * If first time through, create a plan for this expression, and then see - * if we can pass the target variable as a read-write parameter to the - * expression. (This is a bit messy, but it seems cleaner than modifying - * the API of exec_eval_expr for the purpose.) + * If first time through, create a plan for this expression. */ if (expr->plan == NULL) { - exec_prepare_plan(estate, expr, 0, true); + /* + * Mark the expression as being an assignment source, if target is a + * simple variable. (This is a bit messy, but it seems cleaner than + * modifying the API of exec_prepare_plan for the purpose. We need to + * stash the target dno into the expr anyway, so that it will be + * available if we have to replan.) + */ if (target->dtype == PLPGSQL_DTYPE_VAR) - exec_check_rw_parameter(expr, target->dno); + expr->target_param = target->dno; + else + expr->target_param = -1; /* should be that already */ + + exec_prepare_plan(estate, expr, 0, true); } value = exec_eval_expr(estate, expr, &isnull, &valtype, &valtypmod); @@ -6098,6 +6097,7 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate, ReleaseCachedPlan(cplan, true); /* Mark expression as non-simple, and fail */ expr->expr_simple_expr = NULL; + expr->expr_rw_param = NULL; return false; } @@ -6109,10 +6109,6 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate, /* Extract desired scalar expression from cached plan */ exec_save_simple_expr(expr, cplan); - - /* better recheck r/w safety, as it could change due to inlining */ - if (expr->rwparam >= 0) - exec_check_rw_parameter(expr, expr->rwparam); } /* @@ -6385,20 +6381,18 @@ plpgsql_param_fetch(ParamListInfo params, prm->pflags = PARAM_FLAG_CONST; /* - * If it's a read/write expanded datum, convert reference to read-only, - * unless it's safe to pass as read-write. + * If it's a read/write expanded datum, convert reference to read-only. + * (There's little point in trying to optimize read/write parameters, + * given the cases in which this function is used.) */ - if (dno != expr->rwparam) - { - if (datum->dtype == PLPGSQL_DTYPE_VAR) - prm->value = MakeExpandedObjectReadOnly(prm->value, - prm->isnull, - ((PLpgSQL_var *) datum)->datatype->typlen); - else if (datum->dtype == PLPGSQL_DTYPE_REC) - prm->value = MakeExpandedObjectReadOnly(prm->value, - prm->isnull, - -1); - } + if (datum->dtype == PLPGSQL_DTYPE_VAR) + prm->value = MakeExpandedObjectReadOnly(prm->value, + prm->isnull, + ((PLpgSQL_var *) datum)->datatype->typlen); + else if (datum->dtype == PLPGSQL_DTYPE_REC) + prm->value = MakeExpandedObjectReadOnly(prm->value, + prm->isnull, + -1); return prm; } @@ -6441,7 +6435,7 @@ plpgsql_param_compile(ParamListInfo params, Param *param, */ if (datum->dtype == PLPGSQL_DTYPE_VAR) { - if (dno != expr->rwparam && + if (param != expr->expr_rw_param && ((PLpgSQL_var *) datum)->datatype->typlen == -1) scratch.d.cparam.paramfunc = plpgsql_param_eval_var_ro; else @@ -6451,14 +6445,14 @@ plpgsql_param_compile(ParamListInfo params, Param *param, scratch.d.cparam.paramfunc = plpgsql_param_eval_recfield; else if (datum->dtype == PLPGSQL_DTYPE_PROMISE) { - if (dno != expr->rwparam && + if (param != expr->expr_rw_param && ((PLpgSQL_var *) datum)->datatype->typlen == -1) scratch.d.cparam.paramfunc = plpgsql_param_eval_generic_ro; else scratch.d.cparam.paramfunc = plpgsql_param_eval_generic; } else if (datum->dtype == PLPGSQL_DTYPE_REC && - dno != expr->rwparam) + param != expr->expr_rw_param) scratch.d.cparam.paramfunc = plpgsql_param_eval_generic_ro; else scratch.d.cparam.paramfunc = plpgsql_param_eval_generic; @@ -7930,6 +7924,7 @@ exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr) * Initialize to "not simple". */ expr->expr_simple_expr = NULL; + expr->expr_rw_param = NULL; /* * Check the analyzed-and-rewritten form of the query to see if we will be @@ -8108,6 +8103,12 @@ exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan) expr->expr_simple_typmod = exprTypmod((Node *) tle_expr); /* We also want to remember if it is immutable or not */ expr->expr_simple_mutable = contain_mutable_functions((Node *) tle_expr); + + /* + * Lastly, check to see if there's a possibility of optimizing a + * read/write parameter. + */ + exec_check_rw_parameter(expr); } /* @@ -8119,25 +8120,36 @@ exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan) * value as a read/write pointer and let the function modify the value * in-place. * - * This function checks for a safe expression, and sets expr->rwparam to the - * dno of the target variable (x) if safe, or -1 if not safe. + * This function checks for a safe expression, and sets expr->expr_rw_param + * to the address of any Param within the expression that can be passed as + * read/write (there can be only one); or to NULL when there is no safe Param. + * + * Note that this mechanism intentionally applies the safety labeling to just + * one Param; the expression could contain other Params referencing the target + * variable, but those must still be treated as read-only. + * + * Also note that we only apply this optimization within simple expressions. + * There's no point in it for non-simple expressions, because the + * exec_run_select code path will flatten any expanded result anyway. + * Also, it's safe to assume that an expr_simple_expr tree won't get copied + * somewhere before it gets compiled, so that looking for pointer equality + * to expr_rw_param will work for matching the target Param. That'd be much + * shakier in the general case. */ static void -exec_check_rw_parameter(PLpgSQL_expr *expr, int target_dno) +exec_check_rw_parameter(PLpgSQL_expr *expr) { + int target_dno; Oid funcid; List *fargs; ListCell *lc; /* Assume unsafe */ - expr->rwparam = -1; + expr->expr_rw_param = NULL; - /* - * If the expression isn't simple, there's no point in trying to optimize - * (because the exec_run_select code path will flatten any expanded result - * anyway). Even without that, this seems like a good safety restriction. - */ - if (expr->expr_simple_expr == NULL) + /* Done if expression isn't an assignment source */ + target_dno = expr->target_param; + if (target_dno < 0) return; /* @@ -8147,9 +8159,12 @@ exec_check_rw_parameter(PLpgSQL_expr *expr, int target_dno) if (!bms_is_member(target_dno, expr->paramnos)) return; + /* Shouldn't be here for non-simple expression */ + Assert(expr->expr_simple_expr != NULL); + /* * Top level of expression must be a simple FuncExpr, OpExpr, or - * SubscriptingRef. + * SubscriptingRef, else we can't optimize. */ if (IsA(expr->expr_simple_expr, FuncExpr)) { @@ -8174,22 +8189,20 @@ exec_check_rw_parameter(PLpgSQL_expr *expr, int target_dno) F_ARRAY_SUBSCRIPT_HANDLER) return; - /* refexpr can be a simple Param, otherwise must not contain target */ - if (!(sbsref->refexpr && IsA(sbsref->refexpr, Param)) && - contains_target_param((Node *) sbsref->refexpr, &target_dno)) - return; + /* We can optimize the refexpr if it's the target, otherwise not */ + if (sbsref->refexpr && IsA(sbsref->refexpr, Param)) + { + Param *param = (Param *) sbsref->refexpr; - /* the other subexpressions must not contain target */ - if (contains_target_param((Node *) sbsref->refupperindexpr, - &target_dno) || - contains_target_param((Node *) sbsref->reflowerindexpr, - &target_dno) || - contains_target_param((Node *) sbsref->refassgnexpr, - &target_dno)) - return; + if (param->paramkind == PARAM_EXTERN && + param->paramid == target_dno + 1) + { + /* Found the Param we want to pass as read/write */ + expr->expr_rw_param = param; + return; + } + } - /* OK, we can pass target as a read-write parameter */ - expr->rwparam = target_dno; return; } else @@ -8205,44 +8218,28 @@ exec_check_rw_parameter(PLpgSQL_expr *expr, int target_dno) return; /* - * The target variable (in the form of a Param) must only appear as a - * direct argument of the top-level function. + * The target variable (in the form of a Param) must appear as a direct + * argument of the top-level function. References further down in the + * tree can't be optimized; but on the other hand, they don't invalidate + * optimizing the top-level call, since that will be executed last. */ foreach(lc, fargs) { Node *arg = (Node *) lfirst(lc); - /* A Param is OK, whether it's the target variable or not */ if (arg && IsA(arg, Param)) - continue; - /* Otherwise, argument expression must not reference target */ - if (contains_target_param(arg, &target_dno)) - return; - } - - /* OK, we can pass target as a read-write parameter */ - expr->rwparam = target_dno; -} - -/* - * Recursively check for a Param referencing the target variable - */ -static bool -contains_target_param(Node *node, int *target_dno) -{ - if (node == NULL) - return false; - if (IsA(node, Param)) - { - Param *param = (Param *) node; + { + Param *param = (Param *) arg; - if (param->paramkind == PARAM_EXTERN && - param->paramid == *target_dno + 1) - return true; - return false; + if (param->paramkind == PARAM_EXTERN && + param->paramid == target_dno + 1) + { + /* Found the Param we want to pass as read/write */ + expr->expr_rw_param = param; + return; + } + } } - return expression_tree_walker(node, contains_target_param, - (void *) target_dno); } /* ---------- diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y index 0fdbaa5eab86e..0b0ff4e5de28d 100644 --- a/src/pl/plpgsql/src/pl_gram.y +++ b/src/pl/plpgsql/src/pl_gram.y @@ -2820,7 +2820,7 @@ read_sql_construct(int until, expr->parseMode = parsemode; expr->plan = NULL; expr->paramnos = NULL; - expr->rwparam = -1; + expr->target_param = -1; expr->ns = plpgsql_ns_top(); pfree(ds.data); @@ -3067,7 +3067,7 @@ make_execsql_stmt(int firsttoken, int location) expr->parseMode = RAW_PARSE_DEFAULT; expr->plan = NULL; expr->paramnos = NULL; - expr->rwparam = -1; + expr->target_param = -1; expr->ns = plpgsql_ns_top(); pfree(ds.data); @@ -3949,7 +3949,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until) expr->parseMode = RAW_PARSE_PLPGSQL_EXPR; expr->plan = NULL; expr->paramnos = NULL; - expr->rwparam = -1; + expr->target_param = -1; expr->ns = plpgsql_ns_top(); pfree(ds.data); diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index 32061e54e00a2..416fda7f3b5c6 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -221,7 +221,6 @@ typedef struct PLpgSQL_expr RawParseMode parseMode; /* raw_parser() mode to use */ SPIPlanPtr plan; /* plan, or NULL if not made yet */ Bitmapset *paramnos; /* all dnos referenced by this query */ - int rwparam; /* dno of read/write param, or -1 if none */ /* function containing this expr (not set until we first parse query) */ struct PLpgSQL_function *func; @@ -235,6 +234,17 @@ typedef struct PLpgSQL_expr int32 expr_simple_typmod; /* result typmod, if simple */ bool expr_simple_mutable; /* true if simple expr is mutable */ + /* + * These fields are used to optimize assignments to expanded-datum + * variables. If this expression is the source of an assignment to a + * simple variable, target_param holds that variable's dno; else it's -1. + * If we match a Param within expr_simple_expr to such a variable, that + * Param's address is stored in expr_rw_param; then expression code + * generation will allow the value for that Param to be passed read/write. + */ + int target_param; /* dno of assign target, or -1 if none */ + Param *expr_rw_param; /* read/write Param within expr, if any */ + /* * If the expression was ever determined to be simple, we remember its * CachedPlanSource and CachedPlan here. If expr_simple_plan_lxid matches From 87c23d36a3bc81e57b813f13c403f74a67ff33a9 Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Tue, 5 Jan 2021 11:40:03 +1300 Subject: [PATCH 028/240] Remove unused function prototypes. Cleanup for commit dee663f7. Reported-by: Tomas Vondra Discussion: https://postgr.es/m/CA+hUKGLJ=84YT+NvhkEEDAuUtVHMfQ9i-N7k_o50JmQ6Rpj_OQ@mail.gmail.com --- src/include/access/clog.h | 1 - src/include/access/commit_ts.h | 1 - src/include/access/multixact.h | 1 - src/include/access/subtrans.h | 1 - 4 files changed, 4 deletions(-) diff --git a/src/include/access/clog.h b/src/include/access/clog.h index e3329de10b977..39b8e4afa8a48 100644 --- a/src/include/access/clog.h +++ b/src/include/access/clog.h @@ -46,7 +46,6 @@ extern void CLOGShmemInit(void); extern void BootStrapCLOG(void); extern void StartupCLOG(void); extern void TrimCLOG(void); -extern void ShutdownCLOG(void); extern void CheckPointCLOG(void); extern void ExtendCLOG(TransactionId newestXact); extern void TruncateCLOG(TransactionId oldestXact, Oid oldestxid_datoid); diff --git a/src/include/access/commit_ts.h b/src/include/access/commit_ts.h index 61f1c9aa2fd0d..750369104ac59 100644 --- a/src/include/access/commit_ts.h +++ b/src/include/access/commit_ts.h @@ -38,7 +38,6 @@ extern void BootStrapCommitTs(void); extern void StartupCommitTs(void); extern void CommitTsParameterChange(bool newvalue, bool oldvalue); extern void CompleteCommitTsInitialization(void); -extern void ShutdownCommitTs(void); extern void CheckPointCommitTs(void); extern void ExtendCommitTs(TransactionId newestXact); extern void TruncateCommitTs(TransactionId oldestXact); diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h index b5bb170e322b1..4bbb035eaeaf0 100644 --- a/src/include/access/multixact.h +++ b/src/include/access/multixact.h @@ -130,7 +130,6 @@ extern void MultiXactShmemInit(void); extern void BootStrapMultiXact(void); extern void StartupMultiXact(void); extern void TrimMultiXact(void); -extern void ShutdownMultiXact(void); extern void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup); diff --git a/src/include/access/subtrans.h b/src/include/access/subtrans.h index 5ccb52b5f679a..d0ab44ae8283c 100644 --- a/src/include/access/subtrans.h +++ b/src/include/access/subtrans.h @@ -22,7 +22,6 @@ extern Size SUBTRANSShmemSize(void); extern void SUBTRANSShmemInit(void); extern void BootStrapSUBTRANS(void); extern void StartupSUBTRANS(TransactionId oldestActiveXID); -extern void ShutdownSUBTRANS(void); extern void CheckPointSUBTRANS(void); extern void ExtendSUBTRANS(TransactionId newestXact); extern void TruncateSUBTRANS(TransactionId oldestXact); From 4bd3fad80e5c3bd107583dd9d32d4a47c045a3ec Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 4 Jan 2021 18:32:40 -0500 Subject: [PATCH 029/240] Fix integer-overflow corner cases in substring() functions. If the substring start index and length overflow when added together, substring() misbehaved, either throwing a bogus "negative substring length" error on a case that should succeed, or failing to complain that a negative length is negative (and instead returning the whole string, in most cases). Unsurprisingly, the text, bytea, and bit variants of the function all had this issue. Rearrange the logic to ensure that negative lengths are always rejected, and add an overflow check to handle the other case. Also install similar guards into detoast_attr_slice() (nee heap_tuple_untoast_attr_slice()), since it's far from clear that no other code paths leading to that function could pass it values that would overflow. Patch by myself and Pavel Stehule, per bug #16804 from Rafi Shamim. Back-patch to v11. While these bugs are old, the common/int.h infrastructure for overflow-detecting arithmetic didn't exist before commit 4d6ad3125, and it doesn't seem like these misbehaviors are bad enough to justify developing a standalone fix for the older branches. Discussion: https://postgr.es/m/16804-f4eeeb6c11ba71d4@postgresql.org --- src/backend/access/common/detoast.c | 33 ++++++-- src/backend/utils/adt/varbit.c | 26 +++--- src/backend/utils/adt/varlena.c | 110 +++++++++++++++----------- src/test/regress/expected/bit.out | 29 +++++++ src/test/regress/expected/strings.out | 41 ++++++++++ src/test/regress/sql/bit.sql | 8 ++ src/test/regress/sql/strings.sql | 11 +++ 7 files changed, 195 insertions(+), 63 deletions(-) diff --git a/src/backend/access/common/detoast.c b/src/backend/access/common/detoast.c index b118f4a7146b6..d1cdbaf648614 100644 --- a/src/backend/access/common/detoast.c +++ b/src/backend/access/common/detoast.c @@ -17,6 +17,7 @@ #include "access/table.h" #include "access/tableam.h" #include "access/toast_internals.h" +#include "common/int.h" #include "common/pg_lzcompress.h" #include "utils/expandeddatum.h" #include "utils/rel.h" @@ -196,7 +197,8 @@ detoast_attr(struct varlena *attr) * Public entry point to get back part of a toasted value * from compression or external storage. * - * Note: When slicelength is negative, return suffix of the value. + * sliceoffset is where to start (zero or more) + * If slicelength < 0, return everything beyond sliceoffset * ---------- */ struct varlena * @@ -206,8 +208,21 @@ detoast_attr_slice(struct varlena *attr, struct varlena *preslice; struct varlena *result; char *attrdata; + int32 slicelimit; int32 attrsize; + if (sliceoffset < 0) + elog(ERROR, "invalid sliceoffset: %d", sliceoffset); + + /* + * Compute slicelimit = offset + length, or -1 if we must fetch all of the + * value. In case of integer overflow, we must fetch all. + */ + if (slicelength < 0) + slicelimit = -1; + else if (pg_add_s32_overflow(sliceoffset, slicelength, &slicelimit)) + slicelength = slicelimit = -1; + if (VARATT_IS_EXTERNAL_ONDISK(attr)) { struct varatt_external toast_pointer; @@ -223,7 +238,7 @@ detoast_attr_slice(struct varlena *attr, * at least the requested part (when a prefix is requested). * Otherwise, just fetch all slices. */ - if (slicelength > 0 && sliceoffset >= 0) + if (slicelimit >= 0) { int32 max_size; @@ -231,7 +246,7 @@ detoast_attr_slice(struct varlena *attr, * Determine maximum amount of compressed data needed for a prefix * of a given length (after decompression). */ - max_size = pglz_maximum_compressed_size(sliceoffset + slicelength, + max_size = pglz_maximum_compressed_size(slicelimit, toast_pointer.va_extsize); /* @@ -270,8 +285,8 @@ detoast_attr_slice(struct varlena *attr, struct varlena *tmp = preslice; /* Decompress enough to encompass the slice and the offset */ - if (slicelength > 0 && sliceoffset >= 0) - preslice = toast_decompress_datum_slice(tmp, slicelength + sliceoffset); + if (slicelimit >= 0) + preslice = toast_decompress_datum_slice(tmp, slicelimit); else preslice = toast_decompress_datum(tmp); @@ -297,8 +312,7 @@ detoast_attr_slice(struct varlena *attr, sliceoffset = 0; slicelength = 0; } - - if (((sliceoffset + slicelength) > attrsize) || slicelength < 0) + else if (slicelength < 0 || slicelimit > attrsize) slicelength = attrsize - sliceoffset; result = (struct varlena *) palloc(slicelength + VARHDRSZ); @@ -410,6 +424,11 @@ toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset, if (VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer) && slicelength > 0) slicelength = slicelength + sizeof(int32); + /* + * Adjust length request if needed. (Note: our sole caller, + * detoast_attr_slice, protects us against sliceoffset + slicelength + * overflowing.) + */ if (((sliceoffset + slicelength) > attrsize) || slicelength < 0) slicelength = attrsize - sliceoffset; diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c index abbb4d810686e..2235866244da3 100644 --- a/src/backend/utils/adt/varbit.c +++ b/src/backend/utils/adt/varbit.c @@ -1059,7 +1059,7 @@ bitsubstring(VarBit *arg, int32 s, int32 l, bool length_not_specified) len, ishift, i; - int e, + int32 e, s1, e1; bits8 *r, @@ -1072,18 +1072,24 @@ bitsubstring(VarBit *arg, int32 s, int32 l, bool length_not_specified) { e1 = bitlen + 1; } - else + else if (l < 0) + { + /* SQL99 says to throw an error for E < S, i.e., negative length */ + ereport(ERROR, + (errcode(ERRCODE_SUBSTRING_ERROR), + errmsg("negative substring length not allowed"))); + e1 = -1; /* silence stupider compilers */ + } + else if (pg_add_s32_overflow(s, l, &e)) { - e = s + l; - /* - * A negative value for L is the only way for the end position to be - * before the start. SQL99 says to throw an error. + * L could be large enough for S + L to overflow, in which case the + * substring must run to end of string. */ - if (e < s) - ereport(ERROR, - (errcode(ERRCODE_SUBSTRING_ERROR), - errmsg("negative substring length not allowed"))); + e1 = bitlen + 1; + } + else + { e1 = Min(e, bitlen + 1); } if (s1 > bitlen || e1 <= s1) diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index ec1fb4d1b90bc..4838bfb4ff0c6 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -868,29 +868,38 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified) int32 S = start; /* start position */ int32 S1; /* adjusted start position */ int32 L1; /* adjusted substring length */ + int32 E; /* end position */ + + /* + * SQL99 says S can be zero or negative, but we still must fetch from the + * start of the string. + */ + S1 = Max(S, 1); /* life is easy if the encoding max length is 1 */ if (eml == 1) { - S1 = Max(S, 1); - if (length_not_specified) /* special case - get length to end of * string */ L1 = -1; - else + else if (length < 0) + { + /* SQL99 says to throw an error for E < S, i.e., negative length */ + ereport(ERROR, + (errcode(ERRCODE_SUBSTRING_ERROR), + errmsg("negative substring length not allowed"))); + L1 = -1; /* silence stupider compilers */ + } + else if (pg_add_s32_overflow(S, length, &E)) { - /* end position */ - int E = S + length; - /* - * A negative value for L is the only way for the end position to - * be before the start. SQL99 says to throw an error. + * L could be large enough for S + L to overflow, in which case + * the substring must run to end of string. */ - if (E < S) - ereport(ERROR, - (errcode(ERRCODE_SUBSTRING_ERROR), - errmsg("negative substring length not allowed"))); - + L1 = -1; + } + else + { /* * A zero or negative value for the end position can happen if the * start was negative or one. SQL99 says to return a zero-length @@ -904,8 +913,8 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified) /* * If the start position is past the end of the string, SQL99 says to - * return a zero-length string -- PG_GETARG_TEXT_P_SLICE() will do - * that for us. Convert to zero-based starting position + * return a zero-length string -- DatumGetTextPSlice() will do that + * for us. We need only convert S1 to zero-based starting position. */ return DatumGetTextPSlice(str, S1 - 1, L1); } @@ -926,12 +935,6 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified) char *s; text *ret; - /* - * if S is past the end of the string, the tuple toaster will return a - * zero-length string to us - */ - S1 = Max(S, 1); - /* * We need to start at position zero because there is no way to know * in advance which byte offset corresponds to the supplied start @@ -942,19 +945,24 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified) if (length_not_specified) /* special case - get length to end of * string */ slice_size = L1 = -1; - else + else if (length < 0) + { + /* SQL99 says to throw an error for E < S, i.e., negative length */ + ereport(ERROR, + (errcode(ERRCODE_SUBSTRING_ERROR), + errmsg("negative substring length not allowed"))); + slice_size = L1 = -1; /* silence stupider compilers */ + } + else if (pg_add_s32_overflow(S, length, &E)) { - int E = S + length; - /* - * A negative value for L is the only way for the end position to - * be before the start. SQL99 says to throw an error. + * L could be large enough for S + L to overflow, in which case + * the substring must run to end of string. */ - if (E < S) - ereport(ERROR, - (errcode(ERRCODE_SUBSTRING_ERROR), - errmsg("negative substring length not allowed"))); - + slice_size = L1 = -1; + } + else + { /* * A zero or negative value for the end position can happen if the * start was negative or one. SQL99 says to return a zero-length @@ -972,8 +980,10 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified) /* * Total slice size in bytes can't be any longer than the start * position plus substring length times the encoding max length. + * If that overflows, we can just use -1. */ - slice_size = (S1 + L1) * eml; + if (pg_mul_s32_overflow(E, eml, &slice_size)) + slice_size = -1; } /* @@ -3309,9 +3319,13 @@ bytea_substring(Datum str, int L, bool length_not_specified) { - int S1; /* adjusted start position */ - int L1; /* adjusted substring length */ + int32 S1; /* adjusted start position */ + int32 L1; /* adjusted substring length */ + int32 E; /* end position */ + /* + * The logic here should generally match text_substring(). + */ S1 = Max(S, 1); if (length_not_specified) @@ -3322,20 +3336,24 @@ bytea_substring(Datum str, */ L1 = -1; } - else + else if (L < 0) + { + /* SQL99 says to throw an error for E < S, i.e., negative length */ + ereport(ERROR, + (errcode(ERRCODE_SUBSTRING_ERROR), + errmsg("negative substring length not allowed"))); + L1 = -1; /* silence stupider compilers */ + } + else if (pg_add_s32_overflow(S, L, &E)) { - /* end position */ - int E = S + L; - /* - * A negative value for L is the only way for the end position to be - * before the start. SQL99 says to throw an error. + * L could be large enough for S + L to overflow, in which case the + * substring must run to end of string. */ - if (E < S) - ereport(ERROR, - (errcode(ERRCODE_SUBSTRING_ERROR), - errmsg("negative substring length not allowed"))); - + L1 = -1; + } + else + { /* * A zero or negative value for the end position can happen if the * start was negative or one. SQL99 says to return a zero-length @@ -3350,7 +3368,7 @@ bytea_substring(Datum str, /* * If the start position is past the end of the string, SQL99 says to * return a zero-length string -- DatumGetByteaPSlice() will do that for - * us. Convert to zero-based starting position + * us. We need only convert S1 to zero-based starting position. */ return DatumGetByteaPSlice(str, S1 - 1, L1); } diff --git a/src/test/regress/expected/bit.out b/src/test/regress/expected/bit.out index a1fab7ebcb075..a7f95b846d96c 100644 --- a/src/test/regress/expected/bit.out +++ b/src/test/regress/expected/bit.out @@ -106,6 +106,35 @@ SELECT v, 01010101010 | 1010 | 01010 | 101010 (4 rows) +-- test overflow cases +SELECT SUBSTRING('01010101'::bit(8) FROM 2 FOR 2147483646) AS "1010101"; + 1010101 +--------- + 1010101 +(1 row) + +SELECT SUBSTRING('01010101'::bit(8) FROM -10 FOR 2147483646) AS "01010101"; + 01010101 +---------- + 01010101 +(1 row) + +SELECT SUBSTRING('01010101'::bit(8) FROM -10 FOR -2147483646) AS "error"; +ERROR: negative substring length not allowed +SELECT SUBSTRING('01010101'::varbit FROM 2 FOR 2147483646) AS "1010101"; + 1010101 +--------- + 1010101 +(1 row) + +SELECT SUBSTRING('01010101'::varbit FROM -10 FOR 2147483646) AS "01010101"; + 01010101 +---------- + 01010101 +(1 row) + +SELECT SUBSTRING('01010101'::varbit FROM -10 FOR -2147483646) AS "error"; +ERROR: negative substring length not allowed --- Bit operations DROP TABLE varbit_table; CREATE TABLE varbit_table (a BIT VARYING(16), b BIT VARYING(16)); diff --git a/src/test/regress/expected/strings.out b/src/test/regress/expected/strings.out index 298b6c48c21b7..595bd2446e525 100644 --- a/src/test/regress/expected/strings.out +++ b/src/test/regress/expected/strings.out @@ -396,6 +396,21 @@ SELECT SUBSTRING('1234567890' FROM 4 FOR 3) = '456' AS "456"; t (1 row) +-- test overflow cases +SELECT SUBSTRING('string' FROM 2 FOR 2147483646) AS "tring"; + tring +------- + tring +(1 row) + +SELECT SUBSTRING('string' FROM -10 FOR 2147483646) AS "string"; + string +-------- + string +(1 row) + +SELECT SUBSTRING('string' FROM -10 FOR -2147483646) AS "error"; +ERROR: negative substring length not allowed -- T581 regular expression substring (with SQL's bizarre regexp syntax) SELECT SUBSTRING('abcdefg' SIMILAR 'a#"(b_d)#"%' ESCAPE '#') AS "bcd"; bcd @@ -2084,6 +2099,32 @@ SELECT repeat('Pg', -4); (1 row) +SELECT SUBSTRING('1234567890'::bytea FROM 3) "34567890"; + 34567890 +---------- + 34567890 +(1 row) + +SELECT SUBSTRING('1234567890'::bytea FROM 4 FOR 3) AS "456"; + 456 +----- + 456 +(1 row) + +SELECT SUBSTRING('string'::bytea FROM 2 FOR 2147483646) AS "tring"; + tring +------- + tring +(1 row) + +SELECT SUBSTRING('string'::bytea FROM -10 FOR 2147483646) AS "string"; + string +-------- + string +(1 row) + +SELECT SUBSTRING('string'::bytea FROM -10 FOR -2147483646) AS "error"; +ERROR: negative substring length not allowed SELECT trim(E'\\000'::bytea from E'\\000Tom\\000'::bytea); btrim ------- diff --git a/src/test/regress/sql/bit.sql b/src/test/regress/sql/bit.sql index 7681d4ab4d06d..ea01742c4aa1f 100644 --- a/src/test/regress/sql/bit.sql +++ b/src/test/regress/sql/bit.sql @@ -53,6 +53,14 @@ SELECT v, SUBSTRING(v FROM 6) AS sub_6 FROM VARBIT_TABLE; +-- test overflow cases +SELECT SUBSTRING('01010101'::bit(8) FROM 2 FOR 2147483646) AS "1010101"; +SELECT SUBSTRING('01010101'::bit(8) FROM -10 FOR 2147483646) AS "01010101"; +SELECT SUBSTRING('01010101'::bit(8) FROM -10 FOR -2147483646) AS "error"; +SELECT SUBSTRING('01010101'::varbit FROM 2 FOR 2147483646) AS "1010101"; +SELECT SUBSTRING('01010101'::varbit FROM -10 FOR 2147483646) AS "01010101"; +SELECT SUBSTRING('01010101'::varbit FROM -10 FOR -2147483646) AS "error"; + --- Bit operations DROP TABLE varbit_table; CREATE TABLE varbit_table (a BIT VARYING(16), b BIT VARYING(16)); diff --git a/src/test/regress/sql/strings.sql b/src/test/regress/sql/strings.sql index ad5221ab6b09a..ca465d050f70c 100644 --- a/src/test/regress/sql/strings.sql +++ b/src/test/regress/sql/strings.sql @@ -131,6 +131,11 @@ SELECT SUBSTRING('1234567890' FROM 3) = '34567890' AS "34567890"; SELECT SUBSTRING('1234567890' FROM 4 FOR 3) = '456' AS "456"; +-- test overflow cases +SELECT SUBSTRING('string' FROM 2 FOR 2147483646) AS "tring"; +SELECT SUBSTRING('string' FROM -10 FOR 2147483646) AS "string"; +SELECT SUBSTRING('string' FROM -10 FOR -2147483646) AS "error"; + -- T581 regular expression substring (with SQL's bizarre regexp syntax) SELECT SUBSTRING('abcdefg' SIMILAR 'a#"(b_d)#"%' ESCAPE '#') AS "bcd"; -- obsolete SQL99 syntax @@ -710,6 +715,12 @@ SELECT chr(0); SELECT repeat('Pg', 4); SELECT repeat('Pg', -4); +SELECT SUBSTRING('1234567890'::bytea FROM 3) "34567890"; +SELECT SUBSTRING('1234567890'::bytea FROM 4 FOR 3) AS "456"; +SELECT SUBSTRING('string'::bytea FROM 2 FOR 2147483646) AS "tring"; +SELECT SUBSTRING('string'::bytea FROM -10 FOR 2147483646) AS "string"; +SELECT SUBSTRING('string'::bytea FROM -10 FOR -2147483646) AS "error"; + SELECT trim(E'\\000'::bytea from E'\\000Tom\\000'::bytea); SELECT btrim(E'\\000trim\\000'::bytea, E'\\000'::bytea); SELECT btrim(''::bytea, E'\\000'::bytea); From c0d4f6d897492727d4812679e6a94d12edbe016f Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Tue, 5 Jan 2021 12:06:15 +1300 Subject: [PATCH 030/240] Rename "enum blacklist" to "uncommitted enums". We agreed to remove this terminology and use something more descriptive. Discussion: https://postgr.es/m/20200615182235.x7lch5n6kcjq4aue%40alap3.anarazel.de --- src/backend/access/transam/parallel.c | 31 ++++++------- src/backend/catalog/pg_enum.c | 65 ++++++++++++++------------- src/backend/utils/adt/enum.c | 4 +- src/include/catalog/pg_enum.h | 8 ++-- 4 files changed, 55 insertions(+), 53 deletions(-) diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c index 94f9cefa08b04..3550ef13baa40 100644 --- a/src/backend/access/transam/parallel.c +++ b/src/backend/access/transam/parallel.c @@ -75,7 +75,7 @@ #define PARALLEL_KEY_PENDING_SYNCS UINT64CONST(0xFFFFFFFFFFFF000B) #define PARALLEL_KEY_REINDEX_STATE UINT64CONST(0xFFFFFFFFFFFF000C) #define PARALLEL_KEY_RELMAPPER_STATE UINT64CONST(0xFFFFFFFFFFFF000D) -#define PARALLEL_KEY_ENUMBLACKLIST UINT64CONST(0xFFFFFFFFFFFF000E) +#define PARALLEL_KEY_UNCOMMITTEDENUMS UINT64CONST(0xFFFFFFFFFFFF000E) /* Fixed-size parallel state. */ typedef struct FixedParallelState @@ -211,7 +211,7 @@ InitializeParallelDSM(ParallelContext *pcxt) Size pendingsyncslen = 0; Size reindexlen = 0; Size relmapperlen = 0; - Size enumblacklistlen = 0; + Size uncommittedenumslen = 0; Size segsize = 0; int i; FixedParallelState *fps; @@ -267,8 +267,8 @@ InitializeParallelDSM(ParallelContext *pcxt) shm_toc_estimate_chunk(&pcxt->estimator, reindexlen); relmapperlen = EstimateRelationMapSpace(); shm_toc_estimate_chunk(&pcxt->estimator, relmapperlen); - enumblacklistlen = EstimateEnumBlacklistSpace(); - shm_toc_estimate_chunk(&pcxt->estimator, enumblacklistlen); + uncommittedenumslen = EstimateUncommittedEnumsSpace(); + shm_toc_estimate_chunk(&pcxt->estimator, uncommittedenumslen); /* If you add more chunks here, you probably need to add keys. */ shm_toc_estimate_keys(&pcxt->estimator, 11); @@ -348,7 +348,7 @@ InitializeParallelDSM(ParallelContext *pcxt) char *error_queue_space; char *session_dsm_handle_space; char *entrypointstate; - char *enumblacklistspace; + char *uncommittedenumsspace; Size lnamelen; /* Serialize shared libraries we have loaded. */ @@ -404,11 +404,12 @@ InitializeParallelDSM(ParallelContext *pcxt) shm_toc_insert(pcxt->toc, PARALLEL_KEY_RELMAPPER_STATE, relmapperspace); - /* Serialize enum blacklist state. */ - enumblacklistspace = shm_toc_allocate(pcxt->toc, enumblacklistlen); - SerializeEnumBlacklist(enumblacklistspace, enumblacklistlen); - shm_toc_insert(pcxt->toc, PARALLEL_KEY_ENUMBLACKLIST, - enumblacklistspace); + /* Serialize uncommitted enum state. */ + uncommittedenumsspace = shm_toc_allocate(pcxt->toc, + uncommittedenumslen); + SerializeUncommittedEnums(uncommittedenumsspace, uncommittedenumslen); + shm_toc_insert(pcxt->toc, PARALLEL_KEY_UNCOMMITTEDENUMS, + uncommittedenumsspace); /* Allocate space for worker information. */ pcxt->worker = palloc0(sizeof(ParallelWorkerInfo) * pcxt->nworkers); @@ -1257,7 +1258,7 @@ ParallelWorkerMain(Datum main_arg) char *pendingsyncsspace; char *reindexspace; char *relmapperspace; - char *enumblacklistspace; + char *uncommittedenumsspace; StringInfoData msgbuf; char *session_dsm_handle_space; @@ -1449,10 +1450,10 @@ ParallelWorkerMain(Datum main_arg) relmapperspace = shm_toc_lookup(toc, PARALLEL_KEY_RELMAPPER_STATE, false); RestoreRelationMap(relmapperspace); - /* Restore enum blacklist. */ - enumblacklistspace = shm_toc_lookup(toc, PARALLEL_KEY_ENUMBLACKLIST, - false); - RestoreEnumBlacklist(enumblacklistspace); + /* Restore uncommitted enums. */ + uncommittedenumsspace = shm_toc_lookup(toc, PARALLEL_KEY_UNCOMMITTEDENUMS, + false); + RestoreUncommittedEnums(uncommittedenumsspace); /* Attach to the leader's serializable transaction, if SERIALIZABLE. */ AttachSerializableXact(fps->serializable_xact_handle); diff --git a/src/backend/catalog/pg_enum.c b/src/backend/catalog/pg_enum.c index b54f9dff43bd2..f958f1541dec4 100644 --- a/src/backend/catalog/pg_enum.c +++ b/src/backend/catalog/pg_enum.c @@ -41,10 +41,11 @@ Oid binary_upgrade_next_pg_enum_oid = InvalidOid; * committed; otherwise, they might get into indexes where we can't clean * them up, and then if the transaction rolls back we have a broken index. * (See comments for check_safe_enum_use() in enum.c.) Values created by - * EnumValuesCreate are *not* blacklisted; we assume those are created during - * CREATE TYPE, so they can't go away unless the enum type itself does. + * EnumValuesCreate are *not* entered into the table; we assume those are + * created during CREATE TYPE, so they can't go away unless the enum type + * itself does. */ -static HTAB *enum_blacklist = NULL; +static HTAB *uncommitted_enums = NULL; static void RenumberEnumType(Relation pg_enum, HeapTuple *existing, int nelems); static int sort_order_cmp(const void *p1, const void *p2); @@ -181,20 +182,20 @@ EnumValuesDelete(Oid enumTypeOid) } /* - * Initialize the enum blacklist for this transaction. + * Initialize the uncommitted enum table for this transaction. */ static void -init_enum_blacklist(void) +init_uncommitted_enums(void) { HASHCTL hash_ctl; hash_ctl.keysize = sizeof(Oid); hash_ctl.entrysize = sizeof(Oid); hash_ctl.hcxt = TopTransactionContext; - enum_blacklist = hash_create("Enum value blacklist", - 32, - &hash_ctl, - HASH_ELEM | HASH_BLOBS | HASH_CONTEXT); + uncommitted_enums = hash_create("Uncommitted enums", + 32, + &hash_ctl, + HASH_ELEM | HASH_BLOBS | HASH_CONTEXT); } /* @@ -490,12 +491,12 @@ AddEnumLabel(Oid enumTypeOid, table_close(pg_enum, RowExclusiveLock); - /* Set up the blacklist hash if not already done in this transaction */ - if (enum_blacklist == NULL) - init_enum_blacklist(); + /* Set up the uncommitted enum table if not already done in this tx */ + if (uncommitted_enums == NULL) + init_uncommitted_enums(); - /* Add the new value to the blacklist */ - (void) hash_search(enum_blacklist, &newOid, HASH_ENTER, NULL); + /* Add the new value to the table */ + (void) hash_search(uncommitted_enums, &newOid, HASH_ENTER, NULL); } @@ -584,19 +585,19 @@ RenameEnumLabel(Oid enumTypeOid, /* - * Test if the given enum value is on the blacklist + * Test if the given enum value is in the table of uncommitted enums. */ bool -EnumBlacklisted(Oid enum_id) +EnumUncommitted(Oid enum_id) { bool found; - /* If we've made no blacklist table, all values are safe */ - if (enum_blacklist == NULL) + /* If we've made no uncommitted table, all values are safe */ + if (uncommitted_enums == NULL) return false; /* Else, is it in the table? */ - (void) hash_search(enum_blacklist, &enum_id, HASH_FIND, &found); + (void) hash_search(uncommitted_enums, &enum_id, HASH_FIND, &found); return found; } @@ -608,11 +609,11 @@ void AtEOXact_Enum(void) { /* - * Reset the blacklist table, as all our enum values are now committed. + * Reset the uncommitted table, as all our enum values are now committed. * The memory will go away automatically when TopTransactionContext is * freed; it's sufficient to clear our pointer. */ - enum_blacklist = NULL; + uncommitted_enums = NULL; } @@ -691,12 +692,12 @@ sort_order_cmp(const void *p1, const void *p2) } Size -EstimateEnumBlacklistSpace(void) +EstimateUncommittedEnumsSpace(void) { size_t entries; - if (enum_blacklist) - entries = hash_get_num_entries(enum_blacklist); + if (uncommitted_enums) + entries = hash_get_num_entries(uncommitted_enums); else entries = 0; @@ -705,7 +706,7 @@ EstimateEnumBlacklistSpace(void) } void -SerializeEnumBlacklist(void *space, Size size) +SerializeUncommittedEnums(void *space, Size size) { Oid *serialized = (Oid *) space; @@ -713,15 +714,15 @@ SerializeEnumBlacklist(void *space, Size size) * Make sure the hash table hasn't changed in size since the caller * reserved the space. */ - Assert(size == EstimateEnumBlacklistSpace()); + Assert(size == EstimateUncommittedEnumsSpace()); /* Write out all the values from the hash table, if there is one. */ - if (enum_blacklist) + if (uncommitted_enums) { HASH_SEQ_STATUS status; Oid *value; - hash_seq_init(&status, enum_blacklist); + hash_seq_init(&status, uncommitted_enums); while ((value = (Oid *) hash_seq_search(&status))) *serialized++ = *value; } @@ -737,11 +738,11 @@ SerializeEnumBlacklist(void *space, Size size) } void -RestoreEnumBlacklist(void *space) +RestoreUncommittedEnums(void *space) { Oid *serialized = (Oid *) space; - Assert(!enum_blacklist); + Assert(!uncommitted_enums); /* * As a special case, if the list is empty then don't even bother to @@ -752,9 +753,9 @@ RestoreEnumBlacklist(void *space) return; /* Read all the values into a new hash table. */ - init_enum_blacklist(); + init_uncommitted_enums(); do { - hash_search(enum_blacklist, serialized++, HASH_ENTER, NULL); + hash_search(uncommitted_enums, serialized++, HASH_ENTER, NULL); } while (OidIsValid(*serialized)); } diff --git a/src/backend/utils/adt/enum.c b/src/backend/utils/adt/enum.c index 79117c4c904d8..0d892132a841d 100644 --- a/src/backend/utils/adt/enum.c +++ b/src/backend/utils/adt/enum.c @@ -82,12 +82,12 @@ check_safe_enum_use(HeapTuple enumval_tup) return; /* - * Check if the enum value is blacklisted. If not, it's safe, because it + * Check if the enum value is uncommitted. If not, it's safe, because it * was made during CREATE TYPE AS ENUM and can't be shorter-lived than its * owning type. (This'd also be false for values made by other * transactions; but the previous tests should have handled all of those.) */ - if (!EnumBlacklisted(en->oid)) + if (!EnumUncommitted(en->oid)) return; /* diff --git a/src/include/catalog/pg_enum.h b/src/include/catalog/pg_enum.h index 4cc4610589a7b..3ae7a03d4e1d7 100644 --- a/src/include/catalog/pg_enum.h +++ b/src/include/catalog/pg_enum.h @@ -60,10 +60,10 @@ extern void AddEnumLabel(Oid enumTypeOid, const char *newVal, bool skipIfExists); extern void RenameEnumLabel(Oid enumTypeOid, const char *oldVal, const char *newVal); -extern bool EnumBlacklisted(Oid enum_id); -extern Size EstimateEnumBlacklistSpace(void); -extern void SerializeEnumBlacklist(void *space, Size size); -extern void RestoreEnumBlacklist(void *space); +extern bool EnumUncommitted(Oid enum_id); +extern Size EstimateUncommittedEnumsSpace(void); +extern void SerializeUncommittedEnums(void *space, Size size); +extern void RestoreUncommittedEnums(void *space); extern void AtEOXact_Enum(void); #endif /* PG_ENUM_H */ From fe05b6b620066aec313c43b6b4d6c169d0a346f7 Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Tue, 5 Jan 2021 13:27:06 +1300 Subject: [PATCH 031/240] pgindent: whitelist/blacklist -> additional/excluded. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Author: Dagfinn Ilmari Mannsåker Discussion: https://postgr.es/m/20200615182235.x7lch5n6kcjq4aue%40alap3.anarazel.de --- src/tools/pgindent/pgindent | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/tools/pgindent/pgindent b/src/tools/pgindent/pgindent index 4124d27dea669..feb02067c5ad6 100755 --- a/src/tools/pgindent/pgindent +++ b/src/tools/pgindent/pgindent @@ -54,12 +54,12 @@ $excludes ||= "$code_base/src/tools/pgindent/exclude_file_patterns" # some names we want to treat like typedefs, e.g. "bool" (which is a macro # according to ), and may include some names we don't want # treated as typedefs, although various headers that some builds include -# might make them so. For the moment we just hardwire a whitelist of names -# to add and a blacklist of names to remove; eventually this may need to be +# might make them so. For the moment we just hardwire a list of names +# to add and a list of names to exclude; eventually this may need to be # easier to configure. Note that the typedefs need trailing newlines. -my @whitelist = ("bool\n"); +my @additional = ("bool\n"); -my %blacklist = map { +"$_\n" => 1 } qw( +my %excluded = map { +"$_\n" => 1 } qw( ANY FD_SET U abs allocfunc boolean date digit ilist interval iterator other pointer printfunc reference string timestamp type wrap ); @@ -134,11 +134,11 @@ sub load_typedefs } } - # add whitelisted entries - push(@typedefs, @whitelist); + # add additional entries + push(@typedefs, @additional); - # remove blacklisted entries - @typedefs = grep { !$blacklist{$_} } @typedefs; + # remove excluded entries + @typedefs = grep { !$excluded{$_} } @typedefs; # write filtered typedefs my $filter_typedefs_fh = new File::Temp(TEMPLATE => "pgtypedefXXXXX"); From 034510c820cd75e0410332d92b4967ef9b844936 Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Tue, 5 Jan 2021 14:00:16 +1300 Subject: [PATCH 032/240] Replace remaining uses of "whitelist". MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead describe the action that the list effects, or just use "list" where the meaning is obvious from context. Author: Dagfinn Ilmari Mannsåker Discussion: https://postgr.es/m/20200615182235.x7lch5n6kcjq4aue%40alap3.anarazel.de --- contrib/postgres_fdw/postgres_fdw.h | 2 +- contrib/postgres_fdw/shippable.c | 4 ++-- src/backend/access/hash/hashvalidate.c | 2 +- src/backend/utils/adt/lockfuncs.c | 2 +- src/tools/pginclude/README | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/contrib/postgres_fdw/postgres_fdw.h b/contrib/postgres_fdw/postgres_fdw.h index 277a30f5000da..19ea27a1bcdd0 100644 --- a/contrib/postgres_fdw/postgres_fdw.h +++ b/contrib/postgres_fdw/postgres_fdw.h @@ -77,7 +77,7 @@ typedef struct PgFdwRelationInfo bool use_remote_estimate; Cost fdw_startup_cost; Cost fdw_tuple_cost; - List *shippable_extensions; /* OIDs of whitelisted extensions */ + List *shippable_extensions; /* OIDs of shippable extensions */ /* Cached catalog information. */ ForeignTable *table; diff --git a/contrib/postgres_fdw/shippable.c b/contrib/postgres_fdw/shippable.c index c43e7e5ec594e..b27f82e015595 100644 --- a/contrib/postgres_fdw/shippable.c +++ b/contrib/postgres_fdw/shippable.c @@ -7,7 +7,7 @@ * data types are shippable to a remote server for execution --- that is, * do they exist and have the same behavior remotely as they do locally? * Built-in objects are generally considered shippable. Other objects can - * be shipped if they are white-listed by the user. + * be shipped if they are declared as such by the user. * * Note: there are additional filter rules that prevent shipping mutable * functions or functions using nonportable collations. Those considerations @@ -110,7 +110,7 @@ InitializeShippableCache(void) * * Right now "shippability" is exclusively a function of whether the object * belongs to an extension declared by the user. In the future we could - * additionally have a whitelist of functions/operators declared one at a time. + * additionally have a list of functions/operators declared one at a time. */ static bool lookup_shippable(Oid objectId, Oid classId, PgFdwRelationInfo *fpinfo) diff --git a/src/backend/access/hash/hashvalidate.c b/src/backend/access/hash/hashvalidate.c index 8462540017661..1e343df0afc55 100644 --- a/src/backend/access/hash/hashvalidate.c +++ b/src/backend/access/hash/hashvalidate.c @@ -312,7 +312,7 @@ check_hash_func_signature(Oid funcid, int16 amprocnum, Oid argtype) * that are different from but physically compatible with the opclass * datatype. In some of these cases, even a "binary coercible" check * fails because there's no relevant cast. For the moment, fix it by - * having a whitelist of allowed cases. Test the specific function + * having a list of allowed cases. Test the specific function * identity, not just its input type, because hashvarlena() takes * INTERNAL and allowing any such function seems too scary. */ diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c index 9f2c4946c9290..0db8be6c9173e 100644 --- a/src/backend/utils/adt/lockfuncs.c +++ b/src/backend/utils/adt/lockfuncs.c @@ -644,7 +644,7 @@ pg_isolation_test_session_is_blocked(PG_FUNCTION_ARGS) /* * Check if blocked_pid is waiting for a safe snapshot. We could in * theory check the resulting array of blocker PIDs against the - * interesting PIDs whitelist, but since there is no danger of autovacuum + * interesting PIDs list, but since there is no danger of autovacuum * blocking GetSafeSnapshot there seems to be no point in expending cycles * on allocating a buffer and searching for overlap; so it's presently * sufficient for the isolation tester's purposes to use a single element diff --git a/src/tools/pginclude/README b/src/tools/pginclude/README index a067c7f472a14..49eb4b6907996 100644 --- a/src/tools/pginclude/README +++ b/src/tools/pginclude/README @@ -64,7 +64,7 @@ with no prerequisite headers other than postgres.h (or postgres_fe.h or c.h, as appropriate). A small number of header files are exempted from this requirement, -and are whitelisted in the headerscheck script. +and are skipped by the headerscheck script. The easy way to run the script is to say "make -s headerscheck" in the top-level build directory after completing a build. You should @@ -86,7 +86,7 @@ the project's coding language is C, some people write extensions in C++, so it's helpful for include files to be C++-clean. A small number of header files are exempted from this requirement, -and are whitelisted in the cpluspluscheck script. +and are skipped by the cpluspluscheck script. The easy way to run the script is to say "make -s cpluspluscheck" in the top-level build directory after completing a build. You should From 9da2224ea2bb9801afc29bff6a325bf796868bdc Mon Sep 17 00:00:00 2001 From: Amit Kapila Date: Tue, 5 Jan 2021 07:56:40 +0530 Subject: [PATCH 033/240] Fix typo in reorderbuffer.c. Author: Zhijie Hou Reviewed-by: Sawada Masahiko Discussion: https://postgr.es/m/ba88bb58aaf14284abca16aec04bf279@G08CNEXMBPEKD05.g08.fujitsu.local --- src/backend/replication/logical/reorderbuffer.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c index 315bfe7cae27f..5a62ab8bbc1ac 100644 --- a/src/backend/replication/logical/reorderbuffer.c +++ b/src/backend/replication/logical/reorderbuffer.c @@ -2119,13 +2119,13 @@ ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn, * Mapped catalog tuple without data, emitted while * catalog table was in the process of being rewritten. We * can fail to look up the relfilenode, because the - * relmapper has no "historic" view, in contrast to normal - * the normal catalog during decoding. Thus repeated - * rewrites can cause a lookup failure. That's OK because - * we do not decode catalog changes anyway. Normally such - * tuples would be skipped over below, but we can't - * identify whether the table should be logically logged - * without mapping the relfilenode to the oid. + * relmapper has no "historic" view, in contrast to the + * normal catalog during decoding. Thus repeated rewrites + * can cause a lookup failure. That's OK because we do not + * decode catalog changes anyway. Normally such tuples + * would be skipped over below, but we can't identify + * whether the table should be logically logged without + * mapping the relfilenode to the oid. */ if (reloid == InvalidOid && change->data.tp.newtuple == NULL && From cd357c76296e987298e4005b8053adda9e3fb417 Mon Sep 17 00:00:00 2001 From: Amit Kapila Date: Tue, 5 Jan 2021 08:05:08 +0530 Subject: [PATCH 034/240] Fix typo in origin.c. Author: Peter Smith Discussion: https://postgr.es/m/CAHut+PsReyuvww_Fn1NN_Vsv0wBP1bnzuhzRFr_2=y1nNZrG7w@mail.gmail.com --- src/backend/replication/logical/origin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c index 0b01cce44e0c3..77781d059ddde 100644 --- a/src/backend/replication/logical/origin.c +++ b/src/backend/replication/logical/origin.c @@ -843,7 +843,7 @@ replorigin_redo(XLogReaderState *record) * that originated at the LSN remote_commit on the remote node was replayed * successfully and that we don't need to do so again. In combination with * setting up replorigin_session_origin_lsn and replorigin_session_origin - * that ensures we won't loose knowledge about that after a crash if the + * that ensures we won't lose knowledge about that after a crash if the * transaction had a persistent effect (think of asynchronous commits). * * local_commit needs to be a local LSN of the commit so that we can make sure From 83e3239ee77089f76fad022eeef91c83cdf9181d Mon Sep 17 00:00:00 2001 From: Peter Geoghegan Date: Mon, 4 Jan 2021 19:46:11 -0800 Subject: [PATCH 035/240] Standardize one aspect of rmgr desc output. Bring heap and hash rmgr desc output in line with nbtree and GiST desc output by using the name latestRemovedXid for all fields that output the contents of the latestRemovedXid field from the WAL record's C struct (stop using local variants). This seems like a clear improvement because latestRemovedXid is a symbol name that already appears across many different source files, and so is probably much more recognizable. Discussion: https://postgr.es/m/CAH2-Wzkt_Rs4VqPSCk87nyjPAAEmWL8STU9zgET_83EF5YfrLw@mail.gmail.com --- src/backend/access/rmgrdesc/hashdesc.c | 2 +- src/backend/access/rmgrdesc/heapdesc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/access/rmgrdesc/hashdesc.c b/src/backend/access/rmgrdesc/hashdesc.c index 55de27840d98d..90ccea08e2c49 100644 --- a/src/backend/access/rmgrdesc/hashdesc.c +++ b/src/backend/access/rmgrdesc/hashdesc.c @@ -113,7 +113,7 @@ hash_desc(StringInfo buf, XLogReaderState *record) { xl_hash_vacuum_one_page *xlrec = (xl_hash_vacuum_one_page *) rec; - appendStringInfo(buf, "ntuples %d, latest removed xid %u", + appendStringInfo(buf, "ntuples %d, latestRemovedXid %u", xlrec->ntuples, xlrec->latestRemovedXid); break; diff --git a/src/backend/access/rmgrdesc/heapdesc.c b/src/backend/access/rmgrdesc/heapdesc.c index 871c7a155e8c5..e60e32b9353de 100644 --- a/src/backend/access/rmgrdesc/heapdesc.c +++ b/src/backend/access/rmgrdesc/heapdesc.c @@ -125,7 +125,7 @@ heap2_desc(StringInfo buf, XLogReaderState *record) { xl_heap_clean *xlrec = (xl_heap_clean *) rec; - appendStringInfo(buf, "remxid %u", xlrec->latestRemovedXid); + appendStringInfo(buf, "latestRemovedXid %u", xlrec->latestRemovedXid); } else if (info == XLOG_HEAP2_FREEZE_PAGE) { @@ -138,7 +138,7 @@ heap2_desc(StringInfo buf, XLogReaderState *record) { xl_heap_cleanup_info *xlrec = (xl_heap_cleanup_info *) rec; - appendStringInfo(buf, "remxid %u", xlrec->latestRemovedXid); + appendStringInfo(buf, "latestRemovedXid %u", xlrec->latestRemovedXid); } else if (info == XLOG_HEAP2_VISIBLE) { From 854434c50a35e7cb2ae22588c80ebf36e889197a Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Tue, 5 Jan 2021 08:17:40 +0100 Subject: [PATCH 036/240] doc: Document how to run regression tests with custom server settings Author: Craig Ringer Discussion: https://www.postgresql.org/message-id/flat/CAMsr+YF=+ctXBZj3ywmvKNUjWpxmuTuUKuv-rgbHGX5i5pLstQ@mail.gmail.com --- doc/src/sgml/regress.sgml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/doc/src/sgml/regress.sgml b/doc/src/sgml/regress.sgml index 083d0bf46b891..890ec7c88ee74 100644 --- a/doc/src/sgml/regress.sgml +++ b/doc/src/sgml/regress.sgml @@ -351,6 +351,31 @@ make check LANG=C ENCODING=EUC_JP + + Custom Server Settings + + + Custom server settings to use when running a regression test suite can be + set in the PGOPTIONS environment variable (for settings + that allow this): + +make check PGOPTIONS="-c log_checkpoints=on -c work_mem=50MB" + + When running against a temporary installation, custom settings can also be + set by supplying a pre-written postgresql.conf: + +echo 'log_checkpoints = on' > test_postgresql.conf +echo 'work_mem = 50MB' >> test_postgresql.conf +make check EXTRA_REGRESS_OPTS="--temp-config=test_postgresql.conf" + + + + + This can be useful to enable additional logging, adjust resource limits, + or enable extra run-time checks. + + + Extra Tests From 5a3574d7b33480de51692962e6fd25d00c05718a Mon Sep 17 00:00:00 2001 From: Amit Kapila Date: Tue, 5 Jan 2021 15:05:22 +0530 Subject: [PATCH 037/240] Test decoding of two-phase transactions during the build of a consistent snapshot. Commit a271a1b50e added the capability to allow decoding at prepare time. This adds an isolation testcase to test that decoding happens at commit time when the consistent snapshot state is reached after prepare but before commit prepared. Author: Ajin Cherian Reviewed-by: Amit Kapila Discussion: https://postgr.es/m/02DA5F5E-CECE-4D9C-8B4B-418077E2C010@postgrespro.ru https://postgr.es/m/CAMGcDxeqEpWj3fTXwqhSwBdXd2RS9jzwWscO-XbeCfso6ts3+Q@mail.gmail.com --- contrib/test_decoding/Makefile | 3 +- .../expected/twophase_snapshot.out | 41 ++++++++++++++ .../specs/twophase_snapshot.spec | 53 +++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 contrib/test_decoding/expected/twophase_snapshot.out create mode 100644 contrib/test_decoding/specs/twophase_snapshot.spec diff --git a/contrib/test_decoding/Makefile b/contrib/test_decoding/Makefile index 76d4a6977269a..c5e28ce5cca78 100644 --- a/contrib/test_decoding/Makefile +++ b/contrib/test_decoding/Makefile @@ -7,7 +7,8 @@ REGRESS = ddl xact rewrite toast permissions decoding_in_xact \ decoding_into_rel binary prepared replorigin time messages \ spill slot truncate stream stats twophase twophase_stream ISOLATION = mxact delayed_startup ondisk_startup concurrent_ddl_dml \ - oldest_xmin snapshot_transfer subxact_without_top concurrent_stream + oldest_xmin snapshot_transfer subxact_without_top concurrent_stream \ + twophase_snapshot REGRESS_OPTS = --temp-config $(top_srcdir)/contrib/test_decoding/logical.conf ISOLATION_OPTS = --temp-config $(top_srcdir)/contrib/test_decoding/logical.conf diff --git a/contrib/test_decoding/expected/twophase_snapshot.out b/contrib/test_decoding/expected/twophase_snapshot.out new file mode 100644 index 0000000000000..3b7f23b5b4585 --- /dev/null +++ b/contrib/test_decoding/expected/twophase_snapshot.out @@ -0,0 +1,41 @@ +Parsed test spec with 3 sessions + +starting permutation: s2b s2txid s1init s3b s3txid s2c s2b s2insert s2p s3c s1insert s1start s2cp s1start +step s2b: BEGIN; +step s2txid: SELECT pg_current_xact_id() IS NULL; +?column? + +f +step s1init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding'); +step s3b: BEGIN; +step s3txid: SELECT pg_current_xact_id() IS NULL; +?column? + +f +step s2c: COMMIT; +step s2b: BEGIN; +step s2insert: INSERT INTO do_write DEFAULT VALUES; +step s2p: PREPARE TRANSACTION 'test1'; +step s3c: COMMIT; +step s1init: <... completed> +?column? + +init +step s1insert: INSERT INTO do_write DEFAULT VALUES; +step s1start: SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', 'false', 'two-phase-commit', '1'); +data + +BEGIN +table public.do_write: INSERT: id[integer]:2 +COMMIT +step s2cp: COMMIT PREPARED 'test1'; +step s1start: SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', 'false', 'two-phase-commit', '1'); +data + +BEGIN +table public.do_write: INSERT: id[integer]:1 +PREPARE TRANSACTION 'test1' +COMMIT PREPARED 'test1' +?column? + +stop diff --git a/contrib/test_decoding/specs/twophase_snapshot.spec b/contrib/test_decoding/specs/twophase_snapshot.spec new file mode 100644 index 0000000000000..bcaf68c6dc3ac --- /dev/null +++ b/contrib/test_decoding/specs/twophase_snapshot.spec @@ -0,0 +1,53 @@ +# Test decoding of two-phase transactions during the build of a consistent snapshot. +setup +{ + DROP TABLE IF EXISTS do_write; + CREATE TABLE do_write(id serial primary key); +} + +teardown +{ + DROP TABLE do_write; + SELECT 'stop' FROM pg_drop_replication_slot('isolation_slot'); +} + + +session "s1" +setup { SET synchronous_commit=on; } + +step "s1init" {SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');} +step "s1start" {SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', 'false', 'two-phase-commit', '1');} +step "s1insert" { INSERT INTO do_write DEFAULT VALUES; } + +session "s2" +setup { SET synchronous_commit=on; } + +step "s2b" { BEGIN; } +step "s2txid" { SELECT pg_current_xact_id() IS NULL; } +step "s2c" { COMMIT; } +step "s2insert" { INSERT INTO do_write DEFAULT VALUES; } +step "s2p" { PREPARE TRANSACTION 'test1'; } +step "s2cp" { COMMIT PREPARED 'test1'; } + + +session "s3" +setup { SET synchronous_commit=on; } + +step "s3b" { BEGIN; } +step "s3txid" { SELECT pg_current_xact_id() IS NULL; } +step "s3c" { COMMIT; } + +# Force building of a consistent snapshot between a PREPARE and COMMIT PREPARED +# and ensure that the whole transaction is decoded at the time of COMMIT +# PREPARED. +# +# 's1init' step will initialize the replication slot and cause logical decoding +# to wait in initial starting point till the in-progress transaction in s2 is +# committed. 's2c' step will cause logical decoding to go to initial consistent +# point and wait for in-progress transaction s3 to commit. 's3c' step will cause +# logical decoding to find a consistent point while the transaction s2 is +# prepared and not yet committed. This will cause the first s1start to skip +# prepared transaction s2 as that will be before consistent point. The second +# s1start will allow decoding of skipped prepare along with commit prepared done +# as part of s2cp. +permutation "s2b" "s2txid" "s1init" "s3b" "s3txid" "s2c" "s2b" "s2insert" "s2p" "s3c" "s1insert" "s1start" "s2cp" "s1start" From bc43b7c2c06c32264efe79d0b86abd41236f1d5b Mon Sep 17 00:00:00 2001 From: Dean Rasheed Date: Tue, 5 Jan 2021 11:15:28 +0000 Subject: [PATCH 038/240] Fix numeric_power() when the exponent is INT_MIN. In power_var_int(), the computation of the number of significant digits to use in the computation used log(Abs(exp)), which isn't safe because Abs(exp) returns INT_MIN when exp is INT_MIN. Use fabs() instead of Abs(), so that the exponent is cast to a double before the absolute value is taken. Back-patch to 9.6, where this was introduced (by 7d9a4737c2). Discussion: https://postgr.es/m/CAEZATCVd6pMkz=BrZEgBKyqqJrt2xghr=fNc8+Z=5xC6cgWrWA@mail.gmail.com --- src/backend/utils/adt/numeric.c | 2 +- src/test/regress/expected/numeric.out | 6 ++++++ src/test/regress/sql/numeric.sql | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index 68d879160a560..7cf56568f38a6 100644 --- a/src/backend/utils/adt/numeric.c +++ b/src/backend/utils/adt/numeric.c @@ -10290,7 +10290,7 @@ power_var_int(const NumericVar *base, int exp, NumericVar *result, int rscale) * to around log10(abs(exp)) digits, so work with this many extra digits * of precision (plus a few more for good measure). */ - sig_digits += (int) log(Abs(exp)) + 8; + sig_digits += (int) log(fabs(exp)) + 8; /* * Now we can proceed with the multiplications. diff --git a/src/test/regress/expected/numeric.out b/src/test/regress/expected/numeric.out index 56e7799497105..30a5642b95849 100644 --- a/src/test/regress/expected/numeric.out +++ b/src/test/regress/expected/numeric.out @@ -2321,6 +2321,12 @@ select 0.12 ^ (-20); 2608405330458882702.5529619561355838 (1 row) +select 1.000000000123 ^ (-2147483648); + ?column? +-------------------- + 0.7678656556403084 +(1 row) + -- cases that used to error out select 0.12 ^ (-25); ?column? diff --git a/src/test/regress/sql/numeric.sql b/src/test/regress/sql/numeric.sql index f19793af9cb09..db812c813a39b 100644 --- a/src/test/regress/sql/numeric.sql +++ b/src/test/regress/sql/numeric.sql @@ -1089,6 +1089,7 @@ select 3.789 ^ 21; select 3.789 ^ 35; select 1.2 ^ 345; select 0.12 ^ (-20); +select 1.000000000123 ^ (-2147483648); -- cases that used to error out select 0.12 ^ (-25); From fead67c24ada8c6a4b661dec6f159dca1447e3d8 Mon Sep 17 00:00:00 2001 From: Dean Rasheed Date: Tue, 5 Jan 2021 11:52:42 +0000 Subject: [PATCH 039/240] Add an explicit cast to double when using fabs(). Commit bc43b7c2c0 used fabs() directly on an int variable, which apparently requires an explicit cast on some platforms. Per buildfarm. --- src/backend/utils/adt/numeric.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index 7cf56568f38a6..682200f636b9b 100644 --- a/src/backend/utils/adt/numeric.c +++ b/src/backend/utils/adt/numeric.c @@ -10290,7 +10290,7 @@ power_var_int(const NumericVar *base, int exp, NumericVar *result, int rscale) * to around log10(abs(exp)) digits, so work with this many extra digits * of precision (plus a few more for good measure). */ - sig_digits += (int) log(fabs(exp)) + 8; + sig_digits += (int) log(fabs((double) exp)) + 8; /* * Now we can proceed with the multiplications. From 47b2ed1d06c1218eee8869c8eca8bf002b9d43a6 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Tue, 5 Jan 2021 14:26:37 -0500 Subject: [PATCH 040/240] doc: improve NLS instruction wording Reported-by: "Tang, Haiying" Discussion: https://postgr.es/m/bbbccf7a3c2d436e85d45869d612fd6b@G08CNEXMBPEKD05.g08.fujitsu.local Author: "Tang, Haiying" Backpatch-through: 9.5 --- doc/src/sgml/nls.sgml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/src/sgml/nls.sgml b/doc/src/sgml/nls.sgml index 3764d49f627eb..d49f44f3f23bf 100644 --- a/doc/src/sgml/nls.sgml +++ b/doc/src/sgml/nls.sgml @@ -90,7 +90,7 @@ msgstr "another translated" ... - The msgid's are extracted from the program source. (They need not + The msgid lines are extracted from the program source. (They need not be, but this is the most common way.) The msgstr lines are initially empty and are filled in with useful strings by the translator. The strings can contain C-style escape characters and @@ -113,7 +113,7 @@ msgstr "another translated" The #. style comments are extracted from the source file where the message is used. Possibly the programmer has inserted information for the translator, such as about expected alignment. The #: - comment indicates the exact location(s) where the message is used + comments indicate the exact locations where the message is used in the source. The translator need not look at the program source, but can if there is doubt about the correct translation. The #, comments contain flags that describe the From bf8a662c9afad6fd07b42cdc5e71416c51f75d31 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 5 Jan 2021 16:18:01 -0500 Subject: [PATCH 041/240] Introduce a new GUC_REPORT setting "in_hot_standby". Aside from being queriable via SHOW, this value is sent to the client immediately at session startup, and again later on if the server gets promoted to primary during the session. The immediate report will be used in an upcoming patch to avoid an extra round trip when trying to connect to a primary server. Haribabu Kommi, Greg Nancarrow, Tom Lane; reviewed at various times by Laurenz Albe, Takayuki Tsunakawa, Peter Smith. Discussion: https://postgr.es/m/CAF3+xM+8-ztOkaV9gHiJ3wfgENTq97QcjXQt+rbFQ6F7oNzt9A@mail.gmail.com --- doc/src/sgml/config.sgml | 31 ++++++++++++++---- doc/src/sgml/high-availability.sgml | 7 ++-- doc/src/sgml/libpq.sgml | 6 +++- doc/src/sgml/protocol.sgml | 6 +++- src/backend/utils/misc/check_guc | 2 +- src/backend/utils/misc/guc.c | 50 +++++++++++++++++++++++++++++ 6 files changed, 91 insertions(+), 11 deletions(-) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 67de4150b8e48..2a90d011db53b 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -9600,13 +9600,14 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir' Preset Options - The following parameters are read-only, and are determined - when PostgreSQL is compiled or when it is - installed. As such, they have been excluded from the sample + The following parameters are read-only. + As such, they have been excluded from the sample postgresql.conf file. These options report various aspects of PostgreSQL behavior that might be of interest to certain applications, particularly administrative front-ends. + Most of them are determined when PostgreSQL + is compiled or when it is installed. @@ -9651,10 +9652,11 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir' - On Unix systems this parameter reports the permissions of the data - directory defined by () at startup. + On Unix systems this parameter reports the permissions the data + directory (defined by ) + had at server startup. (On Microsoft Windows this parameter will always display - 0700). See + 0700.) See for more information. @@ -9695,6 +9697,23 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir' + + in_hot_standby (boolean) + + in_hot_standby configuration parameter + + + + + Reports whether the server is currently in hot standby mode. When + this is on, all transactions are forced to be + read-only. Within a session, this can change only if the server is + promoted to be primary. See for more + information. + + + + lc_collate (string) diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml index 19d7bd2b28faa..04f75020e44cb 100644 --- a/doc/src/sgml/high-availability.sgml +++ b/doc/src/sgml/high-availability.sgml @@ -1859,8 +1859,11 @@ if (!triggered) - Users will be able to tell whether their session is read-only by - issuing SHOW transaction_read_only. In addition, a set of + Users can determine whether hot standby is currently active for their + session by issuing SHOW in_hot_standby. + (In server versions before 14, the in_hot_standby + parameter did not exist; a workable substitute method for older servers + is SHOW transaction_read_only.) In addition, a set of functions () allow users to access information about the standby server. These allow you to write programs that are aware of the current state of the database. These diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index a5db58d46806c..2bb3bf77e432d 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -2150,6 +2150,7 @@ const char *PQparameterStatus(const PGconn *conn, const char *paramName); server_encoding, client_encoding, application_name, + in_hot_standby, is_superuser, session_authorization, DateStyle, @@ -2162,7 +2163,10 @@ const char *PQparameterStatus(const PGconn *conn, const char *paramName); standard_conforming_strings was not reported by releases before 8.1; IntervalStyle was not reported by releases before 8.4; - application_name was not reported by releases before 9.0.) + application_name was not reported by releases before + 9.0; + in_hot_standby was not reported by releases before + 14.) Note that server_version, server_encoding and diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml index 98b42bb269231..24f7b21ecbd45 100644 --- a/doc/src/sgml/protocol.sgml +++ b/doc/src/sgml/protocol.sgml @@ -1278,6 +1278,7 @@ SELCT 1/0; server_encoding, client_encoding, application_name, + in_hot_standby, is_superuser, session_authorization, DateStyle, @@ -1290,7 +1291,10 @@ SELCT 1/0; standard_conforming_strings was not reported by releases before 8.1; IntervalStyle was not reported by releases before 8.4; - application_name was not reported by releases before 9.0.) + application_name was not reported by releases before + 9.0; + in_hot_standby was not reported by releases before + 14.) Note that server_version, server_encoding and diff --git a/src/backend/utils/misc/check_guc b/src/backend/utils/misc/check_guc index 416a0875b6c93..b171ef0e4ff3f 100755 --- a/src/backend/utils/misc/check_guc +++ b/src/backend/utils/misc/check_guc @@ -16,7 +16,7 @@ ## if an option is valid but shows up in only one file (guc.c but not ## postgresql.conf.sample), it should be listed here so that it ## can be ignored -INTENTIONALLY_NOT_INCLUDED="debug_deadlocks \ +INTENTIONALLY_NOT_INCLUDED="debug_deadlocks in_hot_standby \ is_superuser lc_collate lc_ctype lc_messages lc_monetary lc_numeric lc_time \ pre_auth_delay role seed server_encoding server_version server_version_num \ session_authorization trace_lock_oidmin trace_lock_table trace_locks trace_lwlocks \ diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 2779da8a6936b..383b7d0d710c2 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -209,6 +209,7 @@ static bool check_cluster_name(char **newval, void **extra, GucSource source); static const char *show_unix_socket_permissions(void); static const char *show_log_file_mode(void); static const char *show_data_directory_mode(void); +static const char *show_in_hot_standby(void); static bool check_backtrace_functions(char **newval, void **extra, GucSource source); static void assign_backtrace_functions(const char *newval, void *extra); static bool check_recovery_target_timeline(char **newval, void **extra, GucSource source); @@ -610,6 +611,7 @@ static int wal_block_size; static bool data_checksums; static bool integer_datetimes; static bool assert_enabled; +static bool in_hot_standby; static char *recovery_target_timeline_string; static char *recovery_target_string; static char *recovery_target_xid_string; @@ -1844,6 +1846,17 @@ static struct config_bool ConfigureNamesBool[] = NULL, NULL, NULL }, + { + {"in_hot_standby", PGC_INTERNAL, PRESET_OPTIONS, + gettext_noop("Shows whether hot standby is currently active."), + NULL, + GUC_REPORT | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE + }, + &in_hot_standby, + false, + NULL, NULL, show_in_hot_standby + }, + { {"allow_system_table_mods", PGC_SUSET, DEVELOPER_OPTIONS, gettext_noop("Allows modifications of the structure of system tables."), @@ -6248,6 +6261,14 @@ BeginReportingGUCOptions(void) reporting_enabled = true; + /* + * Hack for in_hot_standby: initialize with the value we're about to send. + * (This could be out of date by the time we actually send it, in which + * case the next ReportChangedGUCOptions call will send a duplicate + * report.) + */ + in_hot_standby = RecoveryInProgress(); + /* Transmit initial values of interesting variables */ for (i = 0; i < num_guc_variables; i++) { @@ -6280,6 +6301,23 @@ ReportChangedGUCOptions(void) if (!reporting_enabled) return; + /* + * Since in_hot_standby isn't actually changed by normal GUC actions, we + * need a hack to check whether a new value needs to be reported to the + * client. For speed, we rely on the assumption that it can never + * transition from false to true. + */ + if (in_hot_standby && !RecoveryInProgress()) + { + struct config_generic *record; + + record = find_option("in_hot_standby", false, ERROR); + Assert(record != NULL); + record->status |= GUC_NEEDS_REPORT; + report_needed = true; + in_hot_standby = false; + } + /* Quick exit if no values have been changed */ if (!report_needed) return; @@ -11773,6 +11811,18 @@ show_data_directory_mode(void) return buf; } +static const char * +show_in_hot_standby(void) +{ + /* + * We display the actual state based on shared memory, so that this GUC + * reports up-to-date state if examined intra-query. The underlying + * variable in_hot_standby changes only when we transmit a new value to + * the client. + */ + return RecoveryInProgress() ? "on" : "off"; +} + /* * We split the input string, where commas separate function names * and certain whitespace chars are ignored, into a \0-separated (and From 7d80441d2c8de5cd5d593e302bd14e8b19ee92d4 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 5 Jan 2021 18:41:50 -0500 Subject: [PATCH 042/240] Allow psql's \dt and \di to show TOAST tables and their indexes. Formerly, TOAST objects were unconditionally suppressed, but since \d is able to print them it's not very clear why these variants should not. Instead, use the same rules as for system catalogs: they can be seen if you write the 'S' modifier or a table name pattern. (In practice, since hardly anybody would keep pg_toast in their search_path, it's really down to whether you use a pattern that can match pg_toast.*.) No docs change seems necessary because the docs already say that this happens for "system objects"; we're just classifying TOAST tables as being that. Justin Pryzby, reviewed by Laurenz Albe Discussion: https://postgr.es/m/20201130165436.GX24052@telsasoft.com --- src/bin/psql/describe.c | 27 +++++++++------------------ src/test/regress/expected/psql.out | 14 ++++++++++++++ src/test/regress/sql/psql.sql | 2 ++ 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index 52c6de51b62d5..caf97563f4871 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -3718,6 +3718,7 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys " WHEN " CppAsString2(RELKIND_INDEX) " THEN '%s'" " WHEN " CppAsString2(RELKIND_SEQUENCE) " THEN '%s'" " WHEN 's' THEN '%s'" + " WHEN " CppAsString2(RELKIND_TOASTVALUE) " THEN '%s'" " WHEN " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN '%s'" " WHEN " CppAsString2(RELKIND_PARTITIONED_TABLE) " THEN '%s'" " WHEN " CppAsString2(RELKIND_PARTITIONED_INDEX) " THEN '%s'" @@ -3731,6 +3732,7 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys gettext_noop("index"), gettext_noop("sequence"), gettext_noop("special"), + gettext_noop("TOAST table"), gettext_noop("foreign table"), gettext_noop("partitioned table"), gettext_noop("partitioned index"), @@ -3813,8 +3815,13 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys appendPQExpBufferStr(&buf, "\nWHERE c.relkind IN ("); if (showTables) + { appendPQExpBufferStr(&buf, CppAsString2(RELKIND_RELATION) "," CppAsString2(RELKIND_PARTITIONED_TABLE) ","); + /* with 'S' or a pattern, allow 't' to match TOAST tables too */ + if (showSystem || pattern) + appendPQExpBufferStr(&buf, CppAsString2(RELKIND_TOASTVALUE) ","); + } if (showViews) appendPQExpBufferStr(&buf, CppAsString2(RELKIND_VIEW) ","); if (showMatViews) @@ -3834,17 +3841,9 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys if (!showSystem && !pattern) appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n" + " AND n.nspname !~ '^pg_toast'\n" " AND n.nspname <> 'information_schema'\n"); - /* - * TOAST objects are suppressed unconditionally. Since we don't provide - * any way to select RELKIND_TOASTVALUE above, we would never show toast - * tables in any case; it seems a bit confusing to allow their indexes to - * be shown. Use plain \d if you really need to look at a TOAST - * table/index. - */ - appendPQExpBufferStr(&buf, " AND n.nspname !~ '^pg_toast'\n"); - processSQLNamePattern(pset.db, &buf, pattern, true, false, "n.nspname", "c.relname", NULL, "pg_catalog.pg_table_is_visible(c.oid)"); @@ -4057,17 +4056,9 @@ listPartitionedTables(const char *reltypes, const char *pattern, bool verbose) if (!pattern) appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n" + " AND n.nspname !~ '^pg_toast'\n" " AND n.nspname <> 'information_schema'\n"); - /* - * TOAST objects are suppressed unconditionally. Since we don't provide - * any way to select RELKIND_TOASTVALUE above, we would never show toast - * tables in any case; it seems a bit confusing to allow their indexes to - * be shown. Use plain \d if you really need to look at a TOAST - * table/index. - */ - appendPQExpBufferStr(&buf, " AND n.nspname !~ '^pg_toast'\n"); - processSQLNamePattern(pset.db, &buf, pattern, true, false, "n.nspname", "c.relname", NULL, "pg_catalog.pg_table_is_visible(c.oid)"); diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out index 7204fdb0b439c..d3134ecb2f433 100644 --- a/src/test/regress/expected/psql.out +++ b/src/test/regress/expected/psql.out @@ -4895,6 +4895,20 @@ Owning table: "pg_catalog.pg_statistic" Indexes: "pg_toast_2619_index" PRIMARY KEY, btree (chunk_id, chunk_seq) +\dt pg_toast.pg_toast_2619 + List of relations + Schema | Name | Type | Owner +----------+---------------+-------------+---------- + pg_toast | pg_toast_2619 | TOAST table | postgres +(1 row) + +\di pg_toast.pg_toast_2619_index + List of relations + Schema | Name | Type | Owner | Table +----------+---------------------+-------+----------+--------------- + pg_toast | pg_toast_2619_index | index | postgres | pg_toast_2619 +(1 row) + -- check printing info about access methods \dA List of access methods diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql index 537d5332aa90c..2cb9da8bff954 100644 --- a/src/test/regress/sql/psql.sql +++ b/src/test/regress/sql/psql.sql @@ -1210,6 +1210,8 @@ drop role regress_partitioning_role; -- \d on toast table (use pg_statistic's toast table, which has a known name) \d pg_toast.pg_toast_2619 +\dt pg_toast.pg_toast_2619 +\di pg_toast.pg_toast_2619_index -- check printing info about access methods \dA From 14d49f483d4c8a5a356e25d5e5ff5726ca43abff Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 5 Jan 2021 19:03:56 -0500 Subject: [PATCH 043/240] Revert unstable test cases from commit 7d80441d2. I momentarily forgot that the "owner" column wouldn't be stable in the buildfarm. Oh well, these tests weren't very valuable anyway. Discussion: https://postgr.es/m/20201130165436.GX24052@telsasoft.com --- src/test/regress/expected/psql.out | 14 -------------- src/test/regress/sql/psql.sql | 2 -- 2 files changed, 16 deletions(-) diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out index d3134ecb2f433..7204fdb0b439c 100644 --- a/src/test/regress/expected/psql.out +++ b/src/test/regress/expected/psql.out @@ -4895,20 +4895,6 @@ Owning table: "pg_catalog.pg_statistic" Indexes: "pg_toast_2619_index" PRIMARY KEY, btree (chunk_id, chunk_seq) -\dt pg_toast.pg_toast_2619 - List of relations - Schema | Name | Type | Owner -----------+---------------+-------------+---------- - pg_toast | pg_toast_2619 | TOAST table | postgres -(1 row) - -\di pg_toast.pg_toast_2619_index - List of relations - Schema | Name | Type | Owner | Table -----------+---------------------+-------+----------+--------------- - pg_toast | pg_toast_2619_index | index | postgres | pg_toast_2619 -(1 row) - -- check printing info about access methods \dA List of access methods diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql index 2cb9da8bff954..537d5332aa90c 100644 --- a/src/test/regress/sql/psql.sql +++ b/src/test/regress/sql/psql.sql @@ -1210,8 +1210,6 @@ drop role regress_partitioning_role; -- \d on toast table (use pg_statistic's toast table, which has a known name) \d pg_toast.pg_toast_2619 -\dt pg_toast.pg_toast_2619 -\di pg_toast.pg_toast_2619_index -- check printing info about access methods \dA From bc08f7971c03550ede43af43e73d4a47a7935c69 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Wed, 6 Jan 2021 10:52:26 +0900 Subject: [PATCH 044/240] Promote --data-checksums to the common set of options in initdb --help This was previously part of the section dedicated to less common options, but it is an option commonly used these days. Author: Michael Banck Reviewed-by: Stephen Frost, Michael Paquier Discussion: https://postgr.es/m/d7938aca4d4ea8e8c72c33bd75efe9f8218fe390.camel@credativ.de --- src/bin/initdb/initdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index 4453aeb0f0ff3..c854221a30602 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -2275,6 +2275,7 @@ usage(const char *progname) printf(_(" [-D, --pgdata=]DATADIR location for this database cluster\n")); printf(_(" -E, --encoding=ENCODING set default encoding for new databases\n")); printf(_(" -g, --allow-group-access allow group read/execute on data directory\n")); + printf(_(" -k, --data-checksums use data page checksums\n")); printf(_(" --locale=LOCALE set default locale for new databases\n")); printf(_(" --lc-collate=, --lc-ctype=, --lc-messages=LOCALE\n" " --lc-monetary=, --lc-numeric=, --lc-time=LOCALE\n" @@ -2290,7 +2291,6 @@ usage(const char *progname) printf(_(" --wal-segsize=SIZE size of WAL segments, in megabytes\n")); printf(_("\nLess commonly used options:\n")); printf(_(" -d, --debug generate lots of debugging output\n")); - printf(_(" -k, --data-checksums use data page checksums\n")); printf(_(" -L DIRECTORY where to find the input files\n")); printf(_(" -n, --no-clean do not clean up after errors\n")); printf(_(" -N, --no-sync do not wait for changes to be written safely to disk\n")); From 25dde5835772a58356383bf1112c6c2a1a37df0e Mon Sep 17 00:00:00 2001 From: Fujii Masao Date: Wed, 6 Jan 2021 11:58:23 +0900 Subject: [PATCH 045/240] doc: Fix description about default behavior of recovery_target_timeline. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The default value of recovery_target_timeline was changed in v12, but the description about the default behavior of that was not updated. Back-patch to v12 where the default behavior of recovery_target_timeline was changed. Author: Benoit Lobréau Reviewed-by: Fujii Masao Discussion: https://postgr.es/m/CAPE8EZ7c3aruEmM24GYkj8y8WmHKD1m9TtPtgCF0nQ3zw4LCkQ@mail.gmail.com --- doc/src/sgml/backup.sgml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml index 42a8ed328d886..3c8aaed0b6203 100644 --- a/doc/src/sgml/backup.sgml +++ b/doc/src/sgml/backup.sgml @@ -1437,12 +1437,13 @@ restore_command = 'cp /mnt/server/archivedir/%f %p' - The default behavior of recovery is to recover along the same timeline - that was current when the base backup was taken. If you wish to recover - into some child timeline (that is, you want to return to some state that - was itself generated after a recovery attempt), you need to specify the - target timeline ID in . You cannot recover into - timelines that branched off earlier than the base backup. + The default behavior of recovery is to recover to the latest timeline found + in the archive. If you wish to recover to the timeline that was current + when the base backup was taken or into a specific child timeline (that + is, you want to return to some state that was itself generated after a + recovery attempt), you need to specify current or the + target timeline ID in . You + cannot recover into timelines that branched off earlier than the base backup. From e02e840ff7787d4798fca9f6a5b8b3657f45cf0c Mon Sep 17 00:00:00 2001 From: Amit Kapila Date: Wed, 6 Jan 2021 08:56:19 +0530 Subject: [PATCH 046/240] Fix typos in decode.c and logical.c. Per report by Ajin Cherian in email: https://postgr.es/m/CAFPTHDYnRKDvzgDxoMn_CKqXA-D0MtrbyJvfvjBsO4G=UHDXkg@mail.gmail.com --- src/backend/replication/logical/decode.c | 8 ++++---- src/backend/replication/logical/logical.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c index 23ab3cf605246..afa1df00d0eaf 100644 --- a/src/backend/replication/logical/decode.c +++ b/src/backend/replication/logical/decode.c @@ -685,10 +685,10 @@ DecodeCommit(LogicalDecodingContext *ctx, XLogRecordBuffer *buf, * so during startup, to get to the first transaction the client needs. As * we have reset the catalog caches before starting to read WAL, and we * haven't yet touched any catalogs, there can't be anything to invalidate. - * But if we're "forgetting" this commit because it's it happened in - * another database, the invalidations might be important, because they - * could be for shared catalogs and we might have loaded data into the - * relevant syscaches. + * But if we're "forgetting" this commit because it happened in another + * database, the invalidations might be important, because they could be + * for shared catalogs and we might have loaded data into the relevant + * syscaches. * --- */ if (DecodeTXNNeedSkip(ctx, buf, parsed->dbId, origin_id)) diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c index 605ec0986caa3..0977aec711cff 100644 --- a/src/backend/replication/logical/logical.c +++ b/src/backend/replication/logical/logical.c @@ -1371,7 +1371,7 @@ stream_commit_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, ctx->write_xid = txn->xid; ctx->write_location = txn->end_lsn; - /* in streaming mode, stream_abort_cb is required */ + /* in streaming mode, stream_commit_cb is required */ if (ctx->callbacks.stream_commit_cb == NULL) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), From 8900b5a9d59a645b3485f5b046c4c7871b2c4026 Mon Sep 17 00:00:00 2001 From: Fujii Masao Date: Wed, 6 Jan 2021 12:39:18 +0900 Subject: [PATCH 047/240] Detect the deadlocks between backends and the startup process. The deadlocks that the recovery conflict on lock is involved in can happen between hot-standby backends and the startup process. If a backend takes an access exclusive lock on the table and which finally triggers the deadlock, that deadlock can be detected as expected. On the other hand, previously, if the startup process took an access exclusive lock and which finally triggered the deadlock, that deadlock could not be detected and could remain even after deadlock_timeout passed. This is a bug. The cause of this bug was that the code for handling the recovery conflict on lock didn't take care of deadlock case at all. It assumed that deadlocks involving the startup process and backends were able to be detected by the deadlock detector invoked within backends. But this assumption was incorrect. The startup process also should have invoked the deadlock detector if necessary. To fix this bug, this commit makes the startup process invoke the deadlock detector if deadlock_timeout is reached while handling the recovery conflict on lock. Specifically, in that case, the startup process requests all the backends holding the conflicting locks to check themselves for deadlocks. Back-patch to v9.6. v9.5 has also this bug, but per discussion we decided not to back-patch the fix to v9.5. Because v9.5 doesn't have some infrastructure codes (e.g., 37c54863cf) that this bug fix patch depends on. We can apply those codes for the back-patch, but since the next minor version release is the final one for v9.5, it's risky to do that. If we unexpectedly introduce new bug to v9.5 by the back-patch, there is no chance to fix that. We determined that the back-patch to v9.5 would give more risk than gain. Author: Fujii Masao Reviewed-by: Bertrand Drouvot, Masahiko Sawada, Kyotaro Horiguchi Discussion: https://postgr.es/m/4041d6b6-cf24-a120-36fa-1294220f8243@oss.nttdata.com --- src/backend/storage/ipc/procarray.c | 9 +- src/backend/storage/ipc/standby.c | 143 ++++++++++++++++++++++------ src/backend/storage/lmgr/proc.c | 3 + src/backend/tcop/postgres.c | 16 +++- src/include/storage/procarray.h | 2 + 5 files changed, 141 insertions(+), 32 deletions(-) diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index 2d202b8ebda57..cf12eda504113 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -3324,6 +3324,13 @@ GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid) */ pid_t CancelVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode) +{ + return SignalVirtualTransaction(vxid, sigmode, true); +} + +pid_t +SignalVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode, + bool conflictPending) { ProcArrayStruct *arrayP = procArray; int index; @@ -3342,7 +3349,7 @@ CancelVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode) if (procvxid.backendId == vxid.backendId && procvxid.localTransactionId == vxid.localTransactionId) { - proc->recoveryConflictPending = true; + proc->recoveryConflictPending = conflictPending; pid = proc->pid; if (pid != 0) { diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c index cd54ae42793fc..77e81bdbc0f5e 100644 --- a/src/backend/storage/ipc/standby.c +++ b/src/backend/storage/ipc/standby.c @@ -42,6 +42,10 @@ int max_standby_streaming_delay = 30 * 1000; static HTAB *RecoveryLockLists; +/* Flags set by timeout handlers */ +static volatile sig_atomic_t got_standby_deadlock_timeout = false; +static volatile sig_atomic_t got_standby_lock_timeout = false; + static void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, ProcSignalReason reason, uint32 wait_event_info, @@ -397,8 +401,10 @@ ResolveRecoveryConflictWithDatabase(Oid dbid) * lock. As we are already queued to be granted the lock, no new lock * requests conflicting with ours will be granted in the meantime. * - * Deadlocks involving the Startup process and an ordinary backend process - * will be detected by the deadlock detector within the ordinary backend. + * We also must check for deadlocks involving the Startup process and + * hot-standby backend processes. If deadlock_timeout is reached in + * this function, all the backends holding the conflicting locks are + * requested to check themselves for deadlocks. */ void ResolveRecoveryConflictWithLock(LOCKTAG locktag) @@ -409,7 +415,7 @@ ResolveRecoveryConflictWithLock(LOCKTAG locktag) ltime = GetStandbyLimitTime(); - if (GetCurrentTimestamp() >= ltime) + if (GetCurrentTimestamp() >= ltime && ltime != 0) { /* * We're already behind, so clear a path as quickly as possible. @@ -431,19 +437,76 @@ ResolveRecoveryConflictWithLock(LOCKTAG locktag) else { /* - * Wait (or wait again) until ltime + * Wait (or wait again) until ltime, and check for deadlocks as well + * if we will be waiting longer than deadlock_timeout */ - EnableTimeoutParams timeouts[1]; + EnableTimeoutParams timeouts[2]; + int cnt = 0; + + if (ltime != 0) + { + got_standby_lock_timeout = false; + timeouts[cnt].id = STANDBY_LOCK_TIMEOUT; + timeouts[cnt].type = TMPARAM_AT; + timeouts[cnt].fin_time = ltime; + cnt++; + } - timeouts[0].id = STANDBY_LOCK_TIMEOUT; - timeouts[0].type = TMPARAM_AT; - timeouts[0].fin_time = ltime; - enable_timeouts(timeouts, 1); + got_standby_deadlock_timeout = false; + timeouts[cnt].id = STANDBY_DEADLOCK_TIMEOUT; + timeouts[cnt].type = TMPARAM_AFTER; + timeouts[cnt].delay_ms = DeadlockTimeout; + cnt++; + + enable_timeouts(timeouts, cnt); } /* Wait to be signaled by the release of the Relation Lock */ ProcWaitForSignal(PG_WAIT_LOCK | locktag.locktag_type); + /* + * Exit if ltime is reached. Then all the backends holding conflicting + * locks will be canceled in the next ResolveRecoveryConflictWithLock() + * call. + */ + if (got_standby_lock_timeout) + goto cleanup; + + if (got_standby_deadlock_timeout) + { + VirtualTransactionId *backends; + + backends = GetLockConflicts(&locktag, AccessExclusiveLock, NULL); + + /* Quick exit if there's no work to be done */ + if (!VirtualTransactionIdIsValid(*backends)) + goto cleanup; + + /* + * Send signals to all the backends holding the conflicting locks, to + * ask them to check themselves for deadlocks. + */ + while (VirtualTransactionIdIsValid(*backends)) + { + SignalVirtualTransaction(*backends, + PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK, + false); + backends++; + } + + /* + * Wait again here to be signaled by the release of the Relation Lock, + * to prevent the subsequent RecoveryConflictWithLock() from causing + * deadlock_timeout and sending a request for deadlocks check again. + * Otherwise the request continues to be sent every deadlock_timeout + * until the relation locks are released or ltime is reached. + */ + got_standby_deadlock_timeout = false; + ProcWaitForSignal(PG_WAIT_LOCK | locktag.locktag_type); + } + +cleanup: + /* * Clear any timeout requests established above. We assume here that the * Startup process doesn't have any other outstanding timeouts than those @@ -451,6 +514,8 @@ ResolveRecoveryConflictWithLock(LOCKTAG locktag) * timeouts individually, but that'd be slower. */ disable_all_timeouts(false); + got_standby_lock_timeout = false; + got_standby_deadlock_timeout = false; } /* @@ -489,15 +554,7 @@ ResolveRecoveryConflictWithBufferPin(void) ltime = GetStandbyLimitTime(); - if (ltime == 0) - { - /* - * We're willing to wait forever for conflicts, so set timeout for - * deadlock check only - */ - enable_timeout_after(STANDBY_DEADLOCK_TIMEOUT, DeadlockTimeout); - } - else if (GetCurrentTimestamp() >= ltime) + if (GetCurrentTimestamp() >= ltime && ltime != 0) { /* * We're already behind, so clear a path as quickly as possible. @@ -511,14 +568,23 @@ ResolveRecoveryConflictWithBufferPin(void) * waiting longer than deadlock_timeout */ EnableTimeoutParams timeouts[2]; + int cnt = 0; - timeouts[0].id = STANDBY_TIMEOUT; - timeouts[0].type = TMPARAM_AT; - timeouts[0].fin_time = ltime; - timeouts[1].id = STANDBY_DEADLOCK_TIMEOUT; - timeouts[1].type = TMPARAM_AFTER; - timeouts[1].delay_ms = DeadlockTimeout; - enable_timeouts(timeouts, 2); + if (ltime != 0) + { + timeouts[cnt].id = STANDBY_TIMEOUT; + timeouts[cnt].type = TMPARAM_AT; + timeouts[cnt].fin_time = ltime; + cnt++; + } + + got_standby_deadlock_timeout = false; + timeouts[cnt].id = STANDBY_DEADLOCK_TIMEOUT; + timeouts[cnt].type = TMPARAM_AFTER; + timeouts[cnt].delay_ms = DeadlockTimeout; + cnt++; + + enable_timeouts(timeouts, cnt); } /* @@ -531,6 +597,25 @@ ResolveRecoveryConflictWithBufferPin(void) */ ProcWaitForSignal(PG_WAIT_BUFFER_PIN); + if (got_standby_deadlock_timeout) + { + /* + * Send out a request for hot-standby backends to check themselves for + * deadlocks. + * + * XXX The subsequent ResolveRecoveryConflictWithBufferPin() will wait + * to be signaled by UnpinBuffer() again and send a request for + * deadlocks check if deadlock_timeout happens. This causes the + * request to continue to be sent every deadlock_timeout until the + * buffer is unpinned or ltime is reached. This would increase the + * workload in the startup process and backends. In practice it may + * not be so harmful because the period that the buffer is kept pinned + * is basically no so long. But we should fix this? + */ + SendRecoveryConflictWithBufferPin( + PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK); + } + /* * Clear any timeout requests established above. We assume here that the * Startup process doesn't have any other timeouts than what this function @@ -538,6 +623,7 @@ ResolveRecoveryConflictWithBufferPin(void) * individually, but that'd be slower. */ disable_all_timeouts(false); + got_standby_deadlock_timeout = false; } static void @@ -597,13 +683,12 @@ CheckRecoveryConflictDeadlock(void) /* * StandbyDeadLockHandler() will be called if STANDBY_DEADLOCK_TIMEOUT - * occurs before STANDBY_TIMEOUT. Send out a request for hot-standby - * backends to check themselves for deadlocks. + * occurs before STANDBY_TIMEOUT. */ void StandbyDeadLockHandler(void) { - SendRecoveryConflictWithBufferPin(PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK); + got_standby_deadlock_timeout = true; } /* @@ -622,11 +707,11 @@ StandbyTimeoutHandler(void) /* * StandbyLockTimeoutHandler() will be called if STANDBY_LOCK_TIMEOUT is exceeded. - * This doesn't need to do anything, simply waking up is enough. */ void StandbyLockTimeoutHandler(void) { + got_standby_lock_timeout = true; } /* diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 57717f666d3d8..9b6aa2fe0de05 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -1793,6 +1793,9 @@ CheckDeadLockAlert(void) * Have to set the latch again, even if handle_sig_alarm already did. Back * then got_deadlock_timeout wasn't yet set... It's unlikely that this * ever would be a problem, but setting a set latch again is cheap. + * + * Note that, when this function runs inside procsignal_sigusr1_handler(), + * the handler function sets the latch again after the latch is set here. */ SetLatch(MyLatch); errno = save_errno; diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index f5c14249d13db..9d98c028a2ddd 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -2950,11 +2950,23 @@ RecoveryConflictInterrupt(ProcSignalReason reason) case PROCSIG_RECOVERY_CONFLICT_BUFFERPIN: /* - * If we aren't blocking the Startup process there is nothing - * more to do. + * If PROCSIG_RECOVERY_CONFLICT_BUFFERPIN is requested but we + * aren't blocking the Startup process there is nothing more + * to do. + * + * When PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK is + * requested, if we're waiting for locks and the startup + * process is not waiting for buffer pin (i.e., also waiting + * for locks), we set the flag so that ProcSleep() will check + * for deadlocks. */ if (!HoldingBufferPinThatDelaysRecovery()) + { + if (reason == PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK && + GetStartupBufferPinWaitBufId() < 0) + CheckDeadLockAlert(); return; + } MyProc->recoveryConflictPending = true; diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h index f40b20f7eac84..b01fa52139af3 100644 --- a/src/include/storage/procarray.h +++ b/src/include/storage/procarray.h @@ -72,6 +72,8 @@ extern VirtualTransactionId *GetCurrentVirtualXIDs(TransactionId limitXmin, int *nvxids); extern VirtualTransactionId *GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid); extern pid_t CancelVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode); +extern pid_t SignalVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode, + bool conflictPending); extern bool MinimumActiveBackends(int min); extern int CountDBBackends(Oid databaseid); From 4656e3d66893f286767285cf74dabb3877068e49 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Wed, 6 Jan 2021 10:15:19 +0100 Subject: [PATCH 048/240] Replace CLOBBER_CACHE_ALWAYS with run-time GUC Forced cache invalidation (CLOBBER_CACHE_ALWAYS) has been impractical to use for testing in PostgreSQL because it's so slow and because it's toggled on/off only at build time. It is helpful when hunting bugs in any code that uses the sycache/relcache because causes cache invalidations to be injected whenever it would be possible for an invalidation to occur, whether or not one was really pending. Address this by providing run-time control over cache clobber behaviour using the new debug_invalidate_system_caches_always GUC. Support is not compiled in at all unless assertions are enabled or CLOBBER_CACHE_ENABLED is explicitly defined at compile time. It defaults to 0 if compiled in, so it has negligible effect on assert build performance by default. When support is compiled in, test code can now set debug_invalidate_system_caches_always=1 locally to a backend to test specific queries, functions, extensions, etc. Or tests can toggle it globally for a specific test case while retaining normal performance during test setup and teardown. For backwards compatibility with existing test harnesses and scripts, debug_invalidate_system_caches_always defaults to 1 if CLOBBER_CACHE_ALWAYS is defined, and to 3 if CLOBBER_CACHE_RECURSIVE is defined. CLOBBER_CACHE_ENABLED is now visible in pg_config_manual.h, as is the related RECOVER_RELATION_BUILD_MEMORY setting for the relcache. Author: Craig Ringer Discussion: https://www.postgresql.org/message-id/flat/CAMsr+YF=+ctXBZj3ywmvKNUjWpxmuTuUKuv-rgbHGX5i5pLstQ@mail.gmail.com --- doc/src/sgml/config.sgml | 37 ++++++++++++++++ doc/src/sgml/regress.sgml | 3 +- src/backend/utils/adt/lockfuncs.c | 2 +- src/backend/utils/cache/inval.c | 48 ++++++++++----------- src/backend/utils/cache/plancache.c | 2 +- src/backend/utils/cache/relcache.c | 67 +++++++++++++++++------------ src/backend/utils/misc/guc.c | 24 +++++++++++ src/include/pg_config_manual.h | 39 +++++++++++++++++ src/include/utils/inval.h | 1 + 9 files changed, 169 insertions(+), 54 deletions(-) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 2a90d011db53b..425f57901d730 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -9989,6 +9989,43 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir' + + debug_invalidate_system_caches_always (integer) + + debug_invalidate_system_caches_always configuration parameter + + + + + When set to 1, each cache lookup for a system catalog entry is + invalidated at the first possible opportunity, irrespective of whether + anything that would render it invalid really occurred. Caching of + system catalogs is effectively disabled as a result, so the server + will run extremely slowly. Higher values run the cache invalidation + recursively, which is even slower and useful only useful for testing + in very specific scenarios. + + + + This option can be very helpful when trying to trigger + hard-to-reproduce bugs involving concurrency and catalog changes but + is otherwise rarely needed. See the source code files + inval.c and + pg_config_manual.h for details. + + + + This setting is supported but off by default (0) when + CLOBBER_CACHE_ENABLED is defined at compile time + (which happens automatically when using the + configure option + ). In production builds, its value + will always be 0 and attempts to set it to another + value will raise an error. + + + + ignore_system_indexes (boolean) diff --git a/doc/src/sgml/regress.sgml b/doc/src/sgml/regress.sgml index 890ec7c88ee74..cb401a45b35ab 100644 --- a/doc/src/sgml/regress.sgml +++ b/doc/src/sgml/regress.sgml @@ -372,7 +372,8 @@ make check EXTRA_REGRESS_OPTS="--temp-config=test_postgresql.conf" This can be useful to enable additional logging, adjust resource limits, - or enable extra run-time checks. + or enable extra run-time checks such as . diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c index 0db8be6c9173e..b1cf5b79a75fe 100644 --- a/src/backend/utils/adt/lockfuncs.c +++ b/src/backend/utils/adt/lockfuncs.c @@ -629,7 +629,7 @@ pg_isolation_test_session_is_blocked(PG_FUNCTION_ARGS) * Check if any of these are in the list of interesting PIDs, that being * the sessions that the isolation tester is running. We don't use * "arrayoverlaps" here, because it would lead to cache lookups and one of - * our goals is to run quickly under CLOBBER_CACHE_ALWAYS. We expect + * our goals is to run quickly with debug_invalidate_system_caches_always > 0. We expect * blocking_pids to be usually empty and otherwise a very small number in * isolation tester cases, so make that the outer loop of a naive search * for a match. diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c index 0837054e7c65c..f54dc12b718a2 100644 --- a/src/backend/utils/cache/inval.c +++ b/src/backend/utils/cache/inval.c @@ -109,6 +109,7 @@ #include "storage/sinval.h" #include "storage/smgr.h" #include "utils/catcache.h" +#include "utils/guc.h" #include "utils/inval.h" #include "utils/memdebug.h" #include "utils/memutils.h" @@ -179,6 +180,8 @@ static SharedInvalidationMessage *SharedInvalidMessagesArray; static int numSharedInvalidMessagesArray; static int maxSharedInvalidMessagesArray; +/* GUC storage */ +int debug_invalidate_system_caches_always = 0; /* * Dynamically-registered callback functions. Current implementation @@ -689,35 +692,32 @@ AcceptInvalidationMessages(void) /* * Test code to force cache flushes anytime a flush could happen. * - * If used with CLOBBER_FREED_MEMORY, CLOBBER_CACHE_ALWAYS provides a - * fairly thorough test that the system contains no cache-flush hazards. - * However, it also makes the system unbelievably slow --- the regression - * tests take about 100 times longer than normal. + * This helps detect intermittent faults caused by code that reads a + * cache entry and then performs an action that could invalidate the entry, + * but rarely actually does so. This can spot issues that would otherwise + * only arise with badly timed concurrent DDL, for example. * - * If you're a glutton for punishment, try CLOBBER_CACHE_RECURSIVELY. This - * slows things by at least a factor of 10000, so I wouldn't suggest - * trying to run the entire regression tests that way. It's useful to try - * a few simple tests, to make sure that cache reload isn't subject to - * internal cache-flush hazards, but after you've done a few thousand - * recursive reloads it's unlikely you'll learn more. + * The default debug_invalidate_system_caches_always = 0 does no forced cache flushes. + * + * If used with CLOBBER_FREED_MEMORY, debug_invalidate_system_caches_always = 1 + * (CLOBBER_CACHE_ALWAYS) provides a fairly thorough test that the system + * contains no cache-flush hazards. However, it also makes the system + * unbelievably slow --- the regression tests take about 100 times longer + * than normal. + * + * If you're a glutton for punishment, try debug_invalidate_system_caches_always = 3 + * (CLOBBER_CACHE_RECURSIVELY). This slows things by at least a factor + * of 10000, so I wouldn't suggest trying to run the entire regression + * tests that way. It's useful to try a few simple tests, to make sure + * that cache reload isn't subject to internal cache-flush hazards, but + * after you've done a few thousand recursive reloads it's unlikely + * you'll learn more. */ -#if defined(CLOBBER_CACHE_ALWAYS) - { - static bool in_recursion = false; - - if (!in_recursion) - { - in_recursion = true; - InvalidateSystemCaches(); - in_recursion = false; - } - } -#elif defined(CLOBBER_CACHE_RECURSIVELY) +#ifdef CLOBBER_CACHE_ENABLED { static int recursion_depth = 0; - /* Maximum depth is arbitrary depending on your threshold of pain */ - if (recursion_depth < 3) + if (recursion_depth < debug_invalidate_system_caches_always) { recursion_depth++; InvalidateSystemCaches(); diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c index 2d0d7841a7653..cc04b5b4bef90 100644 --- a/src/backend/utils/cache/plancache.c +++ b/src/backend/utils/cache/plancache.c @@ -897,7 +897,7 @@ BuildCachedPlan(CachedPlanSource *plansource, List *qlist, * rejected a generic plan, it's possible to reach here with is_valid * false due to an invalidation while making the generic plan. In theory * the invalidation must be a false positive, perhaps a consequence of an - * sinval reset event or the CLOBBER_CACHE_ALWAYS debug code. But for + * sinval reset event or the debug_invalidate_system_caches_always code. But for * safety, let's treat it as real and redo the RevalidateCachedQuery call. */ if (!plansource->is_valid) diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index afc3451a54386..7ef510cd01b70 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -91,15 +91,15 @@ #define RELCACHE_INIT_FILEMAGIC 0x573266 /* version ID value */ /* - * Default policy for whether to apply RECOVER_RELATION_BUILD_MEMORY: - * do so in clobber-cache builds but not otherwise. This choice can be - * overridden at compile time with -DRECOVER_RELATION_BUILD_MEMORY=1 or =0. + * Whether to bother checking if relation cache memory needs to be freed + * eagerly. See also RelationBuildDesc() and pg_config_manual.h. */ -#ifndef RECOVER_RELATION_BUILD_MEMORY -#if defined(CLOBBER_CACHE_ALWAYS) || defined(CLOBBER_CACHE_RECURSIVELY) -#define RECOVER_RELATION_BUILD_MEMORY 1 +#if defined(RECOVER_RELATION_BUILD_MEMORY) && (RECOVER_RELATION_BUILD_MEMORY != 0) +#define MAYBE_RECOVER_RELATION_BUILD_MEMORY 1 #else #define RECOVER_RELATION_BUILD_MEMORY 0 +#ifdef CLOBBER_CACHE_ENABLED +#define MAYBE_RECOVER_RELATION_BUILD_MEMORY 1 #endif #endif @@ -1040,19 +1040,25 @@ RelationBuildDesc(Oid targetRelId, bool insertIt) * scope, and relcache loads shouldn't happen so often that it's essential * to recover transient data before end of statement/transaction. However * that's definitely not true in clobber-cache test builds, and perhaps - * it's not true in other cases. If RECOVER_RELATION_BUILD_MEMORY is not - * zero, arrange to allocate the junk in a temporary context that we'll - * free before returning. Make it a child of caller's context so that it - * will get cleaned up appropriately if we error out partway through. + * it's not true in other cases. + * + * When cache clobbering is enabled or when forced to by + * RECOVER_RELATION_BUILD_MEMORY=1, arrange to allocate the junk in a + * temporary context that we'll free before returning. Make it a child + * of caller's context so that it will get cleaned up appropriately if + * we error out partway through. */ -#if RECOVER_RELATION_BUILD_MEMORY - MemoryContext tmpcxt; - MemoryContext oldcxt; +#ifdef MAYBE_RECOVER_RELATION_BUILD_MEMORY + MemoryContext tmpcxt = NULL; + MemoryContext oldcxt = NULL; - tmpcxt = AllocSetContextCreate(CurrentMemoryContext, - "RelationBuildDesc workspace", - ALLOCSET_DEFAULT_SIZES); - oldcxt = MemoryContextSwitchTo(tmpcxt); + if (RECOVER_RELATION_BUILD_MEMORY || debug_invalidate_system_caches_always > 0) + { + tmpcxt = AllocSetContextCreate(CurrentMemoryContext, + "RelationBuildDesc workspace", + ALLOCSET_DEFAULT_SIZES); + oldcxt = MemoryContextSwitchTo(tmpcxt); + } #endif /* @@ -1065,10 +1071,13 @@ RelationBuildDesc(Oid targetRelId, bool insertIt) */ if (!HeapTupleIsValid(pg_class_tuple)) { -#if RECOVER_RELATION_BUILD_MEMORY - /* Return to caller's context, and blow away the temporary context */ - MemoryContextSwitchTo(oldcxt); - MemoryContextDelete(tmpcxt); +#ifdef MAYBE_RECOVER_RELATION_BUILD_MEMORY + if (tmpcxt) + { + /* Return to caller's context, and blow away the temporary context */ + MemoryContextSwitchTo(oldcxt); + MemoryContextDelete(tmpcxt); + } #endif return NULL; } @@ -1247,10 +1256,13 @@ RelationBuildDesc(Oid targetRelId, bool insertIt) /* It's fully valid */ relation->rd_isvalid = true; -#if RECOVER_RELATION_BUILD_MEMORY - /* Return to caller's context, and blow away the temporary context */ - MemoryContextSwitchTo(oldcxt); - MemoryContextDelete(tmpcxt); +#ifdef MAYBE_RECOVER_RELATION_BUILD_MEMORY + if (tmpcxt) + { + /* Return to caller's context, and blow away the temporary context */ + MemoryContextSwitchTo(oldcxt); + MemoryContextDelete(tmpcxt); + } #endif return relation; @@ -1646,8 +1658,9 @@ LookupOpclassInfo(Oid operatorClassOid, * while we are loading the info, and it's very hard to provoke that if * this happens only once per opclass per backend. */ -#if defined(CLOBBER_CACHE_ALWAYS) - opcentry->valid = false; +#ifdef CLOBBER_CACHE_ENABLED + if (debug_invalidate_system_caches_always > 0) + opcentry->valid = false; #endif if (opcentry->valid) diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 383b7d0d710c2..1ccf7593eea33 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -99,6 +99,7 @@ #include "utils/rls.h" #include "utils/snapmgr.h" #include "utils/tzparser.h" +#include "utils/inval.h" #include "utils/varlena.h" #include "utils/xml.h" @@ -3402,6 +3403,29 @@ static struct config_int ConfigureNamesInt[] = check_huge_page_size, NULL, NULL }, + { + {"debug_invalidate_system_caches_always", PGC_SUSET, DEVELOPER_OPTIONS, + gettext_noop("Aggressively invalidate system caches for debugging purposes."), + NULL, + GUC_NOT_IN_SAMPLE + }, + &debug_invalidate_system_caches_always, +#ifdef CLOBBER_CACHE_ENABLED + /* Set default based on older compile-time-only cache clobber macros */ +#if defined(CLOBBER_CACHE_RECURSIVELY) + 3, +#elif defined(CLOBBER_CACHE_ALWAYS) + 1, +#else + 0, +#endif + 0, 5, +#else /* not CLOBBER_CACHE_ENABLED */ + 0, 0, 0, +#endif /* not CLOBBER_CACHE_ENABLED */ + NULL, NULL, NULL + }, + /* End-of-list marker */ { {NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL diff --git a/src/include/pg_config_manual.h b/src/include/pg_config_manual.h index 3cbdc6d180edd..d27c8601fa7f0 100644 --- a/src/include/pg_config_manual.h +++ b/src/include/pg_config_manual.h @@ -309,6 +309,45 @@ */ /* #define RANDOMIZE_ALLOCATED_MEMORY */ +/* + * For cache invalidation debugging, define CLOBBER_CACHE_ENABLED to enable + * use of the debug_invalidate_system_caches_always GUC to aggressively flush + * syscache/relcache entries whenever it's possible to deliver invalidations. + * See AcceptInvalidationMessages() in src/backend/utils/cache/inval.c for + * details. + * + * USE_ASSERT_CHECKING builds default to enabling this. It's possible to use + * CLOBBER_CACHE_ENABLED without a cassert build and the implied + * CLOBBER_FREED_MEMORY and MEMORY_CONTEXT_CHECKING options but it's unlikely + * to be as effective at identifying problems. + */ +/* #define CLOBBER_CACHE_ENABLED */ + +#if defined(USE_ASSERT_CHECKING) && !defined(CLOBBER_CACHE_ENABLED) +#define CLOBBER_CACHE_ENABLED +#endif + +/* + * Backwards compatibility for the older compile-time-only cache clobber + * macros. + */ +#if !defined(CLOBBER_CACHE_ENABLED) && (defined(CLOBBER_CACHE_ALWAYS) || defined(CLOBBER_CACHE_RECURSIVELY)) +#define CLOBBER_CACHE_ENABLED +#endif + +/* + * Recover memory used for relcache entries when invalidated. See + * RelationBuildDescr() in src/backend/utils/cache/relcache.c. + * + * This is active automatically for clobber cache builds when clobbering is + * active, but can be overridden here by explicitly defining + * RECOVER_RELATION_BUILD_MEMORY. Define to 1 to always free relation cache + * memory even when clobber is off, or to 0 to never free relation cache + * memory even when clobbering is on. + */ +/* #define RECOVER_RELATION_BUILD_MEMORY 0 */ /* Force disable */ +/* #define RECOVER_RELATION_BUILD_MEMORY 1 */ /* Force enable */ + /* * Define this to force all parse and plan trees to be passed through * copyObject(), to facilitate catching errors and omissions in diff --git a/src/include/utils/inval.h b/src/include/utils/inval.h index 49ae5d2864692..a7e04722d0149 100644 --- a/src/include/utils/inval.h +++ b/src/include/utils/inval.h @@ -18,6 +18,7 @@ #include "storage/relfilenode.h" #include "utils/relcache.h" +extern PGDLLIMPORT int debug_invalidate_system_caches_always; typedef void (*SyscacheCallbackFunction) (Datum arg, int cacheid, uint32 hashvalue); typedef void (*RelcacheCallbackFunction) (Datum arg, Oid relid); From ca8217c10138fa3ffe1e7d1def2484fd0eb78226 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 6 Jan 2021 10:51:14 -0500 Subject: [PATCH 049/240] Add a test module for the regular expression package. This module provides a function test_regex() that is functionally rather like regexp_matches(), but with additional debugging-oriented options and additional output. The debug options are somewhat obscure; they are chosen to match the API of the test harness that Henry Spencer wrote way-back-when for use in Tcl. With this, we can import all the test cases that Spencer wrote originally, even for regex functionality that we don't currently expose in Postgres. This seems necessary because we can no longer rely on Tcl to act as upstream and verify any fixes or improvements that we make. In addition to Spencer's tests, I added a few for lookbehind constraints (which we added in 2015, and Tcl still hasn't absorbed) that are modeled on his tests for lookahead constraints. After looking at code coverage reports, I also threw in a couple of tests to more fully exercise our "high colormap" logic. According to my testing, this brings the check-world coverage for src/backend/regex/ from 71.1% to 86.7% of lines. (coverage.postgresql.org shows a slightly different number, which I think is because it measures a non-assert build.) Discussion: https://postgr.es/m/2873268.1609732164@sss.pgh.pa.us --- src/test/modules/Makefile | 1 + src/test/modules/test_regex/.gitignore | 4 + src/test/modules/test_regex/Makefile | 23 + src/test/modules/test_regex/README | 78 + .../test_regex/expected/test_regex.out | 4551 +++++++++++++++++ .../test_regex/expected/test_regex_utf8.out | 100 + .../test_regex/expected/test_regex_utf8_1.out | 8 + .../modules/test_regex/sql/test_regex.sql | 1667 ++++++ .../test_regex/sql/test_regex_utf8.sql | 60 + .../modules/test_regex/test_regex--1.0.sql | 9 + src/test/modules/test_regex/test_regex.c | 759 +++ .../modules/test_regex/test_regex.control | 4 + 12 files changed, 7264 insertions(+) create mode 100644 src/test/modules/test_regex/.gitignore create mode 100644 src/test/modules/test_regex/Makefile create mode 100644 src/test/modules/test_regex/README create mode 100644 src/test/modules/test_regex/expected/test_regex.out create mode 100644 src/test/modules/test_regex/expected/test_regex_utf8.out create mode 100644 src/test/modules/test_regex/expected/test_regex_utf8_1.out create mode 100644 src/test/modules/test_regex/sql/test_regex.sql create mode 100644 src/test/modules/test_regex/sql/test_regex_utf8.sql create mode 100644 src/test/modules/test_regex/test_regex--1.0.sql create mode 100644 src/test/modules/test_regex/test_regex.c create mode 100644 src/test/modules/test_regex/test_regex.control diff --git a/src/test/modules/Makefile b/src/test/modules/Makefile index a6d2ffbf9e0e5..59921b46cf3a8 100644 --- a/src/test/modules/Makefile +++ b/src/test/modules/Makefile @@ -22,6 +22,7 @@ SUBDIRS = \ test_pg_dump \ test_predtest \ test_rbtree \ + test_regex \ test_rls_hooks \ test_shm_mq \ unsafe_tests \ diff --git a/src/test/modules/test_regex/.gitignore b/src/test/modules/test_regex/.gitignore new file mode 100644 index 0000000000000..5dcb3ff972350 --- /dev/null +++ b/src/test/modules/test_regex/.gitignore @@ -0,0 +1,4 @@ +# Generated subdirectories +/log/ +/results/ +/tmp_check/ diff --git a/src/test/modules/test_regex/Makefile b/src/test/modules/test_regex/Makefile new file mode 100644 index 0000000000000..dfbc5dc44b50e --- /dev/null +++ b/src/test/modules/test_regex/Makefile @@ -0,0 +1,23 @@ +# src/test/modules/test_regex/Makefile + +MODULE_big = test_regex +OBJS = \ + $(WIN32RES) \ + test_regex.o +PGFILEDESC = "test_regex - test code for backend/regex/" + +EXTENSION = test_regex +DATA = test_regex--1.0.sql + +REGRESS = test_regex test_regex_utf8 + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = src/test/modules/test_regex +top_builddir = ../../../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/src/test/modules/test_regex/README b/src/test/modules/test_regex/README new file mode 100644 index 0000000000000..3ef152d4e13da --- /dev/null +++ b/src/test/modules/test_regex/README @@ -0,0 +1,78 @@ +test_regex is a module for testing the regular expression package. +It is mostly meant to allow us to absorb Tcl's regex test suite. +Therefore, there are provisions to exercise regex features that +aren't currently exposed at the SQL level by PostgreSQL. + +Currently, one function is provided: + +test_regex(pattern text, string text, flags text) returns setof text[] + +Reports an error if the pattern is an invalid regex. Otherwise, +the first row of output contains the number of subexpressions, +followed by words reporting set bit(s) in the regex's re_info field. +If the pattern doesn't match the string, that's all. +If the pattern does match, the next row contains the whole match +as the first array element. If there are parenthesized subexpression(s), +following array elements contain the matches to those subexpressions. +If the "g" (glob) flag is set, then additional row(s) of output similarly +report any additional matches. + +The "flags" argument is a string of zero or more single-character +flags that modify the behavior of the regex package or the test +function. As described in Tcl's reg.test file: + +The flag characters are complex and a bit eclectic. Generally speaking, +lowercase letters are compile options, uppercase are expected re_info +bits, and nonalphabetics are match options, controls for how the test is +run, or testing options. The one small surprise is that AREs are the +default, and you must explicitly request lesser flavors of RE. The flags +are as follows. It is admitted that some are not very mnemonic. + + - no-op (placeholder) + 0 report indices not actual strings + (This substitutes for Tcl's -indices switch) + ! expect partial match, report start position anyway + % force small state-set cache in matcher (to test cache replace) + ^ beginning of string is not beginning of line + $ end of string is not end of line + * test is Unicode-specific, needs big character set + + provide fake xy equivalence class and ch collating element + (Note: the equivalence class is implemented, the + collating element is not; so references to [.ch.] fail) + , set REG_PROGRESS (only useful in REG_DEBUG builds) + . set REG_DUMP (only useful in REG_DEBUG builds) + : set REG_MTRACE (only useful in REG_DEBUG builds) + ; set REG_FTRACE (only useful in REG_DEBUG builds) + + & test as both ARE and BRE + (Not implemented in Postgres, we use separate tests) + b BRE + e ERE + a turn advanced-features bit on (error unless ERE already) + q literal string, no metacharacters at all + + g global match (find all matches) + i case-independent matching + o ("opaque") do not return match locations + p newlines are half-magic, excluded from . and [^ only + w newlines are half-magic, significant to ^ and $ only + n newlines are fully magic, both effects + x expanded RE syntax + t incomplete-match reporting + c canmatch (equivalent to "t0!", in Postgres implementation) + s match only at start (REG_BOSONLY) + + A backslash-_a_lphanumeric seen + B ERE/ARE literal-_b_race heuristic used + E backslash (_e_scape) seen within [] + H looka_h_ead constraint seen + I _i_mpossible to match + L _l_ocale-specific construct seen + M unportable (_m_achine-specific) construct seen + N RE can match empty (_n_ull) string + P non-_P_OSIX construct seen + Q {} _q_uantifier seen + R back _r_eference seen + S POSIX-un_s_pecified syntax seen + T prefers shortest (_t_iny) + U saw original-POSIX botch: unmatched right paren in ERE (_u_gh) diff --git a/src/test/modules/test_regex/expected/test_regex.out b/src/test/modules/test_regex/expected/test_regex.out new file mode 100644 index 0000000000000..b62cbac697daf --- /dev/null +++ b/src/test/modules/test_regex/expected/test_regex.out @@ -0,0 +1,4551 @@ +-- This file is based on tests/reg.test from the Tcl distribution, +-- which is marked +-- # Copyright (c) 1998, 1999 Henry Spencer. All rights reserved. +-- The full copyright notice can be found in src/backend/regex/COPYRIGHT. +-- Most commented lines below are copied from reg.test. Each +-- test case is followed by an equivalent test using test_regex(). +create extension test_regex; +set standard_conforming_strings = on; +-- # support functions and preliminary misc. +-- # This is sensitive to changes in message wording, but we really have to +-- # test the code->message expansion at least once. +-- ::tcltest::test reg-0.1 "regexp error reporting" { +-- list [catch {regexp (*) ign} msg] $msg +-- } {1 {couldn't compile regular expression pattern: quantifier operand invalid}} +select * from test_regex('(*)', '', ''); +ERROR: invalid regular expression: quantifier operand invalid +-- doing 1 "basic sanity checks" +-- expectMatch 1.1 & abc abc abc +select * from test_regex('abc', 'abc', ''); + test_regex +------------ + {0} + {abc} +(2 rows) + +select * from test_regex('abc', 'abc', 'b'); + test_regex +------------ + {0} + {abc} +(2 rows) + +-- expectNomatch 1.2 & abc def +select * from test_regex('abc', 'def', ''); + test_regex +------------ + {0} +(1 row) + +select * from test_regex('abc', 'def', 'b'); + test_regex +------------ + {0} +(1 row) + +-- expectMatch 1.3 & abc xyabxabce abc +select * from test_regex('abc', 'xyabxabce', ''); + test_regex +------------ + {0} + {abc} +(2 rows) + +select * from test_regex('abc', 'xyabxabce', 'b'); + test_regex +------------ + {0} + {abc} +(2 rows) + +-- doing 2 "invalid option combinations" +-- expectError 2.1 qe a INVARG +select * from test_regex('a', '', 'qe'); +ERROR: invalid regular expression: invalid argument to regex function +-- expectError 2.2 qa a INVARG +select * from test_regex('a', '', 'qa'); +ERROR: invalid regular expression: invalid argument to regex function +-- expectError 2.3 qx a INVARG +select * from test_regex('a', '', 'qx'); +ERROR: invalid regular expression: invalid argument to regex function +-- expectError 2.4 qn a INVARG +select * from test_regex('a', '', 'qn'); +ERROR: invalid regular expression: invalid argument to regex function +-- expectError 2.5 ba a INVARG +select * from test_regex('a', '', 'ba'); +ERROR: invalid regular expression: invalid argument to regex function +-- doing 3 "basic syntax" +-- expectIndices 3.1 &NS "" a {0 -1} +select * from test_regex('', 'a', '0NS'); + test_regex +--------------------------------- + {0,REG_UUNSPEC,REG_UEMPTYMATCH} + {"0 -1"} +(2 rows) + +select * from test_regex('', 'a', '0NSb'); + test_regex +--------------------------------- + {0,REG_UUNSPEC,REG_UEMPTYMATCH} + {"0 -1"} +(2 rows) + +-- expectMatch 3.2 NS a| a a +select * from test_regex('a|', 'a', 'NS'); + test_regex +--------------------------------- + {0,REG_UUNSPEC,REG_UEMPTYMATCH} + {a} +(2 rows) + +-- expectMatch 3.3 - a|b a a +select * from test_regex('a|b', 'a', '-'); + test_regex +------------ + {0} + {a} +(2 rows) + +-- expectMatch 3.4 - a|b b b +select * from test_regex('a|b', 'b', '-'); + test_regex +------------ + {0} + {b} +(2 rows) + +-- expectMatch 3.5 NS a||b b b +select * from test_regex('a||b', 'b', 'NS'); + test_regex +--------------------------------- + {0,REG_UUNSPEC,REG_UEMPTYMATCH} + {b} +(2 rows) + +-- expectMatch 3.6 & ab ab ab +select * from test_regex('ab', 'ab', ''); + test_regex +------------ + {0} + {ab} +(2 rows) + +select * from test_regex('ab', 'ab', 'b'); + test_regex +------------ + {0} + {ab} +(2 rows) + +-- doing 4 "parentheses" +-- expectMatch 4.1 - (a)e ae ae a +select * from test_regex('(a)e', 'ae', '-'); + test_regex +------------ + {1} + {ae,a} +(2 rows) + +-- expectMatch 4.2 o (a)e ae +select * from test_regex('(a)e', 'ae', 'o'); + test_regex +------------ + {0} + {NULL} +(2 rows) + +-- expectMatch 4.3 b {\(a\)b} ab ab a +select * from test_regex('\(a\)b', 'ab', 'b'); + test_regex +------------ + {1} + {ab,a} +(2 rows) + +-- expectMatch 4.4 - a((b)c) abc abc bc b +select * from test_regex('a((b)c)', 'abc', '-'); + test_regex +------------ + {2} + {abc,bc,b} +(2 rows) + +-- expectMatch 4.5 - a(b)(c) abc abc b c +select * from test_regex('a(b)(c)', 'abc', '-'); + test_regex +------------ + {2} + {abc,b,c} +(2 rows) + +-- expectError 4.6 - a(b EPAREN +select * from test_regex('a(b', '', '-'); +ERROR: invalid regular expression: parentheses () not balanced +-- expectError 4.7 b {a\(b} EPAREN +select * from test_regex('a\(b', '', 'b'); +ERROR: invalid regular expression: parentheses () not balanced +-- # sigh, we blew it on the specs here... someday this will be fixed in POSIX, +-- # but meanwhile, it's fixed in AREs +-- expectMatch 4.8 eU a)b a)b a)b +select * from test_regex('a)b', 'a)b', 'eU'); + test_regex +----------------- + {0,REG_UPBOTCH} + {a)b} +(2 rows) + +-- expectError 4.9 - a)b EPAREN +select * from test_regex('a)b', '', '-'); +ERROR: invalid regular expression: parentheses () not balanced +-- expectError 4.10 b {a\)b} EPAREN +select * from test_regex('a\)b', '', 'b'); +ERROR: invalid regular expression: parentheses () not balanced +-- expectMatch 4.11 P a(?:b)c abc abc +select * from test_regex('a(?:b)c', 'abc', 'P'); + test_regex +------------------- + {0,REG_UNONPOSIX} + {abc} +(2 rows) + +-- expectError 4.12 e a(?:b)c BADRPT +select * from test_regex('a(?:b)c', '', 'e'); +ERROR: invalid regular expression: quantifier operand invalid +-- expectIndices 4.13 S a()b ab {0 1} {1 0} +select * from test_regex('a()b', 'ab', '0S'); + test_regex +----------------- + {1,REG_UUNSPEC} + {"0 1","1 0"} +(2 rows) + +-- expectMatch 4.14 SP a(?:)b ab ab +select * from test_regex('a(?:)b', 'ab', 'SP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_UUNSPEC} + {ab} +(2 rows) + +-- expectIndices 4.15 S a(|b)c ac {0 1} {1 0} +select * from test_regex('a(|b)c', 'ac', '0S'); + test_regex +----------------- + {1,REG_UUNSPEC} + {"0 1","1 0"} +(2 rows) + +-- expectMatch 4.16 S a(b|)c abc abc b +select * from test_regex('a(b|)c', 'abc', 'S'); + test_regex +----------------- + {1,REG_UUNSPEC} + {abc,b} +(2 rows) + +-- doing 5 "simple one-char matching" +-- # general case of brackets done later +-- expectMatch 5.1 & a.b axb axb +select * from test_regex('a.b', 'axb', ''); + test_regex +------------ + {0} + {axb} +(2 rows) + +select * from test_regex('a.b', 'axb', 'b'); + test_regex +------------ + {0} + {axb} +(2 rows) + +-- expectNomatch 5.2 &n "a.b" "a\nb" +select * from test_regex('a.b', E'a\nb', 'n'); + test_regex +------------ + {0} +(1 row) + +select * from test_regex('a.b', E'a\nb', 'nb'); + test_regex +------------ + {0} +(1 row) + +-- expectMatch 5.3 & {a[bc]d} abd abd +select * from test_regex('a[bc]d', 'abd', ''); + test_regex +------------ + {0} + {abd} +(2 rows) + +select * from test_regex('a[bc]d', 'abd', 'b'); + test_regex +------------ + {0} + {abd} +(2 rows) + +-- expectMatch 5.4 & {a[bc]d} acd acd +select * from test_regex('a[bc]d', 'acd', ''); + test_regex +------------ + {0} + {acd} +(2 rows) + +select * from test_regex('a[bc]d', 'acd', 'b'); + test_regex +------------ + {0} + {acd} +(2 rows) + +-- expectNomatch 5.5 & {a[bc]d} aed +select * from test_regex('a[bc]d', 'aed', ''); + test_regex +------------ + {0} +(1 row) + +select * from test_regex('a[bc]d', 'aed', 'b'); + test_regex +------------ + {0} +(1 row) + +-- expectNomatch 5.6 & {a[^bc]d} abd +select * from test_regex('a[^bc]d', 'abd', ''); + test_regex +------------ + {0} +(1 row) + +select * from test_regex('a[^bc]d', 'abd', 'b'); + test_regex +------------ + {0} +(1 row) + +-- expectMatch 5.7 & {a[^bc]d} aed aed +select * from test_regex('a[^bc]d', 'aed', ''); + test_regex +------------ + {0} + {aed} +(2 rows) + +select * from test_regex('a[^bc]d', 'aed', 'b'); + test_regex +------------ + {0} + {aed} +(2 rows) + +-- expectNomatch 5.8 &p "a\[^bc]d" "a\nd" +select * from test_regex('a[^bc]d', E'a\nd', 'p'); + test_regex +------------ + {0} +(1 row) + +select * from test_regex('a[^bc]d', E'a\nd', 'pb'); + test_regex +------------ + {0} +(1 row) + +-- doing 6 "context-dependent syntax" +-- # plus odds and ends +-- expectError 6.1 - * BADRPT +select * from test_regex('*', '', '-'); +ERROR: invalid regular expression: quantifier operand invalid +-- expectMatch 6.2 b * * * +select * from test_regex('*', '*', 'b'); + test_regex +------------ + {0} + {*} +(2 rows) + +-- expectMatch 6.3 b {\(*\)} * * * +select * from test_regex('\(*\)', '*', 'b'); + test_regex +------------ + {1} + {*,*} +(2 rows) + +-- expectError 6.4 - (*) BADRPT +select * from test_regex('(*)', '', '-'); +ERROR: invalid regular expression: quantifier operand invalid +-- expectMatch 6.5 b ^* * * +select * from test_regex('^*', '*', 'b'); + test_regex +------------ + {0} + {*} +(2 rows) + +-- expectError 6.6 - ^* BADRPT +select * from test_regex('^*', '', '-'); +ERROR: invalid regular expression: quantifier operand invalid +-- expectNomatch 6.7 & ^b ^b +select * from test_regex('^b', '^b', ''); + test_regex +------------ + {0} +(1 row) + +select * from test_regex('^b', '^b', 'b'); + test_regex +------------ + {0} +(1 row) + +-- expectMatch 6.8 b x^ x^ x^ +select * from test_regex('x^', 'x^', 'b'); + test_regex +------------ + {0} + {x^} +(2 rows) + +-- expectNomatch 6.9 I x^ x +select * from test_regex('x^', 'x', 'I'); + test_regex +--------------------- + {0,REG_UIMPOSSIBLE} +(1 row) + +-- expectMatch 6.10 n "\n^" "x\nb" "\n" +select * from test_regex(E'\n^', E'x\nb', 'n'); + test_regex +------------ + {0} + {" + + "} +(2 rows) + +-- expectNomatch 6.11 bS {\(^b\)} ^b +select * from test_regex('\(^b\)', '^b', 'bS'); + test_regex +----------------- + {1,REG_UUNSPEC} +(1 row) + +-- expectMatch 6.12 - (^b) b b b +select * from test_regex('(^b)', 'b', '-'); + test_regex +------------ + {1} + {b,b} +(2 rows) + +-- expectMatch 6.13 & {x$} x x +select * from test_regex('x$', 'x', ''); + test_regex +------------ + {0} + {x} +(2 rows) + +select * from test_regex('x$', 'x', 'b'); + test_regex +------------ + {0} + {x} +(2 rows) + +-- expectMatch 6.14 bS {\(x$\)} x x x +select * from test_regex('\(x$\)', 'x', 'bS'); + test_regex +----------------- + {1,REG_UUNSPEC} + {x,x} +(2 rows) + +-- expectMatch 6.15 - {(x$)} x x x +select * from test_regex('(x$)', 'x', '-'); + test_regex +------------ + {1} + {x,x} +(2 rows) + +-- expectMatch 6.16 b {x$y} "x\$y" "x\$y" +select * from test_regex('x$y', 'x$y', 'b'); + test_regex +------------ + {0} + {x$y} +(2 rows) + +-- expectNomatch 6.17 I {x$y} xy +select * from test_regex('x$y', 'xy', 'I'); + test_regex +--------------------- + {0,REG_UIMPOSSIBLE} +(1 row) + +-- expectMatch 6.18 n "x\$\n" "x\n" "x\n" +select * from test_regex(E'x$\n', E'x\n', 'n'); + test_regex +------------ + {0} + {"x + + "} +(2 rows) + +-- expectError 6.19 - + BADRPT +select * from test_regex('+', '', '-'); +ERROR: invalid regular expression: quantifier operand invalid +-- expectError 6.20 - ? BADRPT +select * from test_regex('?', '', '-'); +ERROR: invalid regular expression: quantifier operand invalid +-- These two are not yet incorporated in Tcl, cf +-- https://core.tcl-lang.org/tcl/artifact/106269fa65d96b83 +-- expectError 6.21 - {x(\w)(?=(\1))} ESUBREG +select * from test_regex('x(\w)(?=(\1))', '', '-'); +ERROR: invalid regular expression: invalid backreference number +-- expectMatch 6.22 HP {x(?=((foo)))} xfoo x +select * from test_regex('x(?=((foo)))', 'xfoo', 'HP'); + test_regex +----------------------------------- + {0,REG_ULOOKAROUND,REG_UNONPOSIX} + {x} +(2 rows) + +-- doing 7 "simple quantifiers" +-- expectMatch 7.1 &N a* aa aa +select * from test_regex('a*', 'aa', 'N'); + test_regex +--------------------- + {0,REG_UEMPTYMATCH} + {aa} +(2 rows) + +select * from test_regex('a*', 'aa', 'Nb'); + test_regex +--------------------- + {0,REG_UEMPTYMATCH} + {aa} +(2 rows) + +-- expectIndices 7.2 &N a* b {0 -1} +select * from test_regex('a*', 'b', '0N'); + test_regex +--------------------- + {0,REG_UEMPTYMATCH} + {"0 -1"} +(2 rows) + +select * from test_regex('a*', 'b', '0Nb'); + test_regex +--------------------- + {0,REG_UEMPTYMATCH} + {"0 -1"} +(2 rows) + +-- expectMatch 7.3 - a+ aa aa +select * from test_regex('a+', 'aa', '-'); + test_regex +------------ + {0} + {aa} +(2 rows) + +-- expectMatch 7.4 - a?b ab ab +select * from test_regex('a?b', 'ab', '-'); + test_regex +------------ + {0} + {ab} +(2 rows) + +-- expectMatch 7.5 - a?b b b +select * from test_regex('a?b', 'b', '-'); + test_regex +------------ + {0} + {b} +(2 rows) + +-- expectError 7.6 - ** BADRPT +select * from test_regex('**', '', '-'); +ERROR: invalid regular expression: quantifier operand invalid +-- expectMatch 7.7 bN ** *** *** +select * from test_regex('**', '***', 'bN'); + test_regex +--------------------- + {0,REG_UEMPTYMATCH} + {***} +(2 rows) + +-- expectError 7.8 & a** BADRPT +select * from test_regex('a**', '', ''); +ERROR: invalid regular expression: quantifier operand invalid +select * from test_regex('a**', '', 'b'); +ERROR: invalid regular expression: quantifier operand invalid +-- expectError 7.9 & a**b BADRPT +select * from test_regex('a**b', '', ''); +ERROR: invalid regular expression: quantifier operand invalid +select * from test_regex('a**b', '', 'b'); +ERROR: invalid regular expression: quantifier operand invalid +-- expectError 7.10 & *** BADRPT +select * from test_regex('***', '', ''); +ERROR: invalid regular expression: quantifier operand invalid +select * from test_regex('***', '', 'b'); +ERROR: invalid regular expression: quantifier operand invalid +-- expectError 7.11 - a++ BADRPT +select * from test_regex('a++', '', '-'); +ERROR: invalid regular expression: quantifier operand invalid +-- expectError 7.12 - a?+ BADRPT +select * from test_regex('a?+', '', '-'); +ERROR: invalid regular expression: quantifier operand invalid +-- expectError 7.13 - a?* BADRPT +select * from test_regex('a?*', '', '-'); +ERROR: invalid regular expression: quantifier operand invalid +-- expectError 7.14 - a+* BADRPT +select * from test_regex('a+*', '', '-'); +ERROR: invalid regular expression: quantifier operand invalid +-- expectError 7.15 - a*+ BADRPT +select * from test_regex('a*+', '', '-'); +ERROR: invalid regular expression: quantifier operand invalid +-- doing 8 "braces" +-- expectMatch 8.1 NQ "a{0,1}" "" "" +select * from test_regex('a{0,1}', '', 'NQ'); + test_regex +--------------------------------- + {0,REG_UBOUNDS,REG_UEMPTYMATCH} + {""} +(2 rows) + +-- expectMatch 8.2 NQ "a{0,1}" ac a +select * from test_regex('a{0,1}', 'ac', 'NQ'); + test_regex +--------------------------------- + {0,REG_UBOUNDS,REG_UEMPTYMATCH} + {a} +(2 rows) + +-- expectError 8.3 - "a{1,0}" BADBR +select * from test_regex('a{1,0}', '', '-'); +ERROR: invalid regular expression: invalid repetition count(s) +-- expectError 8.4 - "a{1,2,3}" BADBR +select * from test_regex('a{1,2,3}', '', '-'); +ERROR: invalid regular expression: invalid repetition count(s) +-- expectError 8.5 - "a{257}" BADBR +select * from test_regex('a{257}', '', '-'); +ERROR: invalid regular expression: invalid repetition count(s) +-- expectError 8.6 - "a{1000}" BADBR +select * from test_regex('a{1000}', '', '-'); +ERROR: invalid regular expression: invalid repetition count(s) +-- expectError 8.7 - "a{1" EBRACE +select * from test_regex('a{1', '', '-'); +ERROR: invalid regular expression: braces {} not balanced +-- expectError 8.8 - "a{1n}" BADBR +select * from test_regex('a{1n}', '', '-'); +ERROR: invalid regular expression: invalid repetition count(s) +-- expectMatch 8.9 BS "a{b" "a\{b" "a\{b" +select * from test_regex('a{b', 'a{b', 'BS'); + test_regex +----------------------------- + {0,REG_UBRACES,REG_UUNSPEC} + {"a{b"} +(2 rows) + +-- expectMatch 8.10 BS "a{" "a\{" "a\{" +select * from test_regex('a{', 'a{', 'BS'); + test_regex +----------------------------- + {0,REG_UBRACES,REG_UUNSPEC} + {"a{"} +(2 rows) + +-- expectMatch 8.11 bQ "a\\{0,1\\}b" cb b +select * from test_regex('a\{0,1\}b', 'cb', 'bQ'); + test_regex +----------------- + {0,REG_UBOUNDS} + {b} +(2 rows) + +-- expectError 8.12 b "a\\{0,1" EBRACE +select * from test_regex('a\{0,1', '', 'b'); +ERROR: invalid regular expression: braces {} not balanced +-- expectError 8.13 - "a{0,1\\" BADBR +select * from test_regex('a{0,1\', '', '-'); +ERROR: invalid regular expression: invalid repetition count(s) +-- expectMatch 8.14 Q "a{0}b" ab b +select * from test_regex('a{0}b', 'ab', 'Q'); + test_regex +----------------- + {0,REG_UBOUNDS} + {b} +(2 rows) + +-- expectMatch 8.15 Q "a{0,0}b" ab b +select * from test_regex('a{0,0}b', 'ab', 'Q'); + test_regex +----------------- + {0,REG_UBOUNDS} + {b} +(2 rows) + +-- expectMatch 8.16 Q "a{0,1}b" ab ab +select * from test_regex('a{0,1}b', 'ab', 'Q'); + test_regex +----------------- + {0,REG_UBOUNDS} + {ab} +(2 rows) + +-- expectMatch 8.17 Q "a{0,2}b" b b +select * from test_regex('a{0,2}b', 'b', 'Q'); + test_regex +----------------- + {0,REG_UBOUNDS} + {b} +(2 rows) + +-- expectMatch 8.18 Q "a{0,2}b" aab aab +select * from test_regex('a{0,2}b', 'aab', 'Q'); + test_regex +----------------- + {0,REG_UBOUNDS} + {aab} +(2 rows) + +-- expectMatch 8.19 Q "a{0,}b" aab aab +select * from test_regex('a{0,}b', 'aab', 'Q'); + test_regex +----------------- + {0,REG_UBOUNDS} + {aab} +(2 rows) + +-- expectMatch 8.20 Q "a{1,1}b" aab ab +select * from test_regex('a{1,1}b', 'aab', 'Q'); + test_regex +----------------- + {0,REG_UBOUNDS} + {ab} +(2 rows) + +-- expectMatch 8.21 Q "a{1,3}b" aaaab aaab +select * from test_regex('a{1,3}b', 'aaaab', 'Q'); + test_regex +----------------- + {0,REG_UBOUNDS} + {aaab} +(2 rows) + +-- expectNomatch 8.22 Q "a{1,3}b" b +select * from test_regex('a{1,3}b', 'b', 'Q'); + test_regex +----------------- + {0,REG_UBOUNDS} +(1 row) + +-- expectMatch 8.23 Q "a{1,}b" aab aab +select * from test_regex('a{1,}b', 'aab', 'Q'); + test_regex +----------------- + {0,REG_UBOUNDS} + {aab} +(2 rows) + +-- expectNomatch 8.24 Q "a{2,3}b" ab +select * from test_regex('a{2,3}b', 'ab', 'Q'); + test_regex +----------------- + {0,REG_UBOUNDS} +(1 row) + +-- expectMatch 8.25 Q "a{2,3}b" aaaab aaab +select * from test_regex('a{2,3}b', 'aaaab', 'Q'); + test_regex +----------------- + {0,REG_UBOUNDS} + {aaab} +(2 rows) + +-- expectNomatch 8.26 Q "a{2,}b" ab +select * from test_regex('a{2,}b', 'ab', 'Q'); + test_regex +----------------- + {0,REG_UBOUNDS} +(1 row) + +-- expectMatch 8.27 Q "a{2,}b" aaaab aaaab +select * from test_regex('a{2,}b', 'aaaab', 'Q'); + test_regex +----------------- + {0,REG_UBOUNDS} + {aaaab} +(2 rows) + +-- doing 9 "brackets" +-- expectMatch 9.1 & {a[bc]} ac ac +select * from test_regex('a[bc]', 'ac', ''); + test_regex +------------ + {0} + {ac} +(2 rows) + +select * from test_regex('a[bc]', 'ac', 'b'); + test_regex +------------ + {0} + {ac} +(2 rows) + +-- expectMatch 9.2 & {a[-]} a- a- +select * from test_regex('a[-]', 'a-', ''); + test_regex +------------ + {0} + {a-} +(2 rows) + +select * from test_regex('a[-]', 'a-', 'b'); + test_regex +------------ + {0} + {a-} +(2 rows) + +-- expectMatch 9.3 & {a[[.-.]]} a- a- +select * from test_regex('a[[.-.]]', 'a-', ''); + test_regex +------------ + {0} + {a-} +(2 rows) + +select * from test_regex('a[[.-.]]', 'a-', 'b'); + test_regex +------------ + {0} + {a-} +(2 rows) + +-- expectMatch 9.4 &L {a[[.zero.]]} a0 a0 +select * from test_regex('a[[.zero.]]', 'a0', 'L'); + test_regex +----------------- + {0,REG_ULOCALE} + {a0} +(2 rows) + +select * from test_regex('a[[.zero.]]', 'a0', 'Lb'); + test_regex +----------------- + {0,REG_ULOCALE} + {a0} +(2 rows) + +-- expectMatch 9.5 &LM {a[[.zero.]-9]} a2 a2 +select * from test_regex('a[[.zero.]-9]', 'a2', 'LM'); + test_regex +----------------------------- + {0,REG_UUNPORT,REG_ULOCALE} + {a2} +(2 rows) + +select * from test_regex('a[[.zero.]-9]', 'a2', 'LMb'); + test_regex +----------------------------- + {0,REG_UUNPORT,REG_ULOCALE} + {a2} +(2 rows) + +-- expectMatch 9.6 &M {a[0-[.9.]]} a2 a2 +select * from test_regex('a[0-[.9.]]', 'a2', 'M'); + test_regex +----------------- + {0,REG_UUNPORT} + {a2} +(2 rows) + +select * from test_regex('a[0-[.9.]]', 'a2', 'Mb'); + test_regex +----------------- + {0,REG_UUNPORT} + {a2} +(2 rows) + +-- expectMatch 9.7 &+L {a[[=x=]]} ax ax +select * from test_regex('a[[=x=]]', 'ax', '+L'); + test_regex +----------------- + {0,REG_ULOCALE} + {ax} +(2 rows) + +select * from test_regex('a[[=x=]]', 'ax', '+Lb'); + test_regex +----------------- + {0,REG_ULOCALE} + {ax} +(2 rows) + +-- expectMatch 9.8 &+L {a[[=x=]]} ay ay +select * from test_regex('a[[=x=]]', 'ay', '+L'); + test_regex +----------------- + {0,REG_ULOCALE} + {ay} +(2 rows) + +select * from test_regex('a[[=x=]]', 'ay', '+Lb'); + test_regex +----------------- + {0,REG_ULOCALE} + {ay} +(2 rows) + +-- expectNomatch 9.9 &+L {a[[=x=]]} az +select * from test_regex('a[[=x=]]', 'az', '+L'); + test_regex +----------------- + {0,REG_ULOCALE} +(1 row) + +select * from test_regex('a[[=x=]]', 'az', '+Lb'); + test_regex +----------------- + {0,REG_ULOCALE} +(1 row) + +-- expectError 9.10 & {a[0-[=x=]]} ERANGE +select * from test_regex('a[0-[=x=]]', '', ''); +ERROR: invalid regular expression: invalid character range +select * from test_regex('a[0-[=x=]]', '', 'b'); +ERROR: invalid regular expression: invalid character range +-- expectMatch 9.11 &L {a[[:digit:]]} a0 a0 +select * from test_regex('a[[:digit:]]', 'a0', 'L'); + test_regex +----------------- + {0,REG_ULOCALE} + {a0} +(2 rows) + +select * from test_regex('a[[:digit:]]', 'a0', 'Lb'); + test_regex +----------------- + {0,REG_ULOCALE} + {a0} +(2 rows) + +-- expectError 9.12 & {a[[:woopsie:]]} ECTYPE +select * from test_regex('a[[:woopsie:]]', '', ''); +ERROR: invalid regular expression: invalid character class +select * from test_regex('a[[:woopsie:]]', '', 'b'); +ERROR: invalid regular expression: invalid character class +-- expectNomatch 9.13 &L {a[[:digit:]]} ab +select * from test_regex('a[[:digit:]]', 'ab', 'L'); + test_regex +----------------- + {0,REG_ULOCALE} +(1 row) + +select * from test_regex('a[[:digit:]]', 'ab', 'Lb'); + test_regex +----------------- + {0,REG_ULOCALE} +(1 row) + +-- expectError 9.14 & {a[0-[:digit:]]} ERANGE +select * from test_regex('a[0-[:digit:]]', '', ''); +ERROR: invalid regular expression: invalid character range +select * from test_regex('a[0-[:digit:]]', '', 'b'); +ERROR: invalid regular expression: invalid character range +-- expectMatch 9.15 &LP {[[:<:]]a} a a +select * from test_regex('[[:<:]]a', 'a', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {a} +(2 rows) + +select * from test_regex('[[:<:]]a', 'a', 'LPb'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {a} +(2 rows) + +-- expectMatch 9.16 &LP {a[[:>:]]} a a +select * from test_regex('a[[:>:]]', 'a', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {a} +(2 rows) + +select * from test_regex('a[[:>:]]', 'a', 'LPb'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {a} +(2 rows) + +-- expectError 9.17 & {a[[..]]b} ECOLLATE +select * from test_regex('a[[..]]b', '', ''); +ERROR: invalid regular expression: invalid collating element +select * from test_regex('a[[..]]b', '', 'b'); +ERROR: invalid regular expression: invalid collating element +-- expectError 9.18 & {a[[==]]b} ECOLLATE +select * from test_regex('a[[==]]b', '', ''); +ERROR: invalid regular expression: invalid collating element +select * from test_regex('a[[==]]b', '', 'b'); +ERROR: invalid regular expression: invalid collating element +-- expectError 9.19 & {a[[::]]b} ECTYPE +select * from test_regex('a[[::]]b', '', ''); +ERROR: invalid regular expression: invalid character class +select * from test_regex('a[[::]]b', '', 'b'); +ERROR: invalid regular expression: invalid character class +-- expectError 9.20 & {a[[.a} EBRACK +select * from test_regex('a[[.a', '', ''); +ERROR: invalid regular expression: brackets [] not balanced +select * from test_regex('a[[.a', '', 'b'); +ERROR: invalid regular expression: brackets [] not balanced +-- expectError 9.21 & {a[[=a} EBRACK +select * from test_regex('a[[=a', '', ''); +ERROR: invalid regular expression: brackets [] not balanced +select * from test_regex('a[[=a', '', 'b'); +ERROR: invalid regular expression: brackets [] not balanced +-- expectError 9.22 & {a[[:a} EBRACK +select * from test_regex('a[[:a', '', ''); +ERROR: invalid regular expression: brackets [] not balanced +select * from test_regex('a[[:a', '', 'b'); +ERROR: invalid regular expression: brackets [] not balanced +-- expectError 9.23 & {a[} EBRACK +select * from test_regex('a[', '', ''); +ERROR: invalid regular expression: brackets [] not balanced +select * from test_regex('a[', '', 'b'); +ERROR: invalid regular expression: brackets [] not balanced +-- expectError 9.24 & {a[b} EBRACK +select * from test_regex('a[b', '', ''); +ERROR: invalid regular expression: brackets [] not balanced +select * from test_regex('a[b', '', 'b'); +ERROR: invalid regular expression: brackets [] not balanced +-- expectError 9.25 & {a[b-} EBRACK +select * from test_regex('a[b-', '', ''); +ERROR: invalid regular expression: brackets [] not balanced +select * from test_regex('a[b-', '', 'b'); +ERROR: invalid regular expression: brackets [] not balanced +-- expectError 9.26 & {a[b-c} EBRACK +select * from test_regex('a[b-c', '', ''); +ERROR: invalid regular expression: brackets [] not balanced +select * from test_regex('a[b-c', '', 'b'); +ERROR: invalid regular expression: brackets [] not balanced +-- expectMatch 9.27 &M {a[b-c]} ab ab +select * from test_regex('a[b-c]', 'ab', 'M'); + test_regex +----------------- + {0,REG_UUNPORT} + {ab} +(2 rows) + +select * from test_regex('a[b-c]', 'ab', 'Mb'); + test_regex +----------------- + {0,REG_UUNPORT} + {ab} +(2 rows) + +-- expectMatch 9.28 & {a[b-b]} ab ab +select * from test_regex('a[b-b]', 'ab', ''); + test_regex +------------ + {0} + {ab} +(2 rows) + +select * from test_regex('a[b-b]', 'ab', 'b'); + test_regex +------------ + {0} + {ab} +(2 rows) + +-- expectMatch 9.29 &M {a[1-2]} a2 a2 +select * from test_regex('a[1-2]', 'a2', 'M'); + test_regex +----------------- + {0,REG_UUNPORT} + {a2} +(2 rows) + +select * from test_regex('a[1-2]', 'a2', 'Mb'); + test_regex +----------------- + {0,REG_UUNPORT} + {a2} +(2 rows) + +-- expectError 9.30 & {a[c-b]} ERANGE +select * from test_regex('a[c-b]', '', ''); +ERROR: invalid regular expression: invalid character range +select * from test_regex('a[c-b]', '', 'b'); +ERROR: invalid regular expression: invalid character range +-- expectError 9.31 & {a[a-b-c]} ERANGE +select * from test_regex('a[a-b-c]', '', ''); +ERROR: invalid regular expression: invalid character range +select * from test_regex('a[a-b-c]', '', 'b'); +ERROR: invalid regular expression: invalid character range +-- expectMatch 9.32 &M {a[--?]b} a?b a?b +select * from test_regex('a[--?]b', 'a?b', 'M'); + test_regex +----------------- + {0,REG_UUNPORT} + {a?b} +(2 rows) + +select * from test_regex('a[--?]b', 'a?b', 'Mb'); + test_regex +----------------- + {0,REG_UUNPORT} + {a?b} +(2 rows) + +-- expectMatch 9.33 & {a[---]b} a-b a-b +select * from test_regex('a[---]b', 'a-b', ''); + test_regex +------------ + {0} + {a-b} +(2 rows) + +select * from test_regex('a[---]b', 'a-b', 'b'); + test_regex +------------ + {0} + {a-b} +(2 rows) + +-- expectMatch 9.34 & {a[]b]c} a]c a]c +select * from test_regex('a[]b]c', 'a]c', ''); + test_regex +------------ + {0} + {a]c} +(2 rows) + +select * from test_regex('a[]b]c', 'a]c', 'b'); + test_regex +------------ + {0} + {a]c} +(2 rows) + +-- expectMatch 9.35 EP {a[\]]b} a]b a]b +select * from test_regex('a[\]]b', 'a]b', 'EP'); + test_regex +---------------------------- + {0,REG_UBBS,REG_UNONPOSIX} + {a]b} +(2 rows) + +-- expectNomatch 9.36 bE {a[\]]b} a]b +select * from test_regex('a[\]]b', 'a]b', 'bE'); + test_regex +-------------- + {0,REG_UBBS} +(1 row) + +-- expectMatch 9.37 bE {a[\]]b} "a\\]b" "a\\]b" +select * from test_regex('a[\]]b', 'a\]b', 'bE'); + test_regex +-------------- + {0,REG_UBBS} + {"a\\]b"} +(2 rows) + +-- expectMatch 9.38 eE {a[\]]b} "a\\]b" "a\\]b" +select * from test_regex('a[\]]b', 'a\]b', 'eE'); + test_regex +-------------- + {0,REG_UBBS} + {"a\\]b"} +(2 rows) + +-- expectMatch 9.39 EP {a[\\]b} "a\\b" "a\\b" +select * from test_regex('a[\\]b', 'a\b', 'EP'); + test_regex +---------------------------- + {0,REG_UBBS,REG_UNONPOSIX} + {"a\\b"} +(2 rows) + +-- expectMatch 9.40 eE {a[\\]b} "a\\b" "a\\b" +select * from test_regex('a[\\]b', 'a\b', 'eE'); + test_regex +-------------- + {0,REG_UBBS} + {"a\\b"} +(2 rows) + +-- expectMatch 9.41 bE {a[\\]b} "a\\b" "a\\b" +select * from test_regex('a[\\]b', 'a\b', 'bE'); + test_regex +-------------- + {0,REG_UBBS} + {"a\\b"} +(2 rows) + +-- expectError 9.42 - {a[\Z]b} EESCAPE +select * from test_regex('a[\Z]b', '', '-'); +ERROR: invalid regular expression: invalid escape \ sequence +-- expectMatch 9.43 & {a[[b]c} "a\[c" "a\[c" +select * from test_regex('a[[b]c', 'a[c', ''); + test_regex +------------ + {0} + {a[c} +(2 rows) + +select * from test_regex('a[[b]c', 'a[c', 'b'); + test_regex +------------ + {0} + {a[c} +(2 rows) + +-- This only works in UTF8 encoding, so it's moved to test_regex_utf8.sql: +-- expectMatch 9.44 EMP* {a[\u00fe-\u0507][\u00ff-\u0300]b} \ +-- "a\u0102\u02ffb" "a\u0102\u02ffb" +-- doing 10 "anchors and newlines" +-- expectMatch 10.1 & ^a a a +select * from test_regex('^a', 'a', ''); + test_regex +------------ + {0} + {a} +(2 rows) + +select * from test_regex('^a', 'a', 'b'); + test_regex +------------ + {0} + {a} +(2 rows) + +-- expectNomatch 10.2 &^ ^a a +select * from test_regex('^a', 'a', '^'); + test_regex +------------ + {0} +(1 row) + +select * from test_regex('^a', 'a', '^b'); + test_regex +------------ + {0} +(1 row) + +-- expectIndices 10.3 &N ^ a {0 -1} +select * from test_regex('^', 'a', '0N'); + test_regex +--------------------- + {0,REG_UEMPTYMATCH} + {"0 -1"} +(2 rows) + +select * from test_regex('^', 'a', '0Nb'); + test_regex +--------------------- + {0,REG_UEMPTYMATCH} + {"0 -1"} +(2 rows) + +-- expectIndices 10.4 & {a$} aba {2 2} +select * from test_regex('a$', 'aba', '0'); + test_regex +------------ + {0} + {"2 2"} +(2 rows) + +select * from test_regex('a$', 'aba', '0b'); + test_regex +------------ + {0} + {"2 2"} +(2 rows) + +-- expectNomatch 10.5 {&$} {a$} a +select * from test_regex('a$', 'a', '$'); + test_regex +------------ + {0} +(1 row) + +select * from test_regex('a$', 'a', '$b'); + test_regex +------------ + {0} +(1 row) + +-- expectIndices 10.6 &N {$} ab {2 1} +select * from test_regex('$', 'ab', '0N'); + test_regex +--------------------- + {0,REG_UEMPTYMATCH} + {"2 1"} +(2 rows) + +select * from test_regex('$', 'ab', '0Nb'); + test_regex +--------------------- + {0,REG_UEMPTYMATCH} + {"2 1"} +(2 rows) + +-- expectMatch 10.7 &n ^a a a +select * from test_regex('^a', 'a', 'n'); + test_regex +------------ + {0} + {a} +(2 rows) + +select * from test_regex('^a', 'a', 'nb'); + test_regex +------------ + {0} + {a} +(2 rows) + +-- expectMatch 10.8 &n "^a" "b\na" "a" +select * from test_regex('^a', E'b\na', 'n'); + test_regex +------------ + {0} + {a} +(2 rows) + +select * from test_regex('^a', E'b\na', 'nb'); + test_regex +------------ + {0} + {a} +(2 rows) + +-- expectIndices 10.9 &w "^a" "a\na" {0 0} +select * from test_regex('^a', E'a\na', '0w'); + test_regex +------------ + {0} + {"0 0"} +(2 rows) + +select * from test_regex('^a', E'a\na', '0wb'); + test_regex +------------ + {0} + {"0 0"} +(2 rows) + +-- expectIndices 10.10 &n^ "^a" "a\na" {2 2} +select * from test_regex('^a', E'a\na', '0n^'); + test_regex +------------ + {0} + {"2 2"} +(2 rows) + +select * from test_regex('^a', E'a\na', '0n^b'); + test_regex +------------ + {0} + {"2 2"} +(2 rows) + +-- expectMatch 10.11 &n {a$} a a +select * from test_regex('a$', 'a', 'n'); + test_regex +------------ + {0} + {a} +(2 rows) + +select * from test_regex('a$', 'a', 'nb'); + test_regex +------------ + {0} + {a} +(2 rows) + +-- expectMatch 10.12 &n "a\$" "a\nb" "a" +select * from test_regex('a$', E'a\nb', 'n'); + test_regex +------------ + {0} + {a} +(2 rows) + +select * from test_regex('a$', E'a\nb', 'nb'); + test_regex +------------ + {0} + {a} +(2 rows) + +-- expectIndices 10.13 &n "a\$" "a\na" {0 0} +select * from test_regex('a$', E'a\na', '0n'); + test_regex +------------ + {0} + {"0 0"} +(2 rows) + +select * from test_regex('a$', E'a\na', '0nb'); + test_regex +------------ + {0} + {"0 0"} +(2 rows) + +-- expectIndices 10.14 N ^^ a {0 -1} +select * from test_regex('^^', 'a', '0N'); + test_regex +--------------------- + {0,REG_UEMPTYMATCH} + {"0 -1"} +(2 rows) + +-- expectMatch 10.15 b ^^ ^ ^ +select * from test_regex('^^', '^', 'b'); + test_regex +------------ + {0} + {^} +(2 rows) + +-- expectIndices 10.16 N {$$} a {1 0} +select * from test_regex('$$', 'a', '0N'); + test_regex +--------------------- + {0,REG_UEMPTYMATCH} + {"1 0"} +(2 rows) + +-- expectMatch 10.17 b {$$} "\$" "\$" +select * from test_regex('$$', '$', 'b'); + test_regex +------------ + {0} + {$} +(2 rows) + +-- expectMatch 10.18 &N {^$} "" "" +select * from test_regex('^$', '', 'N'); + test_regex +--------------------- + {0,REG_UEMPTYMATCH} + {""} +(2 rows) + +select * from test_regex('^$', '', 'Nb'); + test_regex +--------------------- + {0,REG_UEMPTYMATCH} + {""} +(2 rows) + +-- expectNomatch 10.19 &N {^$} a +select * from test_regex('^$', 'a', 'N'); + test_regex +--------------------- + {0,REG_UEMPTYMATCH} +(1 row) + +select * from test_regex('^$', 'a', 'Nb'); + test_regex +--------------------- + {0,REG_UEMPTYMATCH} +(1 row) + +-- expectIndices 10.20 &nN "^\$" a\n\nb {2 1} +select * from test_regex('^$', E'a\n\nb', '0nN'); + test_regex +--------------------- + {0,REG_UEMPTYMATCH} + {"2 1"} +(2 rows) + +select * from test_regex('^$', E'a\n\nb', '0nNb'); + test_regex +--------------------- + {0,REG_UEMPTYMATCH} + {"2 1"} +(2 rows) + +-- expectMatch 10.21 N {$^} "" "" +select * from test_regex('$^', '', 'N'); + test_regex +--------------------- + {0,REG_UEMPTYMATCH} + {""} +(2 rows) + +-- expectMatch 10.22 b {$^} "\$^" "\$^" +select * from test_regex('$^', '$^', 'b'); + test_regex +------------ + {0} + {$^} +(2 rows) + +-- expectMatch 10.23 P {\Aa} a a +select * from test_regex('\Aa', 'a', 'P'); + test_regex +------------------- + {0,REG_UNONPOSIX} + {a} +(2 rows) + +-- expectMatch 10.24 ^P {\Aa} a a +select * from test_regex('\Aa', 'a', '^P'); + test_regex +------------------- + {0,REG_UNONPOSIX} + {a} +(2 rows) + +-- expectNomatch 10.25 ^nP {\Aa} "b\na" +select * from test_regex('\Aa', E'b\na', '^nP'); + test_regex +------------------- + {0,REG_UNONPOSIX} +(1 row) + +-- expectMatch 10.26 P {a\Z} a a +select * from test_regex('a\Z', 'a', 'P'); + test_regex +------------------- + {0,REG_UNONPOSIX} + {a} +(2 rows) + +-- expectMatch 10.27 \$P {a\Z} a a +select * from test_regex('a\Z', 'a', '$P'); + test_regex +------------------- + {0,REG_UNONPOSIX} + {a} +(2 rows) + +-- expectNomatch 10.28 \$nP {a\Z} "a\nb" +select * from test_regex('a\Z', E'a\nb', '$nP'); + test_regex +------------------- + {0,REG_UNONPOSIX} +(1 row) + +-- expectError 10.29 - ^* BADRPT +select * from test_regex('^*', '', '-'); +ERROR: invalid regular expression: quantifier operand invalid +-- expectError 10.30 - {$*} BADRPT +select * from test_regex('$*', '', '-'); +ERROR: invalid regular expression: quantifier operand invalid +-- expectError 10.31 - {\A*} BADRPT +select * from test_regex('\A*', '', '-'); +ERROR: invalid regular expression: quantifier operand invalid +-- expectError 10.32 - {\Z*} BADRPT +select * from test_regex('\Z*', '', '-'); +ERROR: invalid regular expression: quantifier operand invalid +-- doing 11 "boundary constraints" +-- expectMatch 11.1 &LP {[[:<:]]a} a a +select * from test_regex('[[:<:]]a', 'a', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {a} +(2 rows) + +select * from test_regex('[[:<:]]a', 'a', 'LPb'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {a} +(2 rows) + +-- expectMatch 11.2 &LP {[[:<:]]a} -a a +select * from test_regex('[[:<:]]a', '-a', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {a} +(2 rows) + +select * from test_regex('[[:<:]]a', '-a', 'LPb'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {a} +(2 rows) + +-- expectNomatch 11.3 &LP {[[:<:]]a} ba +select * from test_regex('[[:<:]]a', 'ba', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} +(1 row) + +select * from test_regex('[[:<:]]a', 'ba', 'LPb'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} +(1 row) + +-- expectMatch 11.4 &LP {a[[:>:]]} a a +select * from test_regex('a[[:>:]]', 'a', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {a} +(2 rows) + +select * from test_regex('a[[:>:]]', 'a', 'LPb'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {a} +(2 rows) + +-- expectMatch 11.5 &LP {a[[:>:]]} a- a +select * from test_regex('a[[:>:]]', 'a-', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {a} +(2 rows) + +select * from test_regex('a[[:>:]]', 'a-', 'LPb'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {a} +(2 rows) + +-- expectNomatch 11.6 &LP {a[[:>:]]} ab +select * from test_regex('a[[:>:]]', 'ab', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} +(1 row) + +select * from test_regex('a[[:>:]]', 'ab', 'LPb'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} +(1 row) + +-- expectMatch 11.7 bLP {\} a a +select * from test_regex('a\>', 'a', 'bLP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {a} +(2 rows) + +-- expectNomatch 11.10 bLP {a\>} ab +select * from test_regex('a\>', 'ab', 'bLP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} +(1 row) + +-- expectMatch 11.11 LP {\ya} a a +select * from test_regex('\ya', 'a', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {a} +(2 rows) + +-- expectNomatch 11.12 LP {\ya} ba +select * from test_regex('\ya', 'ba', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} +(1 row) + +-- expectMatch 11.13 LP {a\y} a a +select * from test_regex('a\y', 'a', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {a} +(2 rows) + +-- expectNomatch 11.14 LP {a\y} ab +select * from test_regex('a\y', 'ab', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} +(1 row) + +-- expectMatch 11.15 LP {a\Y} ab a +select * from test_regex('a\Y', 'ab', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {a} +(2 rows) + +-- expectNomatch 11.16 LP {a\Y} a- +select * from test_regex('a\Y', 'a-', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} +(1 row) + +-- expectNomatch 11.17 LP {a\Y} a +select * from test_regex('a\Y', 'a', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} +(1 row) + +-- expectNomatch 11.18 LP {-\Y} -a +select * from test_regex('-\Y', '-a', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} +(1 row) + +-- expectMatch 11.19 LP {-\Y} -% - +select * from test_regex('-\Y', '-%', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {-} +(2 rows) + +-- expectNomatch 11.20 LP {\Y-} a- +select * from test_regex('\Y-', 'a-', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} +(1 row) + +-- expectError 11.21 - {[[:<:]]*} BADRPT +select * from test_regex('[[:<:]]*', '', '-'); +ERROR: invalid regular expression: quantifier operand invalid +-- expectError 11.22 - {[[:>:]]*} BADRPT +select * from test_regex('[[:>:]]*', '', '-'); +ERROR: invalid regular expression: quantifier operand invalid +-- expectError 11.23 b {\<*} BADRPT +select * from test_regex('\<*', '', 'b'); +ERROR: invalid regular expression: quantifier operand invalid +-- expectError 11.24 b {\>*} BADRPT +select * from test_regex('\>*', '', 'b'); +ERROR: invalid regular expression: quantifier operand invalid +-- expectError 11.25 - {\y*} BADRPT +select * from test_regex('\y*', '', '-'); +ERROR: invalid regular expression: quantifier operand invalid +-- expectError 11.26 - {\Y*} BADRPT +select * from test_regex('\Y*', '', '-'); +ERROR: invalid regular expression: quantifier operand invalid +-- expectMatch 11.27 LP {\ma} a a +select * from test_regex('\ma', 'a', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {a} +(2 rows) + +-- expectNomatch 11.28 LP {\ma} ba +select * from test_regex('\ma', 'ba', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} +(1 row) + +-- expectMatch 11.29 LP {a\M} a a +select * from test_regex('a\M', 'a', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {a} +(2 rows) + +-- expectNomatch 11.30 LP {a\M} ab +select * from test_regex('a\M', 'ab', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} +(1 row) + +-- expectNomatch 11.31 ILP {\Ma} a +select * from test_regex('\Ma', 'a', 'ILP'); + test_regex +----------------------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE,REG_UIMPOSSIBLE} +(1 row) + +-- expectNomatch 11.32 ILP {a\m} a +select * from test_regex('a\m', 'a', 'ILP'); + test_regex +----------------------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE,REG_UIMPOSSIBLE} +(1 row) + +-- doing 12 "character classes" +-- expectMatch 12.1 LP {a\db} a0b a0b +select * from test_regex('a\db', 'a0b', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {a0b} +(2 rows) + +-- expectNomatch 12.2 LP {a\db} axb +select * from test_regex('a\db', 'axb', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} +(1 row) + +-- expectNomatch 12.3 LP {a\Db} a0b +select * from test_regex('a\Db', 'a0b', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} +(1 row) + +-- expectMatch 12.4 LP {a\Db} axb axb +select * from test_regex('a\Db', 'axb', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {axb} +(2 rows) + +-- expectMatch 12.5 LP "a\\sb" "a b" "a b" +select * from test_regex('a\sb', 'a b', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {"a b"} +(2 rows) + +-- expectMatch 12.6 LP "a\\sb" "a\tb" "a\tb" +select * from test_regex('a\sb', E'a\tb', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {"a b"} +(2 rows) + +-- expectMatch 12.7 LP "a\\sb" "a\nb" "a\nb" +select * from test_regex('a\sb', E'a\nb', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {"a + + b"} +(2 rows) + +-- expectNomatch 12.8 LP {a\sb} axb +select * from test_regex('a\sb', 'axb', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} +(1 row) + +-- expectMatch 12.9 LP {a\Sb} axb axb +select * from test_regex('a\Sb', 'axb', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {axb} +(2 rows) + +-- expectNomatch 12.10 LP "a\\Sb" "a b" +select * from test_regex('a\Sb', 'a b', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} +(1 row) + +-- expectMatch 12.11 LP {a\wb} axb axb +select * from test_regex('a\wb', 'axb', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {axb} +(2 rows) + +-- expectNomatch 12.12 LP {a\wb} a-b +select * from test_regex('a\wb', 'a-b', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} +(1 row) + +-- expectNomatch 12.13 LP {a\Wb} axb +select * from test_regex('a\Wb', 'axb', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} +(1 row) + +-- expectMatch 12.14 LP {a\Wb} a-b a-b +select * from test_regex('a\Wb', 'a-b', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {a-b} +(2 rows) + +-- expectMatch 12.15 LP {\y\w+z\y} adze-guz guz +select * from test_regex('\y\w+z\y', 'adze-guz', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {guz} +(2 rows) + +-- expectMatch 12.16 LPE {a[\d]b} a1b a1b +select * from test_regex('a[\d]b', 'a1b', 'LPE'); + test_regex +---------------------------------------- + {0,REG_UBBS,REG_UNONPOSIX,REG_ULOCALE} + {a1b} +(2 rows) + +-- expectMatch 12.17 LPE "a\[\\s]b" "a b" "a b" +select * from test_regex('a[\s]b', 'a b', 'LPE'); + test_regex +---------------------------------------- + {0,REG_UBBS,REG_UNONPOSIX,REG_ULOCALE} + {"a b"} +(2 rows) + +-- expectMatch 12.18 LPE {a[\w]b} axb axb +select * from test_regex('a[\w]b', 'axb', 'LPE'); + test_regex +---------------------------------------- + {0,REG_UBBS,REG_UNONPOSIX,REG_ULOCALE} + {axb} +(2 rows) + +-- doing 13 "escapes" +-- expectError 13.1 & "a\\" EESCAPE +select * from test_regex('a\', '', ''); +ERROR: invalid regular expression: invalid escape \ sequence +select * from test_regex('a\', '', 'b'); +ERROR: invalid regular expression: invalid escape \ sequence +-- expectMatch 13.2 - {a\]+)>} a +-- } 1 +select * from test_regex('\A\s*[^<]*\s*<([^>]+)>', 'a', 'LP'); + test_regex +------------------------------- + {1,REG_UNONPOSIX,REG_ULOCALE} + {a,a} +(2 rows) + +-- test reg-33.4 {Bug 505048} { +-- regexp {\A\s*([^b]*)b} ab +-- } 1 +select * from test_regex('\A\s*([^b]*)b', 'ab', 'LP'); + test_regex +------------------------------- + {1,REG_UNONPOSIX,REG_ULOCALE} + {ab,a} +(2 rows) + +-- test reg-33.5 {Bug 505048} { +-- regexp {\A\s*[^b]*(b)} ab +-- } 1 +select * from test_regex('\A\s*[^b]*(b)', 'ab', 'LP'); + test_regex +------------------------------- + {1,REG_UNONPOSIX,REG_ULOCALE} + {ab,b} +(2 rows) + +-- test reg-33.6 {Bug 505048} { +-- regexp {\A(\s*)[^b]*(b)} ab +-- } 1 +select * from test_regex('\A(\s*)[^b]*(b)', 'ab', 'LP'); + test_regex +------------------------------- + {2,REG_UNONPOSIX,REG_ULOCALE} + {ab,"",b} +(2 rows) + +-- test reg-33.7 {Bug 505048} { +-- regexp {\A\s*[^b]*b} ab +-- } 1 +select * from test_regex('\A\s*[^b]*b', 'ab', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {ab} +(2 rows) + +-- test reg-33.8 {Bug 505048} { +-- regexp -inline {\A\s*[^b]*b} ab +-- } ab +select * from test_regex('\A\s*[^b]*b', 'ab', 'LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {ab} +(2 rows) + +-- test reg-33.9 {Bug 505048} { +-- regexp -indices -inline {\A\s*[^b]*b} ab +-- } {{0 1}} +select * from test_regex('\A\s*[^b]*b', 'ab', '0LP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE} + {"0 1"} +(2 rows) + +-- test reg-33.10 {Bug 840258} -body { +-- regsub {(^|\n)+\.*b} \n.b {} tmp +-- } -cleanup { +-- unset tmp +-- } -result 1 +select * from test_regex('(^|\n)+\.*b', E'\n.b', 'P'); + test_regex +------------------- + {1,REG_UNONPOSIX} + {" + + .b"," + + "} +(2 rows) + +-- test reg-33.11 {Bug 840258} -body { +-- regsub {(^|[\n\r]+)\.*\?<.*?(\n|\r)+} \ +-- "TQ\r\n.?<5000267>Test already stopped\r\n" {} tmp +-- } -cleanup { +-- unset tmp +-- } -result 1 +select * from test_regex('(^|[\n\r]+)\.*\?<.*?(\n|\r)+', E'TQ\r\n.?<5000267>Test already stopped\r\n', 'EP'); + test_regex +----------------------------------- + {2,REG_UBBS,REG_UNONPOSIX} + {"\r + + .?<5000267>Test already stopped\r+ + ","\r + + "," + + "} +(2 rows) + +-- test reg-33.12 {Bug 1810264 - bad read} { +-- regexp {\3161573148} {\3161573148} +-- } 0 +select * from test_regex('\3161573148', '\3161573148', 'MP'); + test_regex +------------------------------- + {0,REG_UNONPOSIX,REG_UUNPORT} +(1 row) + +-- test reg-33.13 {Bug 1810264 - infinite loop} { +-- regexp {($|^)*} {x} +-- } 1 +select * from test_regex('($|^)*', 'x', 'N'); + test_regex +--------------------- + {1,REG_UEMPTYMATCH} + {"",""} +(2 rows) + +-- # Some environments have small default stack sizes. [Bug 1905562] +-- test reg-33.14 {Bug 1810264 - super-expensive expression} nonPortable { +-- regexp {(x{200}){200}$y} {x} +-- } 0 +-- This might or might not work depending on platform, so skip it +-- select * from test_regex('(x{200}){200}$y', 'x', 'IQ'); +-- test reg-33.15.1 {Bug 3603557 - an "in the wild" RE} { +-- lindex [regexp -expanded -about { +-- ^TETRA_MODE_CMD # Message Type +-- ([[:blank:]]+) # Pad +-- (ETS_1_1|ETS_1_2|ETS_2_2) # SystemCode +-- ([[:blank:]]+) # Pad +-- (CONTINUOUS|CARRIER|MCCH|TRAFFIC) # SharingMode +-- ([[:blank:]]+) # Pad +-- ([[:digit:]]{1,2}) # ColourCode +-- ([[:blank:]]+) # Pad +-- (1|2|3|4|6|9|12|18) # TSReservedFrames +-- ([[:blank:]]+) # Pad +-- (PASS|TRUE|FAIL|FALSE) # UPlaneDTX +-- ([[:blank:]]+) # Pad +-- (PASS|TRUE|FAIL|FALSE) # Frame18Extension +-- ([[:blank:]]+) # Pad +-- ([[:digit:]]{1,4}) # MCC +-- ([[:blank:]]+) # Pad +-- ([[:digit:]]{1,5}) # MNC +-- ([[:blank:]]+) # Pad +-- (BOTH|BCAST|ENQRY|NONE) # NbrCellBcast +-- ([[:blank:]]+) # Pad +-- (UNKNOWN|LOW|MEDIUM|HIGH) # CellServiceLevel +-- ([[:blank:]]+) # Pad +-- (PASS|TRUE|FAIL|FALSE) # LateEntryInfo +-- ([[:blank:]]+) # Pad +-- (300|400) # FrequencyBand +-- ([[:blank:]]+) # Pad +-- (NORMAL|REVERSE) # ReverseOperation +-- ([[:blank:]]+) # Pad +-- (NONE|\+6\.25|\-6\.25|\+12\.5) # Offset +-- ([[:blank:]]+) # Pad +-- (10) # DuplexSpacing +-- ([[:blank:]]+) # Pad +-- ([[:digit:]]{1,4}) # MainCarrierNr +-- ([[:blank:]]+) # Pad +-- (0|1|2|3) # NrCSCCH +-- ([[:blank:]]+) # Pad +-- (15|20|25|30|35|40|45) # MSTxPwrMax +-- ([[:blank:]]+) # Pad +-- (\-125|\-120|\-115|\-110|\-105|\-100|\-95|\-90|\-85|\-80|\-75|\-70|\-65|\-60|\-55|\-50) +-- # RxLevAccessMin +-- ([[:blank:]]+) # Pad +-- (\-53|\-51|\-49|\-47|\-45|\-43|\-41|\-39|\-37|\-35|\-33|\-31|\-29|\-27|\-25|\-23) +-- # AccessParameter +-- ([[:blank:]]+) # Pad +-- (DISABLE|[[:digit:]]{3,4}) # RadioDLTimeout +-- ([[:blank:]]+) # Pad +-- (\-[[:digit:]]{2,3}) # RSSIThreshold +-- ([[:blank:]]+) # Pad +-- ([[:digit:]]{1,5}) # CCKIdSCKVerNr +-- ([[:blank:]]+) # Pad +-- ([[:digit:]]{1,5}) # LocationArea +-- ([[:blank:]]+) # Pad +-- ([(1|0)]{16}) # SubscriberClass +-- ([[:blank:]]+) # Pad +-- ([(1|0)]{12}) # BSServiceDetails +-- ([[:blank:]]+) # Pad +-- (RANDOMIZE|IMMEDIATE|[[:digit:]]{1,2}) # IMM +-- ([[:blank:]]+) # Pad +-- ([[:digit:]]{1,2}) # WT +-- ([[:blank:]]+) # Pad +-- ([[:digit:]]{1,2}) # Nu +-- ([[:blank:]]+) # Pad +-- ([0-1]) # FrameLngFctr +-- ([[:blank:]]+) # Pad +-- ([[:digit:]]{1,2}) # TSPtr +-- ([[:blank:]]+) # Pad +-- ([0-7]) # MinPriority +-- ([[:blank:]]+) # Pad +-- (PASS|TRUE|FAIL|FALSE) # ExtdSrvcsEnabled +-- ([[:blank:]]+) # Pad +-- (.*) # ConditionalFields +-- }] 0 +-- } 68 +select * from test_regex($$ + ^TETRA_MODE_CMD # Message Type + ([[:blank:]]+) # Pad + (ETS_1_1|ETS_1_2|ETS_2_2) # SystemCode + ([[:blank:]]+) # Pad + (CONTINUOUS|CARRIER|MCCH|TRAFFIC) # SharingMode + ([[:blank:]]+) # Pad + ([[:digit:]]{1,2}) # ColourCode + ([[:blank:]]+) # Pad + (1|2|3|4|6|9|12|18) # TSReservedFrames + ([[:blank:]]+) # Pad + (PASS|TRUE|FAIL|FALSE) # UPlaneDTX + ([[:blank:]]+) # Pad + (PASS|TRUE|FAIL|FALSE) # Frame18Extension + ([[:blank:]]+) # Pad + ([[:digit:]]{1,4}) # MCC + ([[:blank:]]+) # Pad + ([[:digit:]]{1,5}) # MNC + ([[:blank:]]+) # Pad + (BOTH|BCAST|ENQRY|NONE) # NbrCellBcast + ([[:blank:]]+) # Pad + (UNKNOWN|LOW|MEDIUM|HIGH) # CellServiceLevel + ([[:blank:]]+) # Pad + (PASS|TRUE|FAIL|FALSE) # LateEntryInfo + ([[:blank:]]+) # Pad + (300|400) # FrequencyBand + ([[:blank:]]+) # Pad + (NORMAL|REVERSE) # ReverseOperation + ([[:blank:]]+) # Pad + (NONE|\+6\.25|\-6\.25|\+12\.5) # Offset + ([[:blank:]]+) # Pad + (10) # DuplexSpacing + ([[:blank:]]+) # Pad + ([[:digit:]]{1,4}) # MainCarrierNr + ([[:blank:]]+) # Pad + (0|1|2|3) # NrCSCCH + ([[:blank:]]+) # Pad + (15|20|25|30|35|40|45) # MSTxPwrMax + ([[:blank:]]+) # Pad + (\-125|\-120|\-115|\-110|\-105|\-100|\-95|\-90|\-85|\-80|\-75|\-70|\-65|\-60|\-55|\-50) + # RxLevAccessMin + ([[:blank:]]+) # Pad + (\-53|\-51|\-49|\-47|\-45|\-43|\-41|\-39|\-37|\-35|\-33|\-31|\-29|\-27|\-25|\-23) + # AccessParameter + ([[:blank:]]+) # Pad + (DISABLE|[[:digit:]]{3,4}) # RadioDLTimeout + ([[:blank:]]+) # Pad + (\-[[:digit:]]{2,3}) # RSSIThreshold + ([[:blank:]]+) # Pad + ([[:digit:]]{1,5}) # CCKIdSCKVerNr + ([[:blank:]]+) # Pad + ([[:digit:]]{1,5}) # LocationArea + ([[:blank:]]+) # Pad + ([(1|0)]{16}) # SubscriberClass + ([[:blank:]]+) # Pad + ([(1|0)]{12}) # BSServiceDetails + ([[:blank:]]+) # Pad + (RANDOMIZE|IMMEDIATE|[[:digit:]]{1,2}) # IMM + ([[:blank:]]+) # Pad + ([[:digit:]]{1,2}) # WT + ([[:blank:]]+) # Pad + ([[:digit:]]{1,2}) # Nu + ([[:blank:]]+) # Pad + ([0-1]) # FrameLngFctr + ([[:blank:]]+) # Pad + ([[:digit:]]{1,2}) # TSPtr + ([[:blank:]]+) # Pad + ([0-7]) # MinPriority + ([[:blank:]]+) # Pad + (PASS|TRUE|FAIL|FALSE) # ExtdSrvcsEnabled + ([[:blank:]]+) # Pad + (.*) # ConditionalFields + $$, '', 'xLMPQ'); + test_regex +-------------------------------------------------------- + {68,REG_UBOUNDS,REG_UNONPOSIX,REG_UUNPORT,REG_ULOCALE} +(1 row) + +-- test reg-33.16.1 {Bug [8d2c0da36d]- another "in the wild" RE} { +-- lindex [regexp -about "^MRK:client1: =1339 14HKelly Talisman 10011000 (\[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]*) \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* 8 0 8 0 0 0 77 77 1 1 2 0 11 { 1 3 8 \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* 00000000 1 13HC6 My Creator 2 3 8 \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* 00000000 1 31HC7 Slightly offensive name, huh 3 8 8 \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* 00000000 1 23HE-mail:kelly@hotbox.com 4 9 8 \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* 00000000 1 17Hcompface must die 5 10 8 \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* 00000000 0 3HAir 6 12 8 \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* 00000000 1 14HPGP public key 7 13 8 \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* 00000000 1 16Hkelly@hotbox.com 8 30 8 \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* 00000000 0 12H2 text/plain 9 30 8 \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* 00000000 0 13H2 x-kom/basic 10 33 8 \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* 00000000 1 1H0 11 14 8 \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* 00000000 1 1H3 }\r?"] 0 +-- } 1 +select * from test_regex(E'^MRK:client1: =1339 14HKelly Talisman 10011000 ([0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]*) [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* 8 0 8 0 0 0 77 77 1 1 2 0 11 { 1 3 8 [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* 00000000 1 13HC6 My Creator 2 3 8 [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* 00000000 1 31HC7 Slightly offensive name, huh 3 8 8 [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* 00000000 1 23HE-mail:kelly@hotbox.com 4 9 8 [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* 00000000 1 17Hcompface must die 5 10 8 [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* 00000000 0 3HAir 6 12 8 [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* 00000000 1 14HPGP public key 7 13 8 [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* 00000000 1 16Hkelly@hotbox.com 8 30 8 [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* 00000000 0 12H2 text/plain 9 30 8 [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* 00000000 0 13H2 x-kom/basic 10 33 8 [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* 00000000 1 1H0 11 14 8 [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* 00000000 1 1H3 }\r?', '', 'BMS'); + test_regex +----------------------------------------- + {1,REG_UBRACES,REG_UUNSPEC,REG_UUNPORT} +(1 row) + +-- test reg-33.15 {constraint fixes} { +-- regexp {(^)+^} x +-- } 1 +select * from test_regex('(^)+^', 'x', 'N'); + test_regex +--------------------- + {1,REG_UEMPTYMATCH} + {"",""} +(2 rows) + +-- test reg-33.16 {constraint fixes} { +-- regexp {($^)+} x +-- } 0 +select * from test_regex('($^)+', 'x', 'N'); + test_regex +--------------------- + {1,REG_UEMPTYMATCH} +(1 row) + +-- test reg-33.17 {constraint fixes} { +-- regexp {(^$)*} x +-- } 1 +select * from test_regex('(^$)*', 'x', 'N'); + test_regex +--------------------- + {1,REG_UEMPTYMATCH} + {"",NULL} +(2 rows) + +-- test reg-33.18 {constraint fixes} { +-- regexp {(^(?!aa))+} {aa bb cc} +-- } 0 +select * from test_regex('(^(?!aa))+', 'aa bb cc', 'HP'); + test_regex +----------------------------------- + {1,REG_ULOOKAROUND,REG_UNONPOSIX} +(1 row) + +-- test reg-33.19 {constraint fixes} { +-- regexp {(^(?!aa)(?!bb)(?!cc))+} {aa x} +-- } 0 +select * from test_regex('(^(?!aa)(?!bb)(?!cc))+', 'aa x', 'HP'); + test_regex +----------------------------------- + {1,REG_ULOOKAROUND,REG_UNONPOSIX} +(1 row) + +-- test reg-33.20 {constraint fixes} { +-- regexp {(^(?!aa)(?!bb)(?!cc))+} {bb x} +-- } 0 +select * from test_regex('(^(?!aa)(?!bb)(?!cc))+', 'bb x', 'HP'); + test_regex +----------------------------------- + {1,REG_ULOOKAROUND,REG_UNONPOSIX} +(1 row) + +-- test reg-33.21 {constraint fixes} { +-- regexp {(^(?!aa)(?!bb)(?!cc))+} {cc x} +-- } 0 +select * from test_regex('(^(?!aa)(?!bb)(?!cc))+', 'cc x', 'HP'); + test_regex +----------------------------------- + {1,REG_ULOOKAROUND,REG_UNONPOSIX} +(1 row) + +-- test reg-33.22 {constraint fixes} { +-- regexp {(^(?!aa)(?!bb)(?!cc))+} {dd x} +-- } 1 +select * from test_regex('(^(?!aa)(?!bb)(?!cc))+', 'dd x', 'HP'); + test_regex +----------------------------------- + {1,REG_ULOOKAROUND,REG_UNONPOSIX} + {"",""} +(2 rows) + +-- test reg-33.23 {} { +-- regexp {abcd(\m)+xyz} x +-- } 0 +select * from test_regex('abcd(\m)+xyz', 'x', 'ILP'); + test_regex +----------------------------------------------- + {1,REG_UNONPOSIX,REG_ULOCALE,REG_UIMPOSSIBLE} +(1 row) + +-- test reg-33.24 {} { +-- regexp {abcd(\m)+xyz} a +-- } 0 +select * from test_regex('abcd(\m)+xyz', 'a', 'ILP'); + test_regex +----------------------------------------------- + {1,REG_UNONPOSIX,REG_ULOCALE,REG_UIMPOSSIBLE} +(1 row) + +-- test reg-33.25 {} { +-- regexp {^abcd*(((((^(a c(e?d)a+|)+|)+|)+|)+|a)+|)} x +-- } 0 +select * from test_regex('^abcd*(((((^(a c(e?d)a+|)+|)+|)+|)+|a)+|)', 'x', 'S'); + test_regex +----------------- + {7,REG_UUNSPEC} +(1 row) + +-- test reg-33.26 {} { +-- regexp {a^(^)bcd*xy(((((($a+|)+|)+|)+$|)+|)+|)^$} x +-- } 0 +select * from test_regex('a^(^)bcd*xy(((((($a+|)+|)+|)+$|)+|)+|)^$', 'x', 'IS'); + test_regex +--------------------------------- + {7,REG_UUNSPEC,REG_UIMPOSSIBLE} +(1 row) + +-- test reg-33.27 {} { +-- regexp {xyz(\Y\Y)+} x +-- } 0 +select * from test_regex('xyz(\Y\Y)+', 'x', 'LP'); + test_regex +------------------------------- + {1,REG_UNONPOSIX,REG_ULOCALE} +(1 row) + +-- test reg-33.28 {} { +-- regexp {x|(?:\M)+} x +-- } 1 +select * from test_regex('x|(?:\M)+', 'x', 'LNP'); + test_regex +----------------------------------------------- + {0,REG_UNONPOSIX,REG_ULOCALE,REG_UEMPTYMATCH} + {x} +(2 rows) + +-- test reg-33.29 {} { +-- # This is near the limits of the RE engine +-- regexp [string repeat x*y*z* 480] x +-- } 1 +-- The runtime cost of this seems out of proportion to the value, +-- so for Postgres purposes reduce the repeat to 200x +select * from test_regex(repeat('x*y*z*', 200), 'x', 'N'); + test_regex +--------------------- + {0,REG_UEMPTYMATCH} + {x} +(2 rows) + +-- test reg-33.30 {Bug 1080042} { +-- regexp {(\Y)+} foo +-- } 1 +select * from test_regex('(\Y)+', 'foo', 'LNP'); + test_regex +----------------------------------------------- + {1,REG_UNONPOSIX,REG_ULOCALE,REG_UEMPTYMATCH} + {"",""} +(2 rows) + diff --git a/src/test/modules/test_regex/expected/test_regex_utf8.out b/src/test/modules/test_regex/expected/test_regex_utf8.out new file mode 100644 index 0000000000000..112698ac618bc --- /dev/null +++ b/src/test/modules/test_regex/expected/test_regex_utf8.out @@ -0,0 +1,100 @@ +/* + * This test must be run in a database with UTF-8 encoding, + * because other encodings don't support all the characters used. + */ +SELECT getdatabaseencoding() <> 'UTF8' + AS skip_test \gset +\if :skip_test +\quit +\endif +set client_encoding = utf8; +set standard_conforming_strings = on; +-- Run the Tcl test cases that require Unicode +-- expectMatch 9.44 EMP* {a[\u00fe-\u0507][\u00ff-\u0300]b} \ +-- "a\u0102\u02ffb" "a\u0102\u02ffb" +select * from test_regex('a[\u00fe-\u0507][\u00ff-\u0300]b', E'a\u0102\u02ffb', 'EMP*'); + test_regex +---------------------------------------- + {0,REG_UBBS,REG_UNONPOSIX,REG_UUNPORT} + {aĂ˿b} +(2 rows) + +-- expectMatch 13.27 P "a\\U00001234x" "a\u1234x" "a\u1234x" +select * from test_regex('a\U00001234x', E'a\u1234x', 'P'); + test_regex +------------------- + {0,REG_UNONPOSIX} + {aሴx} +(2 rows) + +-- expectMatch 13.28 P {a\U00001234x} "a\u1234x" "a\u1234x" +select * from test_regex('a\U00001234x', E'a\u1234x', 'P'); + test_regex +------------------- + {0,REG_UNONPOSIX} + {aሴx} +(2 rows) + +-- expectMatch 13.29 P "a\\U0001234x" "a\u1234x" "a\u1234x" +-- Tcl has relaxed their code to allow 1-8 hex digits, but Postgres hasn't +select * from test_regex('a\U0001234x', E'a\u1234x', 'P'); +ERROR: invalid regular expression: invalid escape \ sequence +-- expectMatch 13.30 P {a\U0001234x} "a\u1234x" "a\u1234x" +-- Tcl has relaxed their code to allow 1-8 hex digits, but Postgres hasn't +select * from test_regex('a\U0001234x', E'a\u1234x', 'P'); +ERROR: invalid regular expression: invalid escape \ sequence +-- expectMatch 13.31 P "a\\U000012345x" "a\u12345x" "a\u12345x" +select * from test_regex('a\U000012345x', E'a\u12345x', 'P'); + test_regex +------------------- + {0,REG_UNONPOSIX} + {aሴ5x} +(2 rows) + +-- expectMatch 13.32 P {a\U000012345x} "a\u12345x" "a\u12345x" +select * from test_regex('a\U000012345x', E'a\u12345x', 'P'); + test_regex +------------------- + {0,REG_UNONPOSIX} + {aሴ5x} +(2 rows) + +-- expectMatch 13.33 P "a\\U1000000x" "a\ufffd0x" "a\ufffd0x" +-- Tcl allows this as a standalone character, but Postgres doesn't +select * from test_regex('a\U1000000x', E'a\ufffd0x', 'P'); +ERROR: invalid regular expression: invalid escape \ sequence +-- expectMatch 13.34 P {a\U1000000x} "a\ufffd0x" "a\ufffd0x" +-- Tcl allows this as a standalone character, but Postgres doesn't +select * from test_regex('a\U1000000x', E'a\ufffd0x', 'P'); +ERROR: invalid regular expression: invalid escape \ sequence +-- Additional tests, not derived from Tcl +-- Exercise logic around high character ranges a bit more +select * from test_regex('a + [\u1000-\u1100]* + [\u3000-\u3100]* + [\u1234-\u25ff]+ + [\u2000-\u35ff]* + [\u2600-\u2f00]* + \u1236\u1236x', + E'a\u1234\u1236\u1236x', 'xEMP'); + test_regex +---------------------------------------- + {0,REG_UBBS,REG_UNONPOSIX,REG_UUNPORT} + {aሴሶሶx} +(2 rows) + +select * from test_regex('[[:alnum:]]*[[:upper:]]*[\u1000-\u2000]*\u1237', + E'\u1500\u1237', 'ELMP'); + test_regex +---------------------------------------------------- + {0,REG_UBBS,REG_UNONPOSIX,REG_UUNPORT,REG_ULOCALE} + {ᔀሷ} +(2 rows) + +select * from test_regex('[[:alnum:]]*[[:upper:]]*[\u1000-\u2000]*\u1237', + E'A\u1239', 'ELMP'); + test_regex +---------------------------------------------------- + {0,REG_UBBS,REG_UNONPOSIX,REG_UUNPORT,REG_ULOCALE} +(1 row) + diff --git a/src/test/modules/test_regex/expected/test_regex_utf8_1.out b/src/test/modules/test_regex/expected/test_regex_utf8_1.out new file mode 100644 index 0000000000000..37aead89c0c03 --- /dev/null +++ b/src/test/modules/test_regex/expected/test_regex_utf8_1.out @@ -0,0 +1,8 @@ +/* + * This test must be run in a database with UTF-8 encoding, + * because other encodings don't support all the characters used. + */ +SELECT getdatabaseencoding() <> 'UTF8' + AS skip_test \gset +\if :skip_test +\quit diff --git a/src/test/modules/test_regex/sql/test_regex.sql b/src/test/modules/test_regex/sql/test_regex.sql new file mode 100644 index 0000000000000..272dfc0cd6001 --- /dev/null +++ b/src/test/modules/test_regex/sql/test_regex.sql @@ -0,0 +1,1667 @@ +-- This file is based on tests/reg.test from the Tcl distribution, +-- which is marked +-- # Copyright (c) 1998, 1999 Henry Spencer. All rights reserved. +-- The full copyright notice can be found in src/backend/regex/COPYRIGHT. +-- Most commented lines below are copied from reg.test. Each +-- test case is followed by an equivalent test using test_regex(). + +create extension test_regex; + +set standard_conforming_strings = on; + +-- # support functions and preliminary misc. +-- # This is sensitive to changes in message wording, but we really have to +-- # test the code->message expansion at least once. +-- ::tcltest::test reg-0.1 "regexp error reporting" { +-- list [catch {regexp (*) ign} msg] $msg +-- } {1 {couldn't compile regular expression pattern: quantifier operand invalid}} +select * from test_regex('(*)', '', ''); + +-- doing 1 "basic sanity checks" + +-- expectMatch 1.1 & abc abc abc +select * from test_regex('abc', 'abc', ''); +select * from test_regex('abc', 'abc', 'b'); +-- expectNomatch 1.2 & abc def +select * from test_regex('abc', 'def', ''); +select * from test_regex('abc', 'def', 'b'); +-- expectMatch 1.3 & abc xyabxabce abc +select * from test_regex('abc', 'xyabxabce', ''); +select * from test_regex('abc', 'xyabxabce', 'b'); + +-- doing 2 "invalid option combinations" + +-- expectError 2.1 qe a INVARG +select * from test_regex('a', '', 'qe'); +-- expectError 2.2 qa a INVARG +select * from test_regex('a', '', 'qa'); +-- expectError 2.3 qx a INVARG +select * from test_regex('a', '', 'qx'); +-- expectError 2.4 qn a INVARG +select * from test_regex('a', '', 'qn'); +-- expectError 2.5 ba a INVARG +select * from test_regex('a', '', 'ba'); + +-- doing 3 "basic syntax" + +-- expectIndices 3.1 &NS "" a {0 -1} +select * from test_regex('', 'a', '0NS'); +select * from test_regex('', 'a', '0NSb'); +-- expectMatch 3.2 NS a| a a +select * from test_regex('a|', 'a', 'NS'); +-- expectMatch 3.3 - a|b a a +select * from test_regex('a|b', 'a', '-'); +-- expectMatch 3.4 - a|b b b +select * from test_regex('a|b', 'b', '-'); +-- expectMatch 3.5 NS a||b b b +select * from test_regex('a||b', 'b', 'NS'); +-- expectMatch 3.6 & ab ab ab +select * from test_regex('ab', 'ab', ''); +select * from test_regex('ab', 'ab', 'b'); + +-- doing 4 "parentheses" + +-- expectMatch 4.1 - (a)e ae ae a +select * from test_regex('(a)e', 'ae', '-'); +-- expectMatch 4.2 o (a)e ae +select * from test_regex('(a)e', 'ae', 'o'); +-- expectMatch 4.3 b {\(a\)b} ab ab a +select * from test_regex('\(a\)b', 'ab', 'b'); +-- expectMatch 4.4 - a((b)c) abc abc bc b +select * from test_regex('a((b)c)', 'abc', '-'); +-- expectMatch 4.5 - a(b)(c) abc abc b c +select * from test_regex('a(b)(c)', 'abc', '-'); +-- expectError 4.6 - a(b EPAREN +select * from test_regex('a(b', '', '-'); +-- expectError 4.7 b {a\(b} EPAREN +select * from test_regex('a\(b', '', 'b'); +-- # sigh, we blew it on the specs here... someday this will be fixed in POSIX, +-- # but meanwhile, it's fixed in AREs +-- expectMatch 4.8 eU a)b a)b a)b +select * from test_regex('a)b', 'a)b', 'eU'); +-- expectError 4.9 - a)b EPAREN +select * from test_regex('a)b', '', '-'); +-- expectError 4.10 b {a\)b} EPAREN +select * from test_regex('a\)b', '', 'b'); +-- expectMatch 4.11 P a(?:b)c abc abc +select * from test_regex('a(?:b)c', 'abc', 'P'); +-- expectError 4.12 e a(?:b)c BADRPT +select * from test_regex('a(?:b)c', '', 'e'); +-- expectIndices 4.13 S a()b ab {0 1} {1 0} +select * from test_regex('a()b', 'ab', '0S'); +-- expectMatch 4.14 SP a(?:)b ab ab +select * from test_regex('a(?:)b', 'ab', 'SP'); +-- expectIndices 4.15 S a(|b)c ac {0 1} {1 0} +select * from test_regex('a(|b)c', 'ac', '0S'); +-- expectMatch 4.16 S a(b|)c abc abc b +select * from test_regex('a(b|)c', 'abc', 'S'); + +-- doing 5 "simple one-char matching" +-- # general case of brackets done later + +-- expectMatch 5.1 & a.b axb axb +select * from test_regex('a.b', 'axb', ''); +select * from test_regex('a.b', 'axb', 'b'); +-- expectNomatch 5.2 &n "a.b" "a\nb" +select * from test_regex('a.b', E'a\nb', 'n'); +select * from test_regex('a.b', E'a\nb', 'nb'); +-- expectMatch 5.3 & {a[bc]d} abd abd +select * from test_regex('a[bc]d', 'abd', ''); +select * from test_regex('a[bc]d', 'abd', 'b'); +-- expectMatch 5.4 & {a[bc]d} acd acd +select * from test_regex('a[bc]d', 'acd', ''); +select * from test_regex('a[bc]d', 'acd', 'b'); +-- expectNomatch 5.5 & {a[bc]d} aed +select * from test_regex('a[bc]d', 'aed', ''); +select * from test_regex('a[bc]d', 'aed', 'b'); +-- expectNomatch 5.6 & {a[^bc]d} abd +select * from test_regex('a[^bc]d', 'abd', ''); +select * from test_regex('a[^bc]d', 'abd', 'b'); +-- expectMatch 5.7 & {a[^bc]d} aed aed +select * from test_regex('a[^bc]d', 'aed', ''); +select * from test_regex('a[^bc]d', 'aed', 'b'); +-- expectNomatch 5.8 &p "a\[^bc]d" "a\nd" +select * from test_regex('a[^bc]d', E'a\nd', 'p'); +select * from test_regex('a[^bc]d', E'a\nd', 'pb'); + +-- doing 6 "context-dependent syntax" +-- # plus odds and ends + +-- expectError 6.1 - * BADRPT +select * from test_regex('*', '', '-'); +-- expectMatch 6.2 b * * * +select * from test_regex('*', '*', 'b'); +-- expectMatch 6.3 b {\(*\)} * * * +select * from test_regex('\(*\)', '*', 'b'); +-- expectError 6.4 - (*) BADRPT +select * from test_regex('(*)', '', '-'); +-- expectMatch 6.5 b ^* * * +select * from test_regex('^*', '*', 'b'); +-- expectError 6.6 - ^* BADRPT +select * from test_regex('^*', '', '-'); +-- expectNomatch 6.7 & ^b ^b +select * from test_regex('^b', '^b', ''); +select * from test_regex('^b', '^b', 'b'); +-- expectMatch 6.8 b x^ x^ x^ +select * from test_regex('x^', 'x^', 'b'); +-- expectNomatch 6.9 I x^ x +select * from test_regex('x^', 'x', 'I'); +-- expectMatch 6.10 n "\n^" "x\nb" "\n" +select * from test_regex(E'\n^', E'x\nb', 'n'); +-- expectNomatch 6.11 bS {\(^b\)} ^b +select * from test_regex('\(^b\)', '^b', 'bS'); +-- expectMatch 6.12 - (^b) b b b +select * from test_regex('(^b)', 'b', '-'); +-- expectMatch 6.13 & {x$} x x +select * from test_regex('x$', 'x', ''); +select * from test_regex('x$', 'x', 'b'); +-- expectMatch 6.14 bS {\(x$\)} x x x +select * from test_regex('\(x$\)', 'x', 'bS'); +-- expectMatch 6.15 - {(x$)} x x x +select * from test_regex('(x$)', 'x', '-'); +-- expectMatch 6.16 b {x$y} "x\$y" "x\$y" +select * from test_regex('x$y', 'x$y', 'b'); +-- expectNomatch 6.17 I {x$y} xy +select * from test_regex('x$y', 'xy', 'I'); +-- expectMatch 6.18 n "x\$\n" "x\n" "x\n" +select * from test_regex(E'x$\n', E'x\n', 'n'); +-- expectError 6.19 - + BADRPT +select * from test_regex('+', '', '-'); +-- expectError 6.20 - ? BADRPT +select * from test_regex('?', '', '-'); + +-- These two are not yet incorporated in Tcl, cf +-- https://core.tcl-lang.org/tcl/artifact/106269fa65d96b83 +-- expectError 6.21 - {x(\w)(?=(\1))} ESUBREG +select * from test_regex('x(\w)(?=(\1))', '', '-'); +-- expectMatch 6.22 HP {x(?=((foo)))} xfoo x +select * from test_regex('x(?=((foo)))', 'xfoo', 'HP'); + +-- doing 7 "simple quantifiers" + +-- expectMatch 7.1 &N a* aa aa +select * from test_regex('a*', 'aa', 'N'); +select * from test_regex('a*', 'aa', 'Nb'); +-- expectIndices 7.2 &N a* b {0 -1} +select * from test_regex('a*', 'b', '0N'); +select * from test_regex('a*', 'b', '0Nb'); +-- expectMatch 7.3 - a+ aa aa +select * from test_regex('a+', 'aa', '-'); +-- expectMatch 7.4 - a?b ab ab +select * from test_regex('a?b', 'ab', '-'); +-- expectMatch 7.5 - a?b b b +select * from test_regex('a?b', 'b', '-'); +-- expectError 7.6 - ** BADRPT +select * from test_regex('**', '', '-'); +-- expectMatch 7.7 bN ** *** *** +select * from test_regex('**', '***', 'bN'); +-- expectError 7.8 & a** BADRPT +select * from test_regex('a**', '', ''); +select * from test_regex('a**', '', 'b'); +-- expectError 7.9 & a**b BADRPT +select * from test_regex('a**b', '', ''); +select * from test_regex('a**b', '', 'b'); +-- expectError 7.10 & *** BADRPT +select * from test_regex('***', '', ''); +select * from test_regex('***', '', 'b'); +-- expectError 7.11 - a++ BADRPT +select * from test_regex('a++', '', '-'); +-- expectError 7.12 - a?+ BADRPT +select * from test_regex('a?+', '', '-'); +-- expectError 7.13 - a?* BADRPT +select * from test_regex('a?*', '', '-'); +-- expectError 7.14 - a+* BADRPT +select * from test_regex('a+*', '', '-'); +-- expectError 7.15 - a*+ BADRPT +select * from test_regex('a*+', '', '-'); + +-- doing 8 "braces" + +-- expectMatch 8.1 NQ "a{0,1}" "" "" +select * from test_regex('a{0,1}', '', 'NQ'); +-- expectMatch 8.2 NQ "a{0,1}" ac a +select * from test_regex('a{0,1}', 'ac', 'NQ'); +-- expectError 8.3 - "a{1,0}" BADBR +select * from test_regex('a{1,0}', '', '-'); +-- expectError 8.4 - "a{1,2,3}" BADBR +select * from test_regex('a{1,2,3}', '', '-'); +-- expectError 8.5 - "a{257}" BADBR +select * from test_regex('a{257}', '', '-'); +-- expectError 8.6 - "a{1000}" BADBR +select * from test_regex('a{1000}', '', '-'); +-- expectError 8.7 - "a{1" EBRACE +select * from test_regex('a{1', '', '-'); +-- expectError 8.8 - "a{1n}" BADBR +select * from test_regex('a{1n}', '', '-'); +-- expectMatch 8.9 BS "a{b" "a\{b" "a\{b" +select * from test_regex('a{b', 'a{b', 'BS'); +-- expectMatch 8.10 BS "a{" "a\{" "a\{" +select * from test_regex('a{', 'a{', 'BS'); +-- expectMatch 8.11 bQ "a\\{0,1\\}b" cb b +select * from test_regex('a\{0,1\}b', 'cb', 'bQ'); +-- expectError 8.12 b "a\\{0,1" EBRACE +select * from test_regex('a\{0,1', '', 'b'); +-- expectError 8.13 - "a{0,1\\" BADBR +select * from test_regex('a{0,1\', '', '-'); +-- expectMatch 8.14 Q "a{0}b" ab b +select * from test_regex('a{0}b', 'ab', 'Q'); +-- expectMatch 8.15 Q "a{0,0}b" ab b +select * from test_regex('a{0,0}b', 'ab', 'Q'); +-- expectMatch 8.16 Q "a{0,1}b" ab ab +select * from test_regex('a{0,1}b', 'ab', 'Q'); +-- expectMatch 8.17 Q "a{0,2}b" b b +select * from test_regex('a{0,2}b', 'b', 'Q'); +-- expectMatch 8.18 Q "a{0,2}b" aab aab +select * from test_regex('a{0,2}b', 'aab', 'Q'); +-- expectMatch 8.19 Q "a{0,}b" aab aab +select * from test_regex('a{0,}b', 'aab', 'Q'); +-- expectMatch 8.20 Q "a{1,1}b" aab ab +select * from test_regex('a{1,1}b', 'aab', 'Q'); +-- expectMatch 8.21 Q "a{1,3}b" aaaab aaab +select * from test_regex('a{1,3}b', 'aaaab', 'Q'); +-- expectNomatch 8.22 Q "a{1,3}b" b +select * from test_regex('a{1,3}b', 'b', 'Q'); +-- expectMatch 8.23 Q "a{1,}b" aab aab +select * from test_regex('a{1,}b', 'aab', 'Q'); +-- expectNomatch 8.24 Q "a{2,3}b" ab +select * from test_regex('a{2,3}b', 'ab', 'Q'); +-- expectMatch 8.25 Q "a{2,3}b" aaaab aaab +select * from test_regex('a{2,3}b', 'aaaab', 'Q'); +-- expectNomatch 8.26 Q "a{2,}b" ab +select * from test_regex('a{2,}b', 'ab', 'Q'); +-- expectMatch 8.27 Q "a{2,}b" aaaab aaaab +select * from test_regex('a{2,}b', 'aaaab', 'Q'); + +-- doing 9 "brackets" + +-- expectMatch 9.1 & {a[bc]} ac ac +select * from test_regex('a[bc]', 'ac', ''); +select * from test_regex('a[bc]', 'ac', 'b'); +-- expectMatch 9.2 & {a[-]} a- a- +select * from test_regex('a[-]', 'a-', ''); +select * from test_regex('a[-]', 'a-', 'b'); +-- expectMatch 9.3 & {a[[.-.]]} a- a- +select * from test_regex('a[[.-.]]', 'a-', ''); +select * from test_regex('a[[.-.]]', 'a-', 'b'); +-- expectMatch 9.4 &L {a[[.zero.]]} a0 a0 +select * from test_regex('a[[.zero.]]', 'a0', 'L'); +select * from test_regex('a[[.zero.]]', 'a0', 'Lb'); +-- expectMatch 9.5 &LM {a[[.zero.]-9]} a2 a2 +select * from test_regex('a[[.zero.]-9]', 'a2', 'LM'); +select * from test_regex('a[[.zero.]-9]', 'a2', 'LMb'); +-- expectMatch 9.6 &M {a[0-[.9.]]} a2 a2 +select * from test_regex('a[0-[.9.]]', 'a2', 'M'); +select * from test_regex('a[0-[.9.]]', 'a2', 'Mb'); +-- expectMatch 9.7 &+L {a[[=x=]]} ax ax +select * from test_regex('a[[=x=]]', 'ax', '+L'); +select * from test_regex('a[[=x=]]', 'ax', '+Lb'); +-- expectMatch 9.8 &+L {a[[=x=]]} ay ay +select * from test_regex('a[[=x=]]', 'ay', '+L'); +select * from test_regex('a[[=x=]]', 'ay', '+Lb'); +-- expectNomatch 9.9 &+L {a[[=x=]]} az +select * from test_regex('a[[=x=]]', 'az', '+L'); +select * from test_regex('a[[=x=]]', 'az', '+Lb'); +-- expectError 9.10 & {a[0-[=x=]]} ERANGE +select * from test_regex('a[0-[=x=]]', '', ''); +select * from test_regex('a[0-[=x=]]', '', 'b'); +-- expectMatch 9.11 &L {a[[:digit:]]} a0 a0 +select * from test_regex('a[[:digit:]]', 'a0', 'L'); +select * from test_regex('a[[:digit:]]', 'a0', 'Lb'); +-- expectError 9.12 & {a[[:woopsie:]]} ECTYPE +select * from test_regex('a[[:woopsie:]]', '', ''); +select * from test_regex('a[[:woopsie:]]', '', 'b'); +-- expectNomatch 9.13 &L {a[[:digit:]]} ab +select * from test_regex('a[[:digit:]]', 'ab', 'L'); +select * from test_regex('a[[:digit:]]', 'ab', 'Lb'); +-- expectError 9.14 & {a[0-[:digit:]]} ERANGE +select * from test_regex('a[0-[:digit:]]', '', ''); +select * from test_regex('a[0-[:digit:]]', '', 'b'); +-- expectMatch 9.15 &LP {[[:<:]]a} a a +select * from test_regex('[[:<:]]a', 'a', 'LP'); +select * from test_regex('[[:<:]]a', 'a', 'LPb'); +-- expectMatch 9.16 &LP {a[[:>:]]} a a +select * from test_regex('a[[:>:]]', 'a', 'LP'); +select * from test_regex('a[[:>:]]', 'a', 'LPb'); +-- expectError 9.17 & {a[[..]]b} ECOLLATE +select * from test_regex('a[[..]]b', '', ''); +select * from test_regex('a[[..]]b', '', 'b'); +-- expectError 9.18 & {a[[==]]b} ECOLLATE +select * from test_regex('a[[==]]b', '', ''); +select * from test_regex('a[[==]]b', '', 'b'); +-- expectError 9.19 & {a[[::]]b} ECTYPE +select * from test_regex('a[[::]]b', '', ''); +select * from test_regex('a[[::]]b', '', 'b'); +-- expectError 9.20 & {a[[.a} EBRACK +select * from test_regex('a[[.a', '', ''); +select * from test_regex('a[[.a', '', 'b'); +-- expectError 9.21 & {a[[=a} EBRACK +select * from test_regex('a[[=a', '', ''); +select * from test_regex('a[[=a', '', 'b'); +-- expectError 9.22 & {a[[:a} EBRACK +select * from test_regex('a[[:a', '', ''); +select * from test_regex('a[[:a', '', 'b'); +-- expectError 9.23 & {a[} EBRACK +select * from test_regex('a[', '', ''); +select * from test_regex('a[', '', 'b'); +-- expectError 9.24 & {a[b} EBRACK +select * from test_regex('a[b', '', ''); +select * from test_regex('a[b', '', 'b'); +-- expectError 9.25 & {a[b-} EBRACK +select * from test_regex('a[b-', '', ''); +select * from test_regex('a[b-', '', 'b'); +-- expectError 9.26 & {a[b-c} EBRACK +select * from test_regex('a[b-c', '', ''); +select * from test_regex('a[b-c', '', 'b'); +-- expectMatch 9.27 &M {a[b-c]} ab ab +select * from test_regex('a[b-c]', 'ab', 'M'); +select * from test_regex('a[b-c]', 'ab', 'Mb'); +-- expectMatch 9.28 & {a[b-b]} ab ab +select * from test_regex('a[b-b]', 'ab', ''); +select * from test_regex('a[b-b]', 'ab', 'b'); +-- expectMatch 9.29 &M {a[1-2]} a2 a2 +select * from test_regex('a[1-2]', 'a2', 'M'); +select * from test_regex('a[1-2]', 'a2', 'Mb'); +-- expectError 9.30 & {a[c-b]} ERANGE +select * from test_regex('a[c-b]', '', ''); +select * from test_regex('a[c-b]', '', 'b'); +-- expectError 9.31 & {a[a-b-c]} ERANGE +select * from test_regex('a[a-b-c]', '', ''); +select * from test_regex('a[a-b-c]', '', 'b'); +-- expectMatch 9.32 &M {a[--?]b} a?b a?b +select * from test_regex('a[--?]b', 'a?b', 'M'); +select * from test_regex('a[--?]b', 'a?b', 'Mb'); +-- expectMatch 9.33 & {a[---]b} a-b a-b +select * from test_regex('a[---]b', 'a-b', ''); +select * from test_regex('a[---]b', 'a-b', 'b'); +-- expectMatch 9.34 & {a[]b]c} a]c a]c +select * from test_regex('a[]b]c', 'a]c', ''); +select * from test_regex('a[]b]c', 'a]c', 'b'); +-- expectMatch 9.35 EP {a[\]]b} a]b a]b +select * from test_regex('a[\]]b', 'a]b', 'EP'); +-- expectNomatch 9.36 bE {a[\]]b} a]b +select * from test_regex('a[\]]b', 'a]b', 'bE'); +-- expectMatch 9.37 bE {a[\]]b} "a\\]b" "a\\]b" +select * from test_regex('a[\]]b', 'a\]b', 'bE'); +-- expectMatch 9.38 eE {a[\]]b} "a\\]b" "a\\]b" +select * from test_regex('a[\]]b', 'a\]b', 'eE'); +-- expectMatch 9.39 EP {a[\\]b} "a\\b" "a\\b" +select * from test_regex('a[\\]b', 'a\b', 'EP'); +-- expectMatch 9.40 eE {a[\\]b} "a\\b" "a\\b" +select * from test_regex('a[\\]b', 'a\b', 'eE'); +-- expectMatch 9.41 bE {a[\\]b} "a\\b" "a\\b" +select * from test_regex('a[\\]b', 'a\b', 'bE'); +-- expectError 9.42 - {a[\Z]b} EESCAPE +select * from test_regex('a[\Z]b', '', '-'); +-- expectMatch 9.43 & {a[[b]c} "a\[c" "a\[c" +select * from test_regex('a[[b]c', 'a[c', ''); +select * from test_regex('a[[b]c', 'a[c', 'b'); +-- This only works in UTF8 encoding, so it's moved to test_regex_utf8.sql: +-- expectMatch 9.44 EMP* {a[\u00fe-\u0507][\u00ff-\u0300]b} \ +-- "a\u0102\u02ffb" "a\u0102\u02ffb" + +-- doing 10 "anchors and newlines" + +-- expectMatch 10.1 & ^a a a +select * from test_regex('^a', 'a', ''); +select * from test_regex('^a', 'a', 'b'); +-- expectNomatch 10.2 &^ ^a a +select * from test_regex('^a', 'a', '^'); +select * from test_regex('^a', 'a', '^b'); +-- expectIndices 10.3 &N ^ a {0 -1} +select * from test_regex('^', 'a', '0N'); +select * from test_regex('^', 'a', '0Nb'); +-- expectIndices 10.4 & {a$} aba {2 2} +select * from test_regex('a$', 'aba', '0'); +select * from test_regex('a$', 'aba', '0b'); +-- expectNomatch 10.5 {&$} {a$} a +select * from test_regex('a$', 'a', '$'); +select * from test_regex('a$', 'a', '$b'); +-- expectIndices 10.6 &N {$} ab {2 1} +select * from test_regex('$', 'ab', '0N'); +select * from test_regex('$', 'ab', '0Nb'); +-- expectMatch 10.7 &n ^a a a +select * from test_regex('^a', 'a', 'n'); +select * from test_regex('^a', 'a', 'nb'); +-- expectMatch 10.8 &n "^a" "b\na" "a" +select * from test_regex('^a', E'b\na', 'n'); +select * from test_regex('^a', E'b\na', 'nb'); +-- expectIndices 10.9 &w "^a" "a\na" {0 0} +select * from test_regex('^a', E'a\na', '0w'); +select * from test_regex('^a', E'a\na', '0wb'); +-- expectIndices 10.10 &n^ "^a" "a\na" {2 2} +select * from test_regex('^a', E'a\na', '0n^'); +select * from test_regex('^a', E'a\na', '0n^b'); +-- expectMatch 10.11 &n {a$} a a +select * from test_regex('a$', 'a', 'n'); +select * from test_regex('a$', 'a', 'nb'); +-- expectMatch 10.12 &n "a\$" "a\nb" "a" +select * from test_regex('a$', E'a\nb', 'n'); +select * from test_regex('a$', E'a\nb', 'nb'); +-- expectIndices 10.13 &n "a\$" "a\na" {0 0} +select * from test_regex('a$', E'a\na', '0n'); +select * from test_regex('a$', E'a\na', '0nb'); +-- expectIndices 10.14 N ^^ a {0 -1} +select * from test_regex('^^', 'a', '0N'); +-- expectMatch 10.15 b ^^ ^ ^ +select * from test_regex('^^', '^', 'b'); +-- expectIndices 10.16 N {$$} a {1 0} +select * from test_regex('$$', 'a', '0N'); +-- expectMatch 10.17 b {$$} "\$" "\$" +select * from test_regex('$$', '$', 'b'); +-- expectMatch 10.18 &N {^$} "" "" +select * from test_regex('^$', '', 'N'); +select * from test_regex('^$', '', 'Nb'); +-- expectNomatch 10.19 &N {^$} a +select * from test_regex('^$', 'a', 'N'); +select * from test_regex('^$', 'a', 'Nb'); +-- expectIndices 10.20 &nN "^\$" a\n\nb {2 1} +select * from test_regex('^$', E'a\n\nb', '0nN'); +select * from test_regex('^$', E'a\n\nb', '0nNb'); +-- expectMatch 10.21 N {$^} "" "" +select * from test_regex('$^', '', 'N'); +-- expectMatch 10.22 b {$^} "\$^" "\$^" +select * from test_regex('$^', '$^', 'b'); +-- expectMatch 10.23 P {\Aa} a a +select * from test_regex('\Aa', 'a', 'P'); +-- expectMatch 10.24 ^P {\Aa} a a +select * from test_regex('\Aa', 'a', '^P'); +-- expectNomatch 10.25 ^nP {\Aa} "b\na" +select * from test_regex('\Aa', E'b\na', '^nP'); +-- expectMatch 10.26 P {a\Z} a a +select * from test_regex('a\Z', 'a', 'P'); +-- expectMatch 10.27 \$P {a\Z} a a +select * from test_regex('a\Z', 'a', '$P'); +-- expectNomatch 10.28 \$nP {a\Z} "a\nb" +select * from test_regex('a\Z', E'a\nb', '$nP'); +-- expectError 10.29 - ^* BADRPT +select * from test_regex('^*', '', '-'); +-- expectError 10.30 - {$*} BADRPT +select * from test_regex('$*', '', '-'); +-- expectError 10.31 - {\A*} BADRPT +select * from test_regex('\A*', '', '-'); +-- expectError 10.32 - {\Z*} BADRPT +select * from test_regex('\Z*', '', '-'); + +-- doing 11 "boundary constraints" + +-- expectMatch 11.1 &LP {[[:<:]]a} a a +select * from test_regex('[[:<:]]a', 'a', 'LP'); +select * from test_regex('[[:<:]]a', 'a', 'LPb'); +-- expectMatch 11.2 &LP {[[:<:]]a} -a a +select * from test_regex('[[:<:]]a', '-a', 'LP'); +select * from test_regex('[[:<:]]a', '-a', 'LPb'); +-- expectNomatch 11.3 &LP {[[:<:]]a} ba +select * from test_regex('[[:<:]]a', 'ba', 'LP'); +select * from test_regex('[[:<:]]a', 'ba', 'LPb'); +-- expectMatch 11.4 &LP {a[[:>:]]} a a +select * from test_regex('a[[:>:]]', 'a', 'LP'); +select * from test_regex('a[[:>:]]', 'a', 'LPb'); +-- expectMatch 11.5 &LP {a[[:>:]]} a- a +select * from test_regex('a[[:>:]]', 'a-', 'LP'); +select * from test_regex('a[[:>:]]', 'a-', 'LPb'); +-- expectNomatch 11.6 &LP {a[[:>:]]} ab +select * from test_regex('a[[:>:]]', 'ab', 'LP'); +select * from test_regex('a[[:>:]]', 'ab', 'LPb'); +-- expectMatch 11.7 bLP {\} a a +select * from test_regex('a\>', 'a', 'bLP'); +-- expectNomatch 11.10 bLP {a\>} ab +select * from test_regex('a\>', 'ab', 'bLP'); +-- expectMatch 11.11 LP {\ya} a a +select * from test_regex('\ya', 'a', 'LP'); +-- expectNomatch 11.12 LP {\ya} ba +select * from test_regex('\ya', 'ba', 'LP'); +-- expectMatch 11.13 LP {a\y} a a +select * from test_regex('a\y', 'a', 'LP'); +-- expectNomatch 11.14 LP {a\y} ab +select * from test_regex('a\y', 'ab', 'LP'); +-- expectMatch 11.15 LP {a\Y} ab a +select * from test_regex('a\Y', 'ab', 'LP'); +-- expectNomatch 11.16 LP {a\Y} a- +select * from test_regex('a\Y', 'a-', 'LP'); +-- expectNomatch 11.17 LP {a\Y} a +select * from test_regex('a\Y', 'a', 'LP'); +-- expectNomatch 11.18 LP {-\Y} -a +select * from test_regex('-\Y', '-a', 'LP'); +-- expectMatch 11.19 LP {-\Y} -% - +select * from test_regex('-\Y', '-%', 'LP'); +-- expectNomatch 11.20 LP {\Y-} a- +select * from test_regex('\Y-', 'a-', 'LP'); +-- expectError 11.21 - {[[:<:]]*} BADRPT +select * from test_regex('[[:<:]]*', '', '-'); +-- expectError 11.22 - {[[:>:]]*} BADRPT +select * from test_regex('[[:>:]]*', '', '-'); +-- expectError 11.23 b {\<*} BADRPT +select * from test_regex('\<*', '', 'b'); +-- expectError 11.24 b {\>*} BADRPT +select * from test_regex('\>*', '', 'b'); +-- expectError 11.25 - {\y*} BADRPT +select * from test_regex('\y*', '', '-'); +-- expectError 11.26 - {\Y*} BADRPT +select * from test_regex('\Y*', '', '-'); +-- expectMatch 11.27 LP {\ma} a a +select * from test_regex('\ma', 'a', 'LP'); +-- expectNomatch 11.28 LP {\ma} ba +select * from test_regex('\ma', 'ba', 'LP'); +-- expectMatch 11.29 LP {a\M} a a +select * from test_regex('a\M', 'a', 'LP'); +-- expectNomatch 11.30 LP {a\M} ab +select * from test_regex('a\M', 'ab', 'LP'); +-- expectNomatch 11.31 ILP {\Ma} a +select * from test_regex('\Ma', 'a', 'ILP'); +-- expectNomatch 11.32 ILP {a\m} a +select * from test_regex('a\m', 'a', 'ILP'); + +-- doing 12 "character classes" + +-- expectMatch 12.1 LP {a\db} a0b a0b +select * from test_regex('a\db', 'a0b', 'LP'); +-- expectNomatch 12.2 LP {a\db} axb +select * from test_regex('a\db', 'axb', 'LP'); +-- expectNomatch 12.3 LP {a\Db} a0b +select * from test_regex('a\Db', 'a0b', 'LP'); +-- expectMatch 12.4 LP {a\Db} axb axb +select * from test_regex('a\Db', 'axb', 'LP'); +-- expectMatch 12.5 LP "a\\sb" "a b" "a b" +select * from test_regex('a\sb', 'a b', 'LP'); +-- expectMatch 12.6 LP "a\\sb" "a\tb" "a\tb" +select * from test_regex('a\sb', E'a\tb', 'LP'); +-- expectMatch 12.7 LP "a\\sb" "a\nb" "a\nb" +select * from test_regex('a\sb', E'a\nb', 'LP'); +-- expectNomatch 12.8 LP {a\sb} axb +select * from test_regex('a\sb', 'axb', 'LP'); +-- expectMatch 12.9 LP {a\Sb} axb axb +select * from test_regex('a\Sb', 'axb', 'LP'); +-- expectNomatch 12.10 LP "a\\Sb" "a b" +select * from test_regex('a\Sb', 'a b', 'LP'); +-- expectMatch 12.11 LP {a\wb} axb axb +select * from test_regex('a\wb', 'axb', 'LP'); +-- expectNomatch 12.12 LP {a\wb} a-b +select * from test_regex('a\wb', 'a-b', 'LP'); +-- expectNomatch 12.13 LP {a\Wb} axb +select * from test_regex('a\Wb', 'axb', 'LP'); +-- expectMatch 12.14 LP {a\Wb} a-b a-b +select * from test_regex('a\Wb', 'a-b', 'LP'); +-- expectMatch 12.15 LP {\y\w+z\y} adze-guz guz +select * from test_regex('\y\w+z\y', 'adze-guz', 'LP'); +-- expectMatch 12.16 LPE {a[\d]b} a1b a1b +select * from test_regex('a[\d]b', 'a1b', 'LPE'); +-- expectMatch 12.17 LPE "a\[\\s]b" "a b" "a b" +select * from test_regex('a[\s]b', 'a b', 'LPE'); +-- expectMatch 12.18 LPE {a[\w]b} axb axb +select * from test_regex('a[\w]b', 'axb', 'LPE'); + +-- doing 13 "escapes" + +-- expectError 13.1 & "a\\" EESCAPE +select * from test_regex('a\', '', ''); +select * from test_regex('a\', '', 'b'); +-- expectMatch 13.2 - {a\]+)>} a +-- } 1 +select * from test_regex('\A\s*[^<]*\s*<([^>]+)>', 'a', 'LP'); + +-- test reg-33.4 {Bug 505048} { +-- regexp {\A\s*([^b]*)b} ab +-- } 1 +select * from test_regex('\A\s*([^b]*)b', 'ab', 'LP'); + +-- test reg-33.5 {Bug 505048} { +-- regexp {\A\s*[^b]*(b)} ab +-- } 1 +select * from test_regex('\A\s*[^b]*(b)', 'ab', 'LP'); + +-- test reg-33.6 {Bug 505048} { +-- regexp {\A(\s*)[^b]*(b)} ab +-- } 1 +select * from test_regex('\A(\s*)[^b]*(b)', 'ab', 'LP'); + +-- test reg-33.7 {Bug 505048} { +-- regexp {\A\s*[^b]*b} ab +-- } 1 +select * from test_regex('\A\s*[^b]*b', 'ab', 'LP'); + +-- test reg-33.8 {Bug 505048} { +-- regexp -inline {\A\s*[^b]*b} ab +-- } ab +select * from test_regex('\A\s*[^b]*b', 'ab', 'LP'); + +-- test reg-33.9 {Bug 505048} { +-- regexp -indices -inline {\A\s*[^b]*b} ab +-- } {{0 1}} +select * from test_regex('\A\s*[^b]*b', 'ab', '0LP'); + +-- test reg-33.10 {Bug 840258} -body { +-- regsub {(^|\n)+\.*b} \n.b {} tmp +-- } -cleanup { +-- unset tmp +-- } -result 1 +select * from test_regex('(^|\n)+\.*b', E'\n.b', 'P'); + +-- test reg-33.11 {Bug 840258} -body { +-- regsub {(^|[\n\r]+)\.*\?<.*?(\n|\r)+} \ +-- "TQ\r\n.?<5000267>Test already stopped\r\n" {} tmp +-- } -cleanup { +-- unset tmp +-- } -result 1 +select * from test_regex('(^|[\n\r]+)\.*\?<.*?(\n|\r)+', E'TQ\r\n.?<5000267>Test already stopped\r\n', 'EP'); + +-- test reg-33.12 {Bug 1810264 - bad read} { +-- regexp {\3161573148} {\3161573148} +-- } 0 +select * from test_regex('\3161573148', '\3161573148', 'MP'); + +-- test reg-33.13 {Bug 1810264 - infinite loop} { +-- regexp {($|^)*} {x} +-- } 1 +select * from test_regex('($|^)*', 'x', 'N'); + +-- # Some environments have small default stack sizes. [Bug 1905562] +-- test reg-33.14 {Bug 1810264 - super-expensive expression} nonPortable { +-- regexp {(x{200}){200}$y} {x} +-- } 0 +-- This might or might not work depending on platform, so skip it +-- select * from test_regex('(x{200}){200}$y', 'x', 'IQ'); + +-- test reg-33.15.1 {Bug 3603557 - an "in the wild" RE} { +-- lindex [regexp -expanded -about { +-- ^TETRA_MODE_CMD # Message Type +-- ([[:blank:]]+) # Pad +-- (ETS_1_1|ETS_1_2|ETS_2_2) # SystemCode +-- ([[:blank:]]+) # Pad +-- (CONTINUOUS|CARRIER|MCCH|TRAFFIC) # SharingMode +-- ([[:blank:]]+) # Pad +-- ([[:digit:]]{1,2}) # ColourCode +-- ([[:blank:]]+) # Pad +-- (1|2|3|4|6|9|12|18) # TSReservedFrames +-- ([[:blank:]]+) # Pad +-- (PASS|TRUE|FAIL|FALSE) # UPlaneDTX +-- ([[:blank:]]+) # Pad +-- (PASS|TRUE|FAIL|FALSE) # Frame18Extension +-- ([[:blank:]]+) # Pad +-- ([[:digit:]]{1,4}) # MCC +-- ([[:blank:]]+) # Pad +-- ([[:digit:]]{1,5}) # MNC +-- ([[:blank:]]+) # Pad +-- (BOTH|BCAST|ENQRY|NONE) # NbrCellBcast +-- ([[:blank:]]+) # Pad +-- (UNKNOWN|LOW|MEDIUM|HIGH) # CellServiceLevel +-- ([[:blank:]]+) # Pad +-- (PASS|TRUE|FAIL|FALSE) # LateEntryInfo +-- ([[:blank:]]+) # Pad +-- (300|400) # FrequencyBand +-- ([[:blank:]]+) # Pad +-- (NORMAL|REVERSE) # ReverseOperation +-- ([[:blank:]]+) # Pad +-- (NONE|\+6\.25|\-6\.25|\+12\.5) # Offset +-- ([[:blank:]]+) # Pad +-- (10) # DuplexSpacing +-- ([[:blank:]]+) # Pad +-- ([[:digit:]]{1,4}) # MainCarrierNr +-- ([[:blank:]]+) # Pad +-- (0|1|2|3) # NrCSCCH +-- ([[:blank:]]+) # Pad +-- (15|20|25|30|35|40|45) # MSTxPwrMax +-- ([[:blank:]]+) # Pad +-- (\-125|\-120|\-115|\-110|\-105|\-100|\-95|\-90|\-85|\-80|\-75|\-70|\-65|\-60|\-55|\-50) +-- # RxLevAccessMin +-- ([[:blank:]]+) # Pad +-- (\-53|\-51|\-49|\-47|\-45|\-43|\-41|\-39|\-37|\-35|\-33|\-31|\-29|\-27|\-25|\-23) +-- # AccessParameter +-- ([[:blank:]]+) # Pad +-- (DISABLE|[[:digit:]]{3,4}) # RadioDLTimeout +-- ([[:blank:]]+) # Pad +-- (\-[[:digit:]]{2,3}) # RSSIThreshold +-- ([[:blank:]]+) # Pad +-- ([[:digit:]]{1,5}) # CCKIdSCKVerNr +-- ([[:blank:]]+) # Pad +-- ([[:digit:]]{1,5}) # LocationArea +-- ([[:blank:]]+) # Pad +-- ([(1|0)]{16}) # SubscriberClass +-- ([[:blank:]]+) # Pad +-- ([(1|0)]{12}) # BSServiceDetails +-- ([[:blank:]]+) # Pad +-- (RANDOMIZE|IMMEDIATE|[[:digit:]]{1,2}) # IMM +-- ([[:blank:]]+) # Pad +-- ([[:digit:]]{1,2}) # WT +-- ([[:blank:]]+) # Pad +-- ([[:digit:]]{1,2}) # Nu +-- ([[:blank:]]+) # Pad +-- ([0-1]) # FrameLngFctr +-- ([[:blank:]]+) # Pad +-- ([[:digit:]]{1,2}) # TSPtr +-- ([[:blank:]]+) # Pad +-- ([0-7]) # MinPriority +-- ([[:blank:]]+) # Pad +-- (PASS|TRUE|FAIL|FALSE) # ExtdSrvcsEnabled +-- ([[:blank:]]+) # Pad +-- (.*) # ConditionalFields +-- }] 0 +-- } 68 +select * from test_regex($$ + ^TETRA_MODE_CMD # Message Type + ([[:blank:]]+) # Pad + (ETS_1_1|ETS_1_2|ETS_2_2) # SystemCode + ([[:blank:]]+) # Pad + (CONTINUOUS|CARRIER|MCCH|TRAFFIC) # SharingMode + ([[:blank:]]+) # Pad + ([[:digit:]]{1,2}) # ColourCode + ([[:blank:]]+) # Pad + (1|2|3|4|6|9|12|18) # TSReservedFrames + ([[:blank:]]+) # Pad + (PASS|TRUE|FAIL|FALSE) # UPlaneDTX + ([[:blank:]]+) # Pad + (PASS|TRUE|FAIL|FALSE) # Frame18Extension + ([[:blank:]]+) # Pad + ([[:digit:]]{1,4}) # MCC + ([[:blank:]]+) # Pad + ([[:digit:]]{1,5}) # MNC + ([[:blank:]]+) # Pad + (BOTH|BCAST|ENQRY|NONE) # NbrCellBcast + ([[:blank:]]+) # Pad + (UNKNOWN|LOW|MEDIUM|HIGH) # CellServiceLevel + ([[:blank:]]+) # Pad + (PASS|TRUE|FAIL|FALSE) # LateEntryInfo + ([[:blank:]]+) # Pad + (300|400) # FrequencyBand + ([[:blank:]]+) # Pad + (NORMAL|REVERSE) # ReverseOperation + ([[:blank:]]+) # Pad + (NONE|\+6\.25|\-6\.25|\+12\.5) # Offset + ([[:blank:]]+) # Pad + (10) # DuplexSpacing + ([[:blank:]]+) # Pad + ([[:digit:]]{1,4}) # MainCarrierNr + ([[:blank:]]+) # Pad + (0|1|2|3) # NrCSCCH + ([[:blank:]]+) # Pad + (15|20|25|30|35|40|45) # MSTxPwrMax + ([[:blank:]]+) # Pad + (\-125|\-120|\-115|\-110|\-105|\-100|\-95|\-90|\-85|\-80|\-75|\-70|\-65|\-60|\-55|\-50) + # RxLevAccessMin + ([[:blank:]]+) # Pad + (\-53|\-51|\-49|\-47|\-45|\-43|\-41|\-39|\-37|\-35|\-33|\-31|\-29|\-27|\-25|\-23) + # AccessParameter + ([[:blank:]]+) # Pad + (DISABLE|[[:digit:]]{3,4}) # RadioDLTimeout + ([[:blank:]]+) # Pad + (\-[[:digit:]]{2,3}) # RSSIThreshold + ([[:blank:]]+) # Pad + ([[:digit:]]{1,5}) # CCKIdSCKVerNr + ([[:blank:]]+) # Pad + ([[:digit:]]{1,5}) # LocationArea + ([[:blank:]]+) # Pad + ([(1|0)]{16}) # SubscriberClass + ([[:blank:]]+) # Pad + ([(1|0)]{12}) # BSServiceDetails + ([[:blank:]]+) # Pad + (RANDOMIZE|IMMEDIATE|[[:digit:]]{1,2}) # IMM + ([[:blank:]]+) # Pad + ([[:digit:]]{1,2}) # WT + ([[:blank:]]+) # Pad + ([[:digit:]]{1,2}) # Nu + ([[:blank:]]+) # Pad + ([0-1]) # FrameLngFctr + ([[:blank:]]+) # Pad + ([[:digit:]]{1,2}) # TSPtr + ([[:blank:]]+) # Pad + ([0-7]) # MinPriority + ([[:blank:]]+) # Pad + (PASS|TRUE|FAIL|FALSE) # ExtdSrvcsEnabled + ([[:blank:]]+) # Pad + (.*) # ConditionalFields + $$, '', 'xLMPQ'); + +-- test reg-33.16.1 {Bug [8d2c0da36d]- another "in the wild" RE} { +-- lindex [regexp -about "^MRK:client1: =1339 14HKelly Talisman 10011000 (\[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]*) \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* 8 0 8 0 0 0 77 77 1 1 2 0 11 { 1 3 8 \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* 00000000 1 13HC6 My Creator 2 3 8 \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* 00000000 1 31HC7 Slightly offensive name, huh 3 8 8 \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* 00000000 1 23HE-mail:kelly@hotbox.com 4 9 8 \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* 00000000 1 17Hcompface must die 5 10 8 \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* 00000000 0 3HAir 6 12 8 \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* 00000000 1 14HPGP public key 7 13 8 \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* 00000000 1 16Hkelly@hotbox.com 8 30 8 \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* 00000000 0 12H2 text/plain 9 30 8 \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* 00000000 0 13H2 x-kom/basic 10 33 8 \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* 00000000 1 1H0 11 14 8 \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* \[0-9\]* 00000000 1 1H3 }\r?"] 0 +-- } 1 +select * from test_regex(E'^MRK:client1: =1339 14HKelly Talisman 10011000 ([0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]*) [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* 8 0 8 0 0 0 77 77 1 1 2 0 11 { 1 3 8 [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* 00000000 1 13HC6 My Creator 2 3 8 [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* 00000000 1 31HC7 Slightly offensive name, huh 3 8 8 [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* 00000000 1 23HE-mail:kelly@hotbox.com 4 9 8 [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* 00000000 1 17Hcompface must die 5 10 8 [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* 00000000 0 3HAir 6 12 8 [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* 00000000 1 14HPGP public key 7 13 8 [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* 00000000 1 16Hkelly@hotbox.com 8 30 8 [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* 00000000 0 12H2 text/plain 9 30 8 [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* 00000000 0 13H2 x-kom/basic 10 33 8 [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* 00000000 1 1H0 11 14 8 [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* [0-9]* 00000000 1 1H3 }\r?', '', 'BMS'); + +-- test reg-33.15 {constraint fixes} { +-- regexp {(^)+^} x +-- } 1 +select * from test_regex('(^)+^', 'x', 'N'); + +-- test reg-33.16 {constraint fixes} { +-- regexp {($^)+} x +-- } 0 +select * from test_regex('($^)+', 'x', 'N'); + +-- test reg-33.17 {constraint fixes} { +-- regexp {(^$)*} x +-- } 1 +select * from test_regex('(^$)*', 'x', 'N'); + +-- test reg-33.18 {constraint fixes} { +-- regexp {(^(?!aa))+} {aa bb cc} +-- } 0 +select * from test_regex('(^(?!aa))+', 'aa bb cc', 'HP'); + +-- test reg-33.19 {constraint fixes} { +-- regexp {(^(?!aa)(?!bb)(?!cc))+} {aa x} +-- } 0 +select * from test_regex('(^(?!aa)(?!bb)(?!cc))+', 'aa x', 'HP'); + +-- test reg-33.20 {constraint fixes} { +-- regexp {(^(?!aa)(?!bb)(?!cc))+} {bb x} +-- } 0 +select * from test_regex('(^(?!aa)(?!bb)(?!cc))+', 'bb x', 'HP'); + +-- test reg-33.21 {constraint fixes} { +-- regexp {(^(?!aa)(?!bb)(?!cc))+} {cc x} +-- } 0 +select * from test_regex('(^(?!aa)(?!bb)(?!cc))+', 'cc x', 'HP'); + +-- test reg-33.22 {constraint fixes} { +-- regexp {(^(?!aa)(?!bb)(?!cc))+} {dd x} +-- } 1 +select * from test_regex('(^(?!aa)(?!bb)(?!cc))+', 'dd x', 'HP'); + +-- test reg-33.23 {} { +-- regexp {abcd(\m)+xyz} x +-- } 0 +select * from test_regex('abcd(\m)+xyz', 'x', 'ILP'); + +-- test reg-33.24 {} { +-- regexp {abcd(\m)+xyz} a +-- } 0 +select * from test_regex('abcd(\m)+xyz', 'a', 'ILP'); + +-- test reg-33.25 {} { +-- regexp {^abcd*(((((^(a c(e?d)a+|)+|)+|)+|)+|a)+|)} x +-- } 0 +select * from test_regex('^abcd*(((((^(a c(e?d)a+|)+|)+|)+|)+|a)+|)', 'x', 'S'); + +-- test reg-33.26 {} { +-- regexp {a^(^)bcd*xy(((((($a+|)+|)+|)+$|)+|)+|)^$} x +-- } 0 +select * from test_regex('a^(^)bcd*xy(((((($a+|)+|)+|)+$|)+|)+|)^$', 'x', 'IS'); + +-- test reg-33.27 {} { +-- regexp {xyz(\Y\Y)+} x +-- } 0 +select * from test_regex('xyz(\Y\Y)+', 'x', 'LP'); + +-- test reg-33.28 {} { +-- regexp {x|(?:\M)+} x +-- } 1 +select * from test_regex('x|(?:\M)+', 'x', 'LNP'); + +-- test reg-33.29 {} { +-- # This is near the limits of the RE engine +-- regexp [string repeat x*y*z* 480] x +-- } 1 +-- The runtime cost of this seems out of proportion to the value, +-- so for Postgres purposes reduce the repeat to 200x +select * from test_regex(repeat('x*y*z*', 200), 'x', 'N'); + +-- test reg-33.30 {Bug 1080042} { +-- regexp {(\Y)+} foo +-- } 1 +select * from test_regex('(\Y)+', 'foo', 'LNP'); diff --git a/src/test/modules/test_regex/sql/test_regex_utf8.sql b/src/test/modules/test_regex/sql/test_regex_utf8.sql new file mode 100644 index 0000000000000..cfd9396194fee --- /dev/null +++ b/src/test/modules/test_regex/sql/test_regex_utf8.sql @@ -0,0 +1,60 @@ +/* + * This test must be run in a database with UTF-8 encoding, + * because other encodings don't support all the characters used. + */ + +SELECT getdatabaseencoding() <> 'UTF8' + AS skip_test \gset +\if :skip_test +\quit +\endif + +set client_encoding = utf8; + +set standard_conforming_strings = on; + + +-- Run the Tcl test cases that require Unicode + +-- expectMatch 9.44 EMP* {a[\u00fe-\u0507][\u00ff-\u0300]b} \ +-- "a\u0102\u02ffb" "a\u0102\u02ffb" +select * from test_regex('a[\u00fe-\u0507][\u00ff-\u0300]b', E'a\u0102\u02ffb', 'EMP*'); + +-- expectMatch 13.27 P "a\\U00001234x" "a\u1234x" "a\u1234x" +select * from test_regex('a\U00001234x', E'a\u1234x', 'P'); +-- expectMatch 13.28 P {a\U00001234x} "a\u1234x" "a\u1234x" +select * from test_regex('a\U00001234x', E'a\u1234x', 'P'); +-- expectMatch 13.29 P "a\\U0001234x" "a\u1234x" "a\u1234x" +-- Tcl has relaxed their code to allow 1-8 hex digits, but Postgres hasn't +select * from test_regex('a\U0001234x', E'a\u1234x', 'P'); +-- expectMatch 13.30 P {a\U0001234x} "a\u1234x" "a\u1234x" +-- Tcl has relaxed their code to allow 1-8 hex digits, but Postgres hasn't +select * from test_regex('a\U0001234x', E'a\u1234x', 'P'); +-- expectMatch 13.31 P "a\\U000012345x" "a\u12345x" "a\u12345x" +select * from test_regex('a\U000012345x', E'a\u12345x', 'P'); +-- expectMatch 13.32 P {a\U000012345x} "a\u12345x" "a\u12345x" +select * from test_regex('a\U000012345x', E'a\u12345x', 'P'); +-- expectMatch 13.33 P "a\\U1000000x" "a\ufffd0x" "a\ufffd0x" +-- Tcl allows this as a standalone character, but Postgres doesn't +select * from test_regex('a\U1000000x', E'a\ufffd0x', 'P'); +-- expectMatch 13.34 P {a\U1000000x} "a\ufffd0x" "a\ufffd0x" +-- Tcl allows this as a standalone character, but Postgres doesn't +select * from test_regex('a\U1000000x', E'a\ufffd0x', 'P'); + + +-- Additional tests, not derived from Tcl + +-- Exercise logic around high character ranges a bit more +select * from test_regex('a + [\u1000-\u1100]* + [\u3000-\u3100]* + [\u1234-\u25ff]+ + [\u2000-\u35ff]* + [\u2600-\u2f00]* + \u1236\u1236x', + E'a\u1234\u1236\u1236x', 'xEMP'); + +select * from test_regex('[[:alnum:]]*[[:upper:]]*[\u1000-\u2000]*\u1237', + E'\u1500\u1237', 'ELMP'); +select * from test_regex('[[:alnum:]]*[[:upper:]]*[\u1000-\u2000]*\u1237', + E'A\u1239', 'ELMP'); diff --git a/src/test/modules/test_regex/test_regex--1.0.sql b/src/test/modules/test_regex/test_regex--1.0.sql new file mode 100644 index 0000000000000..7d991537f42bf --- /dev/null +++ b/src/test/modules/test_regex/test_regex--1.0.sql @@ -0,0 +1,9 @@ +/* src/test/modules/test_regex/test_regex--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION test_regex" to load this file. \quit + +CREATE FUNCTION test_regex(pattern text, string text, flags text) +RETURNS SETOF text[] +STRICT +AS 'MODULE_PATHNAME' LANGUAGE C; diff --git a/src/test/modules/test_regex/test_regex.c b/src/test/modules/test_regex/test_regex.c new file mode 100644 index 0000000000000..ad3c6d3b1a6c5 --- /dev/null +++ b/src/test/modules/test_regex/test_regex.c @@ -0,0 +1,759 @@ +/*-------------------------------------------------------------------------- + * + * test_regex.c + * Test harness for the regular expression package. + * + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/test/modules/test_regex/test_regex.c + * + * ------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "funcapi.h" +#include "miscadmin.h" +#include "regex/regex.h" +#include "utils/array.h" +#include "utils/builtins.h" + +PG_MODULE_MAGIC; + + +/* all the options of interest for regex functions */ +typedef struct test_re_flags +{ + int cflags; /* compile flags for Spencer's regex code */ + int eflags; /* execute flags for Spencer's regex code */ + long info; /* expected re_info bits */ + bool glob; /* do it globally (for each occurrence) */ + bool indices; /* report indices not actual strings */ + bool partial; /* expect partial match */ +} test_re_flags; + +/* cross-call state for test_regex() */ +typedef struct test_regex_ctx +{ + test_re_flags re_flags; /* flags */ + rm_detail_t details; /* "details" from execution */ + text *orig_str; /* data string in original TEXT form */ + int nmatches; /* number of places where pattern matched */ + int npatterns; /* number of capturing subpatterns */ + /* We store start char index and end+1 char index for each match */ + /* so the number of entries in match_locs is nmatches * npatterns * 2 */ + int *match_locs; /* 0-based character indexes */ + int next_match; /* 0-based index of next match to process */ + /* workspace for build_test_match_result() */ + Datum *elems; /* has npatterns+1 elements */ + bool *nulls; /* has npatterns+1 elements */ + pg_wchar *wide_str; /* wide-char version of original string */ + char *conv_buf; /* conversion buffer, if needed */ + int conv_bufsiz; /* size thereof */ +} test_regex_ctx; + +/* Local functions */ +static void test_re_compile(text *text_re, int cflags, Oid collation, + regex_t *result_re); +static void parse_test_flags(test_re_flags *flags, text *opts); +static test_regex_ctx *setup_test_matches(text *orig_str, + regex_t *cpattern, + test_re_flags *flags, + Oid collation, + bool use_subpatterns); +static ArrayType *build_test_info_result(regex_t *cpattern, + test_re_flags *flags); +static ArrayType *build_test_match_result(test_regex_ctx *matchctx); + + +/* + * test_regex(pattern text, string text, flags text) returns setof text[] + * + * This is largely based on regexp.c's regexp_matches, with additions + * for debugging purposes. + */ +PG_FUNCTION_INFO_V1(test_regex); + +Datum +test_regex(PG_FUNCTION_ARGS) +{ + FuncCallContext *funcctx; + test_regex_ctx *matchctx; + ArrayType *result_ary; + + if (SRF_IS_FIRSTCALL()) + { + text *pattern = PG_GETARG_TEXT_PP(0); + text *flags = PG_GETARG_TEXT_PP(2); + Oid collation = PG_GET_COLLATION(); + test_re_flags re_flags; + regex_t cpattern; + MemoryContext oldcontext; + + funcctx = SRF_FIRSTCALL_INIT(); + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + + /* Determine options */ + parse_test_flags(&re_flags, flags); + + /* set up the compiled pattern */ + test_re_compile(pattern, re_flags.cflags, collation, &cpattern); + + /* be sure to copy the input string into the multi-call ctx */ + matchctx = setup_test_matches(PG_GETARG_TEXT_P_COPY(1), &cpattern, + &re_flags, + collation, + true); + + /* Pre-create workspace that build_test_match_result needs */ + matchctx->elems = (Datum *) palloc(sizeof(Datum) * + (matchctx->npatterns + 1)); + matchctx->nulls = (bool *) palloc(sizeof(bool) * + (matchctx->npatterns + 1)); + + MemoryContextSwitchTo(oldcontext); + funcctx->user_fctx = (void *) matchctx; + + /* + * Return the first result row, which is info equivalent to Tcl's + * "regexp -about" output + */ + result_ary = build_test_info_result(&cpattern, &re_flags); + + pg_regfree(&cpattern); + + SRF_RETURN_NEXT(funcctx, PointerGetDatum(result_ary)); + } + else + { + /* Each subsequent row describes one match */ + funcctx = SRF_PERCALL_SETUP(); + matchctx = (test_regex_ctx *) funcctx->user_fctx; + + if (matchctx->next_match < matchctx->nmatches) + { + result_ary = build_test_match_result(matchctx); + matchctx->next_match++; + SRF_RETURN_NEXT(funcctx, PointerGetDatum(result_ary)); + } + } + + SRF_RETURN_DONE(funcctx); +} + + +/* + * test_re_compile - compile a RE + * + * text_re --- the pattern, expressed as a TEXT object + * cflags --- compile options for the pattern + * collation --- collation to use for LC_CTYPE-dependent behavior + * result_re --- output, compiled RE is stored here + * + * Pattern is given in the database encoding. We internally convert to + * an array of pg_wchar, which is what Spencer's regex package wants. + * + * Caller must eventually pg_regfree the resulting RE to avoid memory leaks. + */ +static void +test_re_compile(text *text_re, int cflags, Oid collation, + regex_t *result_re) +{ + int text_re_len = VARSIZE_ANY_EXHDR(text_re); + char *text_re_val = VARDATA_ANY(text_re); + pg_wchar *pattern; + int pattern_len; + int regcomp_result; + char errMsg[100]; + + /* Convert pattern string to wide characters */ + pattern = (pg_wchar *) palloc((text_re_len + 1) * sizeof(pg_wchar)); + pattern_len = pg_mb2wchar_with_len(text_re_val, + pattern, + text_re_len); + + regcomp_result = pg_regcomp(result_re, + pattern, + pattern_len, + cflags, + collation); + + pfree(pattern); + + if (regcomp_result != REG_OKAY) + { + /* re didn't compile (no need for pg_regfree, if so) */ + + /* + * Here and in other places in this file, do CHECK_FOR_INTERRUPTS + * before reporting a regex error. This is so that if the regex + * library aborts and returns REG_CANCEL, we don't print an error + * message that implies the regex was invalid. + */ + CHECK_FOR_INTERRUPTS(); + + pg_regerror(regcomp_result, result_re, errMsg, sizeof(errMsg)); + ereport(ERROR, + (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION), + errmsg("invalid regular expression: %s", errMsg))); + } +} + +/* + * test_re_execute - execute a RE on pg_wchar data + * + * Returns true on match, false on no match + * Arguments are as for pg_regexec + */ +static bool +test_re_execute(regex_t *re, pg_wchar *data, int data_len, + int start_search, + rm_detail_t *details, + int nmatch, regmatch_t *pmatch, + int eflags) +{ + int regexec_result; + char errMsg[100]; + + /* Initialize match locations in case engine doesn't */ + details->rm_extend.rm_so = -1; + details->rm_extend.rm_eo = -1; + for (int i = 0; i < nmatch; i++) + { + pmatch[i].rm_so = -1; + pmatch[i].rm_eo = -1; + } + + /* Perform RE match and return result */ + regexec_result = pg_regexec(re, + data, + data_len, + start_search, + details, + nmatch, + pmatch, + eflags); + + if (regexec_result != REG_OKAY && regexec_result != REG_NOMATCH) + { + /* re failed??? */ + CHECK_FOR_INTERRUPTS(); + pg_regerror(regexec_result, re, errMsg, sizeof(errMsg)); + ereport(ERROR, + (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION), + errmsg("regular expression failed: %s", errMsg))); + } + + return (regexec_result == REG_OKAY); +} + + +/* + * parse_test_flags - parse the flags argument + * + * flags --- output argument, filled with desired options + * opts --- TEXT object, or NULL for defaults + */ +static void +parse_test_flags(test_re_flags *flags, text *opts) +{ + /* these defaults must match Tcl's */ + int cflags = REG_ADVANCED; + int eflags = 0; + long info = 0; + + flags->glob = false; + flags->indices = false; + flags->partial = false; + + if (opts) + { + char *opt_p = VARDATA_ANY(opts); + int opt_len = VARSIZE_ANY_EXHDR(opts); + int i; + + for (i = 0; i < opt_len; i++) + { + switch (opt_p[i]) + { + case '-': + /* allowed, no-op */ + break; + case '!': + flags->partial = true; + break; + case '*': + /* test requires Unicode --- ignored here */ + break; + case '0': + flags->indices = true; + break; + + /* These flags correspond to user-exposed RE options: */ + case 'g': /* global match */ + flags->glob = true; + break; + case 'i': /* case insensitive */ + cflags |= REG_ICASE; + break; + case 'n': /* \n affects ^ $ . [^ */ + cflags |= REG_NEWLINE; + break; + case 'p': /* ~Perl, \n affects . [^ */ + cflags |= REG_NLSTOP; + cflags &= ~REG_NLANCH; + break; + case 'w': /* weird, \n affects ^ $ only */ + cflags &= ~REG_NLSTOP; + cflags |= REG_NLANCH; + break; + case 'x': /* expanded syntax */ + cflags |= REG_EXPANDED; + break; + + /* These flags correspond to Tcl's -xflags options: */ + case 'a': + cflags |= REG_ADVF; + break; + case 'b': + cflags &= ~REG_ADVANCED; + break; + case 'c': + + /* + * Tcl calls this TCL_REG_CANMATCH, but it's really + * REG_EXPECT. In this implementation we must also set + * the partial and indices flags, so that + * setup_test_matches and build_test_match_result will + * emit the desired data. (They'll emit more fields than + * Tcl would, but that's fine.) + */ + cflags |= REG_EXPECT; + flags->partial = true; + flags->indices = true; + break; + case 'e': + cflags &= ~REG_ADVANCED; + cflags |= REG_EXTENDED; + break; + case 'q': + cflags &= ~REG_ADVANCED; + cflags |= REG_QUOTE; + break; + case 'o': /* o for opaque */ + cflags |= REG_NOSUB; + break; + case 's': /* s for start */ + cflags |= REG_BOSONLY; + break; + case '+': + cflags |= REG_FAKE; + break; + case ',': + cflags |= REG_PROGRESS; + break; + case '.': + cflags |= REG_DUMP; + break; + case ':': + eflags |= REG_MTRACE; + break; + case ';': + eflags |= REG_FTRACE; + break; + case '^': + eflags |= REG_NOTBOL; + break; + case '$': + eflags |= REG_NOTEOL; + break; + case 't': + cflags |= REG_EXPECT; + break; + case '%': + eflags |= REG_SMALL; + break; + + /* These flags define expected info bits: */ + case 'A': + info |= REG_UBSALNUM; + break; + case 'B': + info |= REG_UBRACES; + break; + case 'E': + info |= REG_UBBS; + break; + case 'H': + info |= REG_ULOOKAROUND; + break; + case 'I': + info |= REG_UIMPOSSIBLE; + break; + case 'L': + info |= REG_ULOCALE; + break; + case 'M': + info |= REG_UUNPORT; + break; + case 'N': + info |= REG_UEMPTYMATCH; + break; + case 'P': + info |= REG_UNONPOSIX; + break; + case 'Q': + info |= REG_UBOUNDS; + break; + case 'R': + info |= REG_UBACKREF; + break; + case 'S': + info |= REG_UUNSPEC; + break; + case 'T': + info |= REG_USHORTEST; + break; + case 'U': + info |= REG_UPBOTCH; + break; + + default: + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid regular expression test option: \"%.*s\"", + pg_mblen(opt_p + i), opt_p + i))); + break; + } + } + } + flags->cflags = cflags; + flags->eflags = eflags; + flags->info = info; +} + +/* + * setup_test_matches --- do the initial matching + * + * To simplify memory management, we do all the matching in one swoop. + * The returned test_regex_ctx contains the locations of all the substrings + * matching the pattern. + */ +static test_regex_ctx * +setup_test_matches(text *orig_str, + regex_t *cpattern, test_re_flags *re_flags, + Oid collation, + bool use_subpatterns) +{ + test_regex_ctx *matchctx = palloc0(sizeof(test_regex_ctx)); + int eml = pg_database_encoding_max_length(); + int orig_len; + pg_wchar *wide_str; + int wide_len; + regmatch_t *pmatch; + int pmatch_len; + int array_len; + int array_idx; + int prev_match_end; + int start_search; + int maxlen = 0; /* largest fetch length in characters */ + + /* save flags */ + matchctx->re_flags = *re_flags; + + /* save original string --- we'll extract result substrings from it */ + matchctx->orig_str = orig_str; + + /* convert string to pg_wchar form for matching */ + orig_len = VARSIZE_ANY_EXHDR(orig_str); + wide_str = (pg_wchar *) palloc(sizeof(pg_wchar) * (orig_len + 1)); + wide_len = pg_mb2wchar_with_len(VARDATA_ANY(orig_str), wide_str, orig_len); + + /* do we want to remember subpatterns? */ + if (use_subpatterns && cpattern->re_nsub > 0) + { + matchctx->npatterns = cpattern->re_nsub + 1; + pmatch_len = cpattern->re_nsub + 1; + } + else + { + use_subpatterns = false; + matchctx->npatterns = 1; + pmatch_len = 1; + } + + /* temporary output space for RE package */ + pmatch = palloc(sizeof(regmatch_t) * pmatch_len); + + /* + * the real output space (grown dynamically if needed) + * + * use values 2^n-1, not 2^n, so that we hit the limit at 2^28-1 rather + * than at 2^27 + */ + array_len = re_flags->glob ? 255 : 31; + matchctx->match_locs = (int *) palloc(sizeof(int) * array_len); + array_idx = 0; + + /* search for the pattern, perhaps repeatedly */ + prev_match_end = 0; + start_search = 0; + while (test_re_execute(cpattern, wide_str, wide_len, + start_search, + &matchctx->details, + pmatch_len, pmatch, + re_flags->eflags)) + { + /* enlarge output space if needed */ + while (array_idx + matchctx->npatterns * 2 + 1 > array_len) + { + array_len += array_len + 1; /* 2^n-1 => 2^(n+1)-1 */ + if (array_len > MaxAllocSize / sizeof(int)) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("too many regular expression matches"))); + matchctx->match_locs = (int *) repalloc(matchctx->match_locs, + sizeof(int) * array_len); + } + + /* save this match's locations */ + for (int i = 0; i < matchctx->npatterns; i++) + { + int so = pmatch[i].rm_so; + int eo = pmatch[i].rm_eo; + + matchctx->match_locs[array_idx++] = so; + matchctx->match_locs[array_idx++] = eo; + if (so >= 0 && eo >= 0 && (eo - so) > maxlen) + maxlen = (eo - so); + } + matchctx->nmatches++; + prev_match_end = pmatch[0].rm_eo; + + /* if not glob, stop after one match */ + if (!re_flags->glob) + break; + + /* + * Advance search position. Normally we start the next search at the + * end of the previous match; but if the match was of zero length, we + * have to advance by one character, or we'd just find the same match + * again. + */ + start_search = prev_match_end; + if (pmatch[0].rm_so == pmatch[0].rm_eo) + start_search++; + if (start_search > wide_len) + break; + } + + /* + * If we had no match, but "partial" and "indices" are set, emit the + * details. + */ + if (matchctx->nmatches == 0 && re_flags->partial && re_flags->indices) + { + matchctx->match_locs[array_idx++] = matchctx->details.rm_extend.rm_so; + matchctx->match_locs[array_idx++] = matchctx->details.rm_extend.rm_eo; + /* we don't have pmatch data, so emit -1 */ + for (int i = 1; i < matchctx->npatterns; i++) + { + matchctx->match_locs[array_idx++] = -1; + matchctx->match_locs[array_idx++] = -1; + } + matchctx->nmatches++; + } + + if (eml > 1) + { + int64 maxsiz = eml * (int64) maxlen; + int conv_bufsiz; + + /* + * Make the conversion buffer large enough for any substring of + * interest. + * + * Worst case: assume we need the maximum size (maxlen*eml), but take + * advantage of the fact that the original string length in bytes is + * an upper bound on the byte length of any fetched substring (and we + * know that len+1 is safe to allocate because the varlena header is + * longer than 1 byte). + */ + if (maxsiz > orig_len) + conv_bufsiz = orig_len + 1; + else + conv_bufsiz = maxsiz + 1; /* safe since maxsiz < 2^30 */ + + matchctx->conv_buf = palloc(conv_bufsiz); + matchctx->conv_bufsiz = conv_bufsiz; + matchctx->wide_str = wide_str; + } + else + { + /* No need to keep the wide string if we're in a single-byte charset. */ + pfree(wide_str); + matchctx->wide_str = NULL; + matchctx->conv_buf = NULL; + matchctx->conv_bufsiz = 0; + } + + /* Clean up temp storage */ + pfree(pmatch); + + return matchctx; +} + +/* + * build_test_info_result - build output array describing compiled regexp + * + * This borrows some code from Tcl's TclRegAbout(). + */ +static ArrayType * +build_test_info_result(regex_t *cpattern, test_re_flags *flags) +{ + /* Translation data for flag bits in regex_t.re_info */ + struct infoname + { + int bit; + const char *text; + }; + static const struct infoname infonames[] = { + {REG_UBACKREF, "REG_UBACKREF"}, + {REG_ULOOKAROUND, "REG_ULOOKAROUND"}, + {REG_UBOUNDS, "REG_UBOUNDS"}, + {REG_UBRACES, "REG_UBRACES"}, + {REG_UBSALNUM, "REG_UBSALNUM"}, + {REG_UPBOTCH, "REG_UPBOTCH"}, + {REG_UBBS, "REG_UBBS"}, + {REG_UNONPOSIX, "REG_UNONPOSIX"}, + {REG_UUNSPEC, "REG_UUNSPEC"}, + {REG_UUNPORT, "REG_UUNPORT"}, + {REG_ULOCALE, "REG_ULOCALE"}, + {REG_UEMPTYMATCH, "REG_UEMPTYMATCH"}, + {REG_UIMPOSSIBLE, "REG_UIMPOSSIBLE"}, + {REG_USHORTEST, "REG_USHORTEST"}, + {0, NULL} + }; + const struct infoname *inf; + Datum elems[lengthof(infonames) + 1]; + int nresults = 0; + char buf[80]; + int dims[1]; + int lbs[1]; + + /* Set up results: first, the number of subexpressions */ + snprintf(buf, sizeof(buf), "%d", (int) cpattern->re_nsub); + elems[nresults++] = PointerGetDatum(cstring_to_text(buf)); + + /* Report individual info bit states */ + for (inf = infonames; inf->bit != 0; inf++) + { + if (cpattern->re_info & inf->bit) + { + if (flags->info & inf->bit) + elems[nresults++] = PointerGetDatum(cstring_to_text(inf->text)); + else + { + snprintf(buf, sizeof(buf), "unexpected %s!", inf->text); + elems[nresults++] = PointerGetDatum(cstring_to_text(buf)); + } + } + else + { + if (flags->info & inf->bit) + { + snprintf(buf, sizeof(buf), "missing %s!", inf->text); + elems[nresults++] = PointerGetDatum(cstring_to_text(buf)); + } + } + } + + /* And form an array */ + dims[0] = nresults; + lbs[0] = 1; + /* XXX: this hardcodes assumptions about the text type */ + return construct_md_array(elems, NULL, 1, dims, lbs, + TEXTOID, -1, false, TYPALIGN_INT); +} + +/* + * build_test_match_result - build output array for current match + * + * Note that if the indices flag is set, we don't need any strings, + * just the location data. + */ +static ArrayType * +build_test_match_result(test_regex_ctx *matchctx) +{ + char *buf = matchctx->conv_buf; + Datum *elems = matchctx->elems; + bool *nulls = matchctx->nulls; + bool indices = matchctx->re_flags.indices; + char bufstr[80]; + int dims[1]; + int lbs[1]; + int loc; + int i; + + /* Extract matching substrings from the original string */ + loc = matchctx->next_match * matchctx->npatterns * 2; + for (i = 0; i < matchctx->npatterns; i++) + { + int so = matchctx->match_locs[loc++]; + int eo = matchctx->match_locs[loc++]; + + if (indices) + { + /* Report eo this way for consistency with Tcl */ + snprintf(bufstr, sizeof(bufstr), "%d %d", + so, so < 0 ? eo : eo - 1); + elems[i] = PointerGetDatum(cstring_to_text(bufstr)); + nulls[i] = false; + } + else if (so < 0 || eo < 0) + { + elems[i] = (Datum) 0; + nulls[i] = true; + } + else if (buf) + { + int len = pg_wchar2mb_with_len(matchctx->wide_str + so, + buf, + eo - so); + + Assert(len < matchctx->conv_bufsiz); + elems[i] = PointerGetDatum(cstring_to_text_with_len(buf, len)); + nulls[i] = false; + } + else + { + elems[i] = DirectFunctionCall3(text_substr, + PointerGetDatum(matchctx->orig_str), + Int32GetDatum(so + 1), + Int32GetDatum(eo - so)); + nulls[i] = false; + } + } + + /* In EXPECT indices mode, also report the "details" */ + if (indices && (matchctx->re_flags.cflags & REG_EXPECT)) + { + int so = matchctx->details.rm_extend.rm_so; + int eo = matchctx->details.rm_extend.rm_eo; + + snprintf(bufstr, sizeof(bufstr), "%d %d", + so, so < 0 ? eo : eo - 1); + elems[i] = PointerGetDatum(cstring_to_text(bufstr)); + nulls[i] = false; + i++; + } + + /* And form an array */ + dims[0] = i; + lbs[0] = 1; + /* XXX: this hardcodes assumptions about the text type */ + return construct_md_array(elems, nulls, 1, dims, lbs, + TEXTOID, -1, false, TYPALIGN_INT); +} diff --git a/src/test/modules/test_regex/test_regex.control b/src/test/modules/test_regex/test_regex.control new file mode 100644 index 0000000000000..bfce1009cc5d4 --- /dev/null +++ b/src/test/modules/test_regex/test_regex.control @@ -0,0 +1,4 @@ +comment = 'Test code for backend/regex/' +default_version = '1.0' +module_pathname = '$libdir/test_regex' +relocatable = true From 8a4f618e7ae3cb11b0b37d0f06f05c8ff905833f Mon Sep 17 00:00:00 2001 From: Tomas Vondra Date: Wed, 6 Jan 2021 21:46:26 +0100 Subject: [PATCH 050/240] Report progress of COPY commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit introduces a view pg_stat_progress_copy, reporting progress of COPY commands. This allows rough estimates how far a running COPY progressed, with the caveat that the total number of bytes may not be available in some cases (e.g. when the input comes from the client). Author: Josef Šimánek Reviewed-by: Fujii Masao, Bharath Rupireddy, Vignesh C, Matthias van de Meent Discussion: https://postgr.es/m/CAFp7QwqMGEi4OyyaLEK9DR0+E+oK3UtA4bEjDVCa4bNkwUY2PQ@mail.gmail.com Discussion: https://postgr.es/m/CAFp7Qwr6_FmRM6pCO0x_a0mymOfX_Gg+FEKet4XaTGSW=LitKQ@mail.gmail.com --- doc/src/sgml/monitoring.sgml | 107 +++++++++++++++++++++++ src/backend/catalog/system_views.sql | 11 +++ src/backend/commands/copyfrom.c | 17 +++- src/backend/commands/copyfromparse.c | 4 + src/backend/commands/copyto.c | 22 ++++- src/backend/utils/adt/pgstatfuncs.c | 2 + src/include/commands/copyfrom_internal.h | 1 + src/include/commands/progress.h | 5 ++ src/include/pgstat.h | 3 +- src/test/regress/expected/rules.out | 9 ++ 10 files changed, 176 insertions(+), 5 deletions(-) diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index 3d6c901306777..43fe8ae383eb9 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -399,6 +399,12 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser + + pg_stat_progress_copypg_stat_progress_copy + One row for each backend running COPY, showing current progress. + See . + +
@@ -5247,6 +5253,7 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid, which support progress reporting are ANALYZE, CLUSTER, CREATE INDEX, VACUUM, + COPY, and (i.e., replication command that issues to take a base backup). @@ -6396,6 +6403,106 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid, + + + COPY Progress Reporting + + + pg_stat_progress_copy + + + + Whenever COPY is running, the + pg_stat_progress_copy view will contain one row + for each backend that is currently running COPY command. + The table bellow describes the information that will be reported and provide + information how to interpret it. + + + + <structname>pg_stat_progress_copy</structname> View + + + + + Column Type + + + Description + + + + + + + + pid integer + + + Process ID of backend. + + + + + + datid text + + + OID of the database to which this backend is connected. + + + + + + datname name + + + Name of the database to which this backend is connected. + + + + + + relid oid + + + OID of the table on which the COPY command is executed. + It is set to 0 if SELECT query is provided. + + + + + + bytes_processed bigint + + + Number of bytes already processed by COPY command. + + + + + + bytes_total bigint + + + Size of source file for COPY FROM command in bytes. + It is set to 0 if not available. + + + + + + lines_processed bigint + + + Number of lines already processed by COPY command. + + + + +
+
+ diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index ab4603c69b8e8..5d89e77dbe2f5 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -1117,6 +1117,17 @@ CREATE VIEW pg_stat_progress_basebackup AS S.param5 AS tablespaces_streamed FROM pg_stat_get_progress_info('BASEBACKUP') AS S; + +CREATE VIEW pg_stat_progress_copy AS + SELECT + S.pid AS pid, S.datid AS datid, D.datname AS datname, + S.relid AS relid, + S.param1 AS bytes_processed, + S.param2 AS bytes_total, + S.param3 AS lines_processed + FROM pg_stat_get_progress_info('COPY') AS S + LEFT JOIN pg_database D ON S.datid = D.oid; + CREATE VIEW pg_user_mappings AS SELECT U.oid AS umid, diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c index 84a5045215b07..08b6f782c7358 100644 --- a/src/backend/commands/copyfrom.c +++ b/src/backend/commands/copyfrom.c @@ -25,6 +25,7 @@ #include "access/xlog.h" #include "commands/copy.h" #include "commands/copyfrom_internal.h" +#include "commands/progress.h" #include "commands/trigger.h" #include "executor/execPartition.h" #include "executor/executor.h" @@ -35,6 +36,7 @@ #include "libpq/pqformat.h" #include "miscadmin.h" #include "optimizer/optimizer.h" +#include "pgstat.h" #include "rewrite/rewriteHandler.h" #include "storage/fd.h" #include "tcop/tcopprot.h" @@ -1100,9 +1102,10 @@ CopyFrom(CopyFromState cstate) /* * We count only tuples not suppressed by a BEFORE INSERT trigger * or FDW; this is the same definition used by nodeModifyTable.c - * for counting tuples inserted by an INSERT command. + * for counting tuples inserted by an INSERT command. Update + * progress of the COPY command as well. */ - processed++; + pgstat_progress_update_param(PROGRESS_COPY_LINES_PROCESSED, ++processed); } } @@ -1415,6 +1418,12 @@ BeginCopyFrom(ParseState *pstate, } } + + /* initialize progress */ + pgstat_progress_start_command(PROGRESS_COMMAND_COPY, + cstate->rel ? RelationGetRelid(cstate->rel) : InvalidOid); + cstate->bytes_processed = 0; + /* We keep those variables in cstate. */ cstate->in_functions = in_functions; cstate->typioparams = typioparams; @@ -1479,6 +1488,8 @@ BeginCopyFrom(ParseState *pstate, ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is a directory", cstate->filename))); + + pgstat_progress_update_param(PROGRESS_COPY_BYTES_TOTAL, st.st_size); } } @@ -1522,6 +1533,8 @@ EndCopyFrom(CopyFromState cstate) cstate->filename))); } + pgstat_progress_end_command(); + MemoryContextDelete(cstate->copycontext); pfree(cstate); } diff --git a/src/backend/commands/copyfromparse.c b/src/backend/commands/copyfromparse.c index 4360b7788ea0b..4c74067f849cc 100644 --- a/src/backend/commands/copyfromparse.c +++ b/src/backend/commands/copyfromparse.c @@ -20,11 +20,13 @@ #include "commands/copy.h" #include "commands/copyfrom_internal.h" +#include "commands/progress.h" #include "executor/executor.h" #include "libpq/libpq.h" #include "libpq/pqformat.h" #include "mb/pg_wchar.h" #include "miscadmin.h" +#include "pgstat.h" #include "port/pg_bswap.h" #include "utils/memutils.h" #include "utils/rel.h" @@ -384,6 +386,8 @@ CopyLoadRawBuf(CopyFromState cstate) cstate->raw_buf[nbytes] = '\0'; cstate->raw_buf_index = 0; cstate->raw_buf_len = nbytes; + cstate->bytes_processed += nbytes; + pgstat_progress_update_param(PROGRESS_COPY_BYTES_PROCESSED, cstate->bytes_processed); return (inbytes > 0); } diff --git a/src/backend/commands/copyto.c b/src/backend/commands/copyto.c index 51597ae523d1a..e04ec1e331b4b 100644 --- a/src/backend/commands/copyto.c +++ b/src/backend/commands/copyto.c @@ -24,6 +24,7 @@ #include "access/xact.h" #include "access/xlog.h" #include "commands/copy.h" +#include "commands/progress.h" #include "executor/execdesc.h" #include "executor/executor.h" #include "executor/tuptable.h" @@ -32,6 +33,7 @@ #include "mb/pg_wchar.h" #include "miscadmin.h" #include "optimizer/optimizer.h" +#include "pgstat.h" #include "rewrite/rewriteHandler.h" #include "storage/fd.h" #include "tcop/tcopprot.h" @@ -95,6 +97,7 @@ typedef struct CopyToStateData FmgrInfo *out_functions; /* lookup info for output functions */ MemoryContext rowcontext; /* per-row evaluation context */ + uint64 bytes_processed; /* number of bytes processed so far */ } CopyToStateData; @@ -288,6 +291,10 @@ CopySendEndOfRow(CopyToState cstate) break; } + /* Update the progress */ + cstate->bytes_processed += fe_msgbuf->len; + pgstat_progress_update_param(PROGRESS_COPY_BYTES_PROCESSED, cstate->bytes_processed); + resetStringInfo(fe_msgbuf); } @@ -363,6 +370,8 @@ EndCopy(CopyToState cstate) cstate->filename))); } + pgstat_progress_end_command(); + MemoryContextDelete(cstate->copycontext); pfree(cstate); } @@ -760,6 +769,11 @@ BeginCopyTo(ParseState *pstate, } } + /* initialize progress */ + pgstat_progress_start_command(PROGRESS_COMMAND_COPY, + cstate->rel ? RelationGetRelid(cstate->rel) : InvalidOid); + cstate->bytes_processed = 0; + MemoryContextSwitchTo(oldcontext); return cstate; @@ -938,7 +952,9 @@ CopyTo(CopyToState cstate) /* Format and send the data */ CopyOneRowTo(cstate, slot); - processed++; + + /* Increment amount of processed tuples and update the progress */ + pgstat_progress_update_param(PROGRESS_COPY_LINES_PROCESSED, ++processed); } ExecDropSingleTupleTableSlot(slot); @@ -1303,7 +1319,9 @@ copy_dest_receive(TupleTableSlot *slot, DestReceiver *self) /* Send the data */ CopyOneRowTo(cstate, slot); - myState->processed++; + + /* Increment amount of processed tuples and update the progress */ + pgstat_progress_update_param(PROGRESS_COPY_LINES_PROCESSED, ++myState->processed); return true; } diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index c9a1d4c56d978..5c12a165a1535 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -494,6 +494,8 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS) cmdtype = PROGRESS_COMMAND_CREATE_INDEX; else if (pg_strcasecmp(cmd, "BASEBACKUP") == 0) cmdtype = PROGRESS_COMMAND_BASEBACKUP; + else if (pg_strcasecmp(cmd, "COPY") == 0) + cmdtype = PROGRESS_COMMAND_COPY; else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), diff --git a/src/include/commands/copyfrom_internal.h b/src/include/commands/copyfrom_internal.h index 5401a966d2707..e37942df391e7 100644 --- a/src/include/commands/copyfrom_internal.h +++ b/src/include/commands/copyfrom_internal.h @@ -154,6 +154,7 @@ typedef struct CopyFromStateData char *raw_buf; int raw_buf_index; /* next byte to process */ int raw_buf_len; /* total # of bytes stored */ + uint64 bytes_processed;/* number of bytes processed so far */ /* Shorthand for number of unconsumed bytes available in raw_buf */ #define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index) } CopyFromStateData; diff --git a/src/include/commands/progress.h b/src/include/commands/progress.h index 49a158aabbf92..95ec5d02e9cc4 100644 --- a/src/include/commands/progress.h +++ b/src/include/commands/progress.h @@ -133,4 +133,9 @@ #define PROGRESS_BASEBACKUP_PHASE_WAIT_WAL_ARCHIVE 4 #define PROGRESS_BASEBACKUP_PHASE_TRANSFER_WAL 5 +/* Commands of PROGRESS_COPY */ +#define PROGRESS_COPY_BYTES_PROCESSED 0 +#define PROGRESS_COPY_BYTES_TOTAL 1 +#define PROGRESS_COPY_LINES_PROCESSED 2 + #endif diff --git a/src/include/pgstat.h b/src/include/pgstat.h index 3a7e1997506e2..c38b68971019c 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -1077,7 +1077,8 @@ typedef enum ProgressCommandType PROGRESS_COMMAND_ANALYZE, PROGRESS_COMMAND_CLUSTER, PROGRESS_COMMAND_CREATE_INDEX, - PROGRESS_COMMAND_BASEBACKUP + PROGRESS_COMMAND_BASEBACKUP, + PROGRESS_COMMAND_COPY } ProgressCommandType; #define PGSTAT_NUM_PROGRESS_PARAM 20 diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 6293ab57bcf61..a687e99d1e4fe 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1937,6 +1937,15 @@ pg_stat_progress_cluster| SELECT s.pid, s.param8 AS index_rebuild_count FROM (pg_stat_get_progress_info('CLUSTER'::text) s(pid, datid, relid, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) LEFT JOIN pg_database d ON ((s.datid = d.oid))); +pg_stat_progress_copy| SELECT s.pid, + s.datid, + d.datname, + s.relid, + s.param1 AS bytes_processed, + s.param2 AS bytes_total, + s.param3 AS lines_processed + FROM (pg_stat_get_progress_info('COPY'::text) s(pid, datid, relid, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) + LEFT JOIN pg_database d ON ((s.datid = d.oid))); pg_stat_progress_create_index| SELECT s.pid, s.datid, d.datname, From 09cf1d52267644cdbdb734294012cf1228745aaa Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 6 Jan 2021 18:23:03 -0500 Subject: [PATCH 051/240] Improve timeout.c's handling of repeated timeout set/cancel. A very common usage pattern is that we set a timeout that we don't expect to reach, cancel it after a little bit, and later repeat. With the original implementation of timeout.c, this results in one setitimer() call per timeout set or cancel. We can do a lot better by being lazy about changing the timeout interrupt request, namely: (1) never cancel the outstanding interrupt, even when we have no active timeout events; (2) if we need to set an interrupt, but there already is one pending at or before the required time, leave it alone. When the interrupt happens, the signal handler will reschedule it at whatever time is then needed. For example, with a one-second setting for statement_timeout, this method results in having to interact with the kernel only a little more than once a second, no matter how many statements we execute in between. The mainline code might never call setitimer() at all after the first time, while each time the signal handler fires, it sees that the then-pending request is most of a second away, and that's when it sets the next interrupt request for. Each mainline timeout-set request after that will observe that the time it wants is past the pending interrupt request time, and do nothing. This also works pretty well for cases where a few different timeout lengths are in use, as long as none of them are very short. But that describes our usage well. Idea and original patch by Thomas Munro; I fixed a race condition and improved the comments. Discussion: https://postgr.es/m/CA+hUKG+o6pbuHBJSGnud=TadsuXySWA7CCcPgCt2QE9F6_4iHQ@mail.gmail.com --- src/backend/utils/misc/timeout.c | 126 ++++++++++++++++++++++++------- 1 file changed, 100 insertions(+), 26 deletions(-) diff --git a/src/backend/utils/misc/timeout.c b/src/backend/utils/misc/timeout.c index b47e8ba2fb490..88139ab82b688 100644 --- a/src/backend/utils/misc/timeout.c +++ b/src/backend/utils/misc/timeout.c @@ -53,18 +53,29 @@ static timeout_params *volatile active_timeouts[MAX_TIMEOUTS]; /* * Flag controlling whether the signal handler is allowed to do anything. - * We leave this "false" when we're not expecting interrupts, just in case. + * This is useful to avoid race conditions with the handler. Note in + * particular that this lets us make changes in the data structures without + * tediously disabling and re-enabling the timer signal. Most of the time, + * no interrupt would happen anyway during such critical sections, but if + * one does, this rule ensures it's safe. Leaving the signal enabled across + * multiple operations can greatly reduce the number of kernel calls we make, + * too. See comments in schedule_alarm() about that. * - * Note that we don't bother to reset any pending timer interrupt when we - * disable the signal handler; it's not really worth the cycles to do so, - * since the probability of the interrupt actually occurring while we have - * it disabled is low. See comments in schedule_alarm() about that. + * We leave this "false" when we're not expecting interrupts, just in case. */ static volatile sig_atomic_t alarm_enabled = false; #define disable_alarm() (alarm_enabled = false) #define enable_alarm() (alarm_enabled = true) +/* + * State recording if and when we next expect the interrupt to fire. + * Note that the signal handler will unconditionally reset signal_pending to + * false, so that can change asynchronously even when alarm_enabled is false. + */ +static volatile sig_atomic_t signal_pending = false; +static TimestampTz signal_due_at = 0; /* valid only when signal_pending */ + /***************************************************************************** * Internal helper functions @@ -185,7 +196,11 @@ enable_timeout(TimeoutId id, TimestampTz now, TimestampTz fin_time) * Schedule alarm for the next active timeout, if any * * We assume the caller has obtained the current time, or a close-enough - * approximation. + * approximation. (It's okay if a tick or two has passed since "now", or + * if a little more time elapses before we reach the kernel call; that will + * cause us to ask for an interrupt a tick or two later than the nearest + * timeout, which is no big deal. Passing a "now" value that's in the future + * would be bad though.) */ static void schedule_alarm(TimestampTz now) @@ -193,21 +208,38 @@ schedule_alarm(TimestampTz now) if (num_active_timeouts > 0) { struct itimerval timeval; + TimestampTz nearest_timeout; long secs; int usecs; MemSet(&timeval, 0, sizeof(struct itimerval)); - /* Get the time remaining till the nearest pending timeout */ - TimestampDifference(now, active_timeouts[0]->fin_time, - &secs, &usecs); - /* - * It's possible that the difference is less than a microsecond; - * ensure we don't cancel, rather than set, the interrupt. + * Get the time remaining till the nearest pending timeout. If it is + * negative, assume that we somehow missed an interrupt, and force + * signal_pending off. This gives us a chance to recover if the + * kernel drops a timeout request for some reason. */ - if (secs == 0 && usecs == 0) + nearest_timeout = active_timeouts[0]->fin_time; + if (now > nearest_timeout) + { + signal_pending = false; + /* force an interrupt as soon as possible */ + secs = 0; usecs = 1; + } + else + { + TimestampDifference(now, nearest_timeout, + &secs, &usecs); + + /* + * It's possible that the difference is less than a microsecond; + * ensure we don't cancel, rather than set, the interrupt. + */ + if (secs == 0 && usecs == 0) + usecs = 1; + } timeval.it_value.tv_sec = secs; timeval.it_value.tv_usec = usecs; @@ -218,7 +250,7 @@ schedule_alarm(TimestampTz now) * interrupt could occur before we can set alarm_enabled, so that the * signal handler would fail to do anything. * - * Because we didn't bother to reset the timer in disable_alarm(), + * Because we didn't bother to disable the timer in disable_alarm(), * it's possible that a previously-set interrupt will fire between * enable_alarm() and setitimer(). This is safe, however. There are * two possible outcomes: @@ -244,9 +276,53 @@ schedule_alarm(TimestampTz now) */ enable_alarm(); + /* + * If there is already an interrupt pending that's at or before the + * needed time, we need not do anything more. The signal handler will + * do the right thing in the first case, and re-schedule the interrupt + * for later in the second case. It might seem that the extra + * interrupt is wasted work, but it's not terribly much work, and this + * method has very significant advantages in the common use-case where + * we repeatedly set a timeout that we don't expect to reach and then + * cancel it. Instead of invoking setitimer() every time the timeout + * is set or canceled, we perform one interrupt and a re-scheduling + * setitimer() call at intervals roughly equal to the timeout delay. + * For example, with statement_timeout = 1s and a throughput of + * thousands of queries per second, this method requires an interrupt + * and setitimer() call roughly once a second, rather than thousands + * of setitimer() calls per second. + * + * Because of the possible passage of time between when we obtained + * "now" and when we reach setitimer(), the kernel's opinion of when + * to trigger the interrupt is likely to be a bit later than + * signal_due_at. That's fine, for the same reasons described above. + */ + if (signal_pending && nearest_timeout >= signal_due_at) + return; + + /* + * As with calling enable_alarm(), we must set signal_pending *before* + * calling setitimer(); if we did it after, the signal handler could + * trigger before we set it, leaving us with a false opinion that a + * signal is still coming. + * + * Other race conditions involved with setting/checking signal_pending + * are okay, for the reasons described above. + */ + signal_due_at = nearest_timeout; + signal_pending = true; + /* Set the alarm timer */ if (setitimer(ITIMER_REAL, &timeval, NULL) != 0) + { + /* + * Clearing signal_pending here is a bit pro forma, but not + * entirely so, since something in the FATAL exit path could try + * to use timeout facilities. + */ + signal_pending = false; elog(FATAL, "could not enable SIGALRM timer: %m"); + } } } @@ -279,6 +355,12 @@ handle_sig_alarm(SIGNAL_ARGS) */ SetLatch(MyLatch); + /* + * Always reset signal_pending, even if !alarm_enabled, since indeed no + * signal is now pending. + */ + signal_pending = false; + /* * Fire any pending timeouts, but only if we're enabled to do so. */ @@ -591,7 +673,7 @@ disable_timeouts(const DisableTimeoutParams *timeouts, int count) } /* - * Disable SIGALRM and remove all timeouts from the active list, + * Disable the signal handler, remove all timeouts from the active list, * and optionally reset their timeout indicators. */ void @@ -602,18 +684,10 @@ disable_all_timeouts(bool keep_indicators) disable_alarm(); /* - * Only bother to reset the timer if we think it's active. We could just - * let the interrupt happen anyway, but it's probably a bit cheaper to do - * setitimer() than to let the useless interrupt happen. + * We used to disable the timer interrupt here, but in common usage + * patterns it's cheaper to leave it enabled; that may save us from having + * to enable it again shortly. See comments in schedule_alarm(). */ - if (num_active_timeouts > 0) - { - struct itimerval timeval; - - MemSet(&timeval, 0, sizeof(struct itimerval)); - if (setitimer(ITIMER_REAL, &timeval, NULL) != 0) - elog(FATAL, "could not disable SIGALRM timer: %m"); - } num_active_timeouts = 0; From 9877374bef76ef03923f6aa8b955f2dbcbe6c2c7 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 6 Jan 2021 18:28:42 -0500 Subject: [PATCH 052/240] Add idle_session_timeout. This GUC variable works much like idle_in_transaction_session_timeout, in that it kills sessions that have waited too long for a new client query. But it applies when we're not in a transaction, rather than when we are. Li Japin, reviewed by David Johnston and Hayato Kuroda, some fixes by me Discussion: https://postgr.es/m/763A0689-F189-459E-946F-F0EC4458980B@hotmail.com --- doc/src/sgml/config.sgml | 51 ++++++++++++++++--- src/backend/storage/lmgr/proc.c | 1 + src/backend/tcop/postgres.c | 48 ++++++++++++++--- src/backend/utils/errcodes.txt | 1 + src/backend/utils/init/globals.c | 1 + src/backend/utils/init/postinit.c | 10 ++++ src/backend/utils/misc/guc.c | 13 ++++- src/backend/utils/misc/postgresql.conf.sample | 1 + src/include/miscadmin.h | 1 + src/include/storage/proc.h | 1 + src/include/utils/timeout.h | 3 +- 11 files changed, 115 insertions(+), 16 deletions(-) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 425f57901d730..15b94c96c084d 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -8310,15 +8310,52 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv; - Terminate any session with an open transaction that has been idle for - longer than the specified amount of time. This allows any - locks held by that session to be released and the connection slot to be reused; - it also allows tuples visible only to this transaction to be vacuumed. See - for more details about this. + Terminate any session that has been idle (that is, waiting for a + client query) within an open transaction for longer than the + specified amount of time. + If this value is specified without units, it is taken as milliseconds. + A value of zero (the default) disables the timeout. + + + + This option can be used to ensure that idle sessions do not hold + locks for an unreasonable amount of time. Even when no significant + locks are held, an open transaction prevents vacuuming away + recently-dead tuples that may be visible only to this transaction; + so remaining idle for a long time can contribute to table bloat. + See for more details. + + + + + + idle_session_timeout (integer) + + idle_session_timeout configuration parameter + + + + + Terminate any session that has been idle (that is, waiting for a + client query), but not within an open transaction, for longer than + the specified amount of time. + If this value is specified without units, it is taken as milliseconds. + A value of zero (the default) disables the timeout. + + + Unlike the case with an open transaction, an idle session without a + transaction imposes no large costs on the server, so there is less + need to enable this timeout + than idle_in_transaction_session_timeout. + + - If this value is specified without units, it is taken as milliseconds. - A value of zero (the default) disables the timeout. + Be wary of enforcing this timeout on connections made through + connection-pooling software or other middleware, as such a layer + may not react well to unexpected connection closure. It may be + helpful to enable this timeout only for interactive sessions, + perhaps by applying it only to particular users. diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 9b6aa2fe0de05..0366a7cc004e4 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -61,6 +61,7 @@ int DeadlockTimeout = 1000; int StatementTimeout = 0; int LockTimeout = 0; int IdleInTransactionSessionTimeout = 0; +int IdleSessionTimeout = 0; bool log_lock_waits = false; /* Pointer to this process's PGPROC struct, if any */ diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 9d98c028a2ddd..2b53ebf97dc48 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3242,14 +3242,28 @@ ProcessInterrupts(void) if (IdleInTransactionSessionTimeoutPending) { - /* Has the timeout setting changed since last we looked? */ + /* + * If the GUC has been reset to zero, ignore the signal. This is + * important because the GUC update itself won't disable any pending + * interrupt. + */ if (IdleInTransactionSessionTimeout > 0) ereport(FATAL, (errcode(ERRCODE_IDLE_IN_TRANSACTION_SESSION_TIMEOUT), errmsg("terminating connection due to idle-in-transaction timeout"))); else IdleInTransactionSessionTimeoutPending = false; + } + if (IdleSessionTimeoutPending) + { + /* As above, ignore the signal if the GUC has been reset to zero. */ + if (IdleSessionTimeout > 0) + ereport(FATAL, + (errcode(ERRCODE_IDLE_SESSION_TIMEOUT), + errmsg("terminating connection due to idle-session timeout"))); + else + IdleSessionTimeoutPending = false; } if (ProcSignalBarrierPending) @@ -3826,7 +3840,8 @@ PostgresMain(int argc, char *argv[], StringInfoData input_message; sigjmp_buf local_sigjmp_buf; volatile bool send_ready_for_query = true; - bool disable_idle_in_transaction_timeout = false; + bool idle_in_transaction_timeout_enabled = false; + bool idle_session_timeout_enabled = false; /* Initialize startup process environment if necessary. */ if (!IsUnderPostmaster) @@ -4228,6 +4243,8 @@ PostgresMain(int argc, char *argv[], * processing of batched messages, and because we don't want to report * uncommitted updates (that confuses autovacuum). The notification * processor wants a call too, if we are not in a transaction block. + * + * Also, if an idle timeout is enabled, start the timer for that. */ if (send_ready_for_query) { @@ -4239,7 +4256,7 @@ PostgresMain(int argc, char *argv[], /* Start the idle-in-transaction timer */ if (IdleInTransactionSessionTimeout > 0) { - disable_idle_in_transaction_timeout = true; + idle_in_transaction_timeout_enabled = true; enable_timeout_after(IDLE_IN_TRANSACTION_SESSION_TIMEOUT, IdleInTransactionSessionTimeout); } @@ -4252,7 +4269,7 @@ PostgresMain(int argc, char *argv[], /* Start the idle-in-transaction timer */ if (IdleInTransactionSessionTimeout > 0) { - disable_idle_in_transaction_timeout = true; + idle_in_transaction_timeout_enabled = true; enable_timeout_after(IDLE_IN_TRANSACTION_SESSION_TIMEOUT, IdleInTransactionSessionTimeout); } @@ -4275,6 +4292,14 @@ PostgresMain(int argc, char *argv[], set_ps_display("idle"); pgstat_report_activity(STATE_IDLE, NULL); + + /* Start the idle-session timer */ + if (IdleSessionTimeout > 0) + { + idle_session_timeout_enabled = true; + enable_timeout_after(IDLE_SESSION_TIMEOUT, + IdleSessionTimeout); + } } /* Report any recently-changed GUC options */ @@ -4310,12 +4335,21 @@ PostgresMain(int argc, char *argv[], DoingCommandRead = false; /* - * (5) turn off the idle-in-transaction timeout + * (5) turn off the idle-in-transaction and idle-session timeouts, if + * active. + * + * At most one of these two will be active, so there's no need to + * worry about combining the timeout.c calls into one. */ - if (disable_idle_in_transaction_timeout) + if (idle_in_transaction_timeout_enabled) { disable_timeout(IDLE_IN_TRANSACTION_SESSION_TIMEOUT, false); - disable_idle_in_transaction_timeout = false; + idle_in_transaction_timeout_enabled = false; + } + if (idle_session_timeout_enabled) + { + disable_timeout(IDLE_SESSION_TIMEOUT, false); + idle_session_timeout_enabled = false; } /* diff --git a/src/backend/utils/errcodes.txt b/src/backend/utils/errcodes.txt index 64ca2deec9995..1d5a78e73d6b9 100644 --- a/src/backend/utils/errcodes.txt +++ b/src/backend/utils/errcodes.txt @@ -109,6 +109,7 @@ Section: Class 08 - Connection Exception 08004 E ERRCODE_SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION sqlserver_rejected_establishment_of_sqlconnection 08007 E ERRCODE_TRANSACTION_RESOLUTION_UNKNOWN transaction_resolution_unknown 08P01 E ERRCODE_PROTOCOL_VIOLATION protocol_violation +08P02 E ERRCODE_IDLE_SESSION_TIMEOUT idle_session_timeout Section: Class 09 - Triggered Action Exception diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c index 3d5d6cc033c66..ea28769d6a396 100644 --- a/src/backend/utils/init/globals.c +++ b/src/backend/utils/init/globals.c @@ -32,6 +32,7 @@ volatile sig_atomic_t QueryCancelPending = false; volatile sig_atomic_t ProcDiePending = false; volatile sig_atomic_t ClientConnectionLost = false; volatile sig_atomic_t IdleInTransactionSessionTimeoutPending = false; +volatile sig_atomic_t IdleSessionTimeoutPending = false; volatile sig_atomic_t ProcSignalBarrierPending = false; volatile uint32 InterruptHoldoffCount = 0; volatile uint32 QueryCancelHoldoffCount = 0; diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index 59b3f4b135988..e5965bc517dd9 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -72,6 +72,7 @@ static void ShutdownPostgres(int code, Datum arg); static void StatementTimeoutHandler(void); static void LockTimeoutHandler(void); static void IdleInTransactionSessionTimeoutHandler(void); +static void IdleSessionTimeoutHandler(void); static bool ThereIsAtLeastOneRole(void); static void process_startup_options(Port *port, bool am_superuser); static void process_settings(Oid databaseid, Oid roleid); @@ -619,6 +620,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username, RegisterTimeout(LOCK_TIMEOUT, LockTimeoutHandler); RegisterTimeout(IDLE_IN_TRANSACTION_SESSION_TIMEOUT, IdleInTransactionSessionTimeoutHandler); + RegisterTimeout(IDLE_SESSION_TIMEOUT, IdleSessionTimeoutHandler); } /* @@ -1233,6 +1235,14 @@ IdleInTransactionSessionTimeoutHandler(void) SetLatch(MyLatch); } +static void +IdleSessionTimeoutHandler(void) +{ + IdleSessionTimeoutPending = true; + InterruptPending = true; + SetLatch(MyLatch); +} + /* * Returns true if at least one role is defined in this database cluster. */ diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 1ccf7593eea33..daf9c127cde67 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -2509,7 +2509,7 @@ static struct config_int ConfigureNamesInt[] = { {"idle_in_transaction_session_timeout", PGC_USERSET, CLIENT_CONN_STATEMENT, - gettext_noop("Sets the maximum allowed duration of any idling transaction."), + gettext_noop("Sets the maximum allowed idle time between queries, when in a transaction."), gettext_noop("A value of 0 turns off the timeout."), GUC_UNIT_MS }, @@ -2518,6 +2518,17 @@ static struct config_int ConfigureNamesInt[] = NULL, NULL, NULL }, + { + {"idle_session_timeout", PGC_USERSET, CLIENT_CONN_STATEMENT, + gettext_noop("Sets the maximum allowed idle time between queries, when not in a transaction."), + gettext_noop("A value of 0 turns off the timeout."), + GUC_UNIT_MS + }, + &IdleSessionTimeout, + 0, 0, INT_MAX, + NULL, NULL, NULL + }, + { {"vacuum_freeze_min_age", PGC_USERSET, CLIENT_CONN_STATEMENT, gettext_noop("Minimum age at which VACUUM should freeze a table row."), diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 5298e18ecd558..033aa335a012b 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -663,6 +663,7 @@ #statement_timeout = 0 # in milliseconds, 0 is disabled #lock_timeout = 0 # in milliseconds, 0 is disabled #idle_in_transaction_session_timeout = 0 # in milliseconds, 0 is disabled +#idle_session_timeout = 0 # in milliseconds, 0 is disabled #vacuum_freeze_min_age = 50000000 #vacuum_freeze_table_age = 150000000 #vacuum_multixact_freeze_min_age = 5000000 diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index 2c71db79c0af2..1bdc97e3082d7 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -82,6 +82,7 @@ extern PGDLLIMPORT volatile sig_atomic_t InterruptPending; extern PGDLLIMPORT volatile sig_atomic_t QueryCancelPending; extern PGDLLIMPORT volatile sig_atomic_t ProcDiePending; extern PGDLLIMPORT volatile sig_atomic_t IdleInTransactionSessionTimeoutPending; +extern PGDLLIMPORT volatile sig_atomic_t IdleSessionTimeoutPending; extern PGDLLIMPORT volatile sig_atomic_t ProcSignalBarrierPending; extern PGDLLIMPORT volatile sig_atomic_t ClientConnectionLost; diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 989c5849d4583..0786fcf103a70 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -378,6 +378,7 @@ extern PGDLLIMPORT int DeadlockTimeout; extern PGDLLIMPORT int StatementTimeout; extern PGDLLIMPORT int LockTimeout; extern PGDLLIMPORT int IdleInTransactionSessionTimeout; +extern PGDLLIMPORT int IdleSessionTimeout; extern bool log_lock_waits; diff --git a/src/include/utils/timeout.h b/src/include/utils/timeout.h index 8adb4e14cacc1..ecb2a366a5f44 100644 --- a/src/include/utils/timeout.h +++ b/src/include/utils/timeout.h @@ -31,10 +31,11 @@ typedef enum TimeoutId STANDBY_TIMEOUT, STANDBY_LOCK_TIMEOUT, IDLE_IN_TRANSACTION_SESSION_TIMEOUT, + IDLE_SESSION_TIMEOUT, /* First user-definable timeout reason */ USER_TIMEOUT, /* Maximum number of timeout reasons */ - MAX_TIMEOUTS = 16 + MAX_TIMEOUTS = USER_TIMEOUT + 10 } TimeoutId; /* callback function signature */ From 55fe26a4b580b17d721c5accb842cc6a08295273 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Thu, 7 Jan 2021 10:21:02 +0900 Subject: [PATCH 053/240] Fix allocation logic of cryptohash context data with OpenSSL The allocation of the cryptohash context data when building with OpenSSL was happening in the memory context of the caller of pg_cryptohash_create(), which could lead to issues with resowner cleanup if cascading resources are cleaned up on an error. Like other facilities using resowners, move the base allocation to TopMemoryContext to ensure a correct cleanup on failure. The resulting code gets simpler with this commit as the context data is now hold by a unique opaque pointer, so as there is only one single allocation done in TopMemoryContext. After discussion, also change the cryptohash subroutines to return an error if the caller provides NULL for the context data to ease error detection on OOM. Author: Heikki Linnakangas Discussion: https://postgr.es/m/X9xbuEoiU3dlImfa@paquier.xyz --- src/common/cryptohash.c | 111 ++++++++++++------------------- src/common/cryptohash_openssl.c | 86 ++++++++++-------------- src/include/common/cryptohash.h | 8 +-- src/tools/pgindent/typedefs.list | 1 - 4 files changed, 81 insertions(+), 125 deletions(-) diff --git a/src/common/cryptohash.c b/src/common/cryptohash.c index 1921a33b34e41..efedadd6263d2 100644 --- a/src/common/cryptohash.c +++ b/src/common/cryptohash.c @@ -39,6 +39,21 @@ #define FREE(ptr) free(ptr) #endif +/* Internal pg_cryptohash_ctx structure */ +struct pg_cryptohash_ctx +{ + pg_cryptohash_type type; + + union + { + pg_md5_ctx md5; + pg_sha224_ctx sha224; + pg_sha256_ctx sha256; + pg_sha384_ctx sha384; + pg_sha512_ctx sha512; + } data; +}; + /* * pg_cryptohash_create * @@ -50,38 +65,18 @@ pg_cryptohash_create(pg_cryptohash_type type) { pg_cryptohash_ctx *ctx; + /* + * Note that this always allocates enough space for the largest hash. A + * smaller allocation would be enough for md5, sha224 and sha256, but the + * small extra amount of memory does not make it worth complicating this + * code. + */ ctx = ALLOC(sizeof(pg_cryptohash_ctx)); if (ctx == NULL) return NULL; - + memset(ctx, 0, sizeof(pg_cryptohash_ctx)); ctx->type = type; - switch (type) - { - case PG_MD5: - ctx->data = ALLOC(sizeof(pg_md5_ctx)); - break; - case PG_SHA224: - ctx->data = ALLOC(sizeof(pg_sha224_ctx)); - break; - case PG_SHA256: - ctx->data = ALLOC(sizeof(pg_sha256_ctx)); - break; - case PG_SHA384: - ctx->data = ALLOC(sizeof(pg_sha384_ctx)); - break; - case PG_SHA512: - ctx->data = ALLOC(sizeof(pg_sha512_ctx)); - break; - } - - if (ctx->data == NULL) - { - explicit_bzero(ctx, sizeof(pg_cryptohash_ctx)); - FREE(ctx); - return NULL; - } - return ctx; } @@ -95,24 +90,24 @@ int pg_cryptohash_init(pg_cryptohash_ctx *ctx) { if (ctx == NULL) - return 0; + return -1; switch (ctx->type) { case PG_MD5: - pg_md5_init((pg_md5_ctx *) ctx->data); + pg_md5_init(&ctx->data.md5); break; case PG_SHA224: - pg_sha224_init((pg_sha224_ctx *) ctx->data); + pg_sha224_init(&ctx->data.sha224); break; case PG_SHA256: - pg_sha256_init((pg_sha256_ctx *) ctx->data); + pg_sha256_init(&ctx->data.sha256); break; case PG_SHA384: - pg_sha384_init((pg_sha384_ctx *) ctx->data); + pg_sha384_init(&ctx->data.sha384); break; case PG_SHA512: - pg_sha512_init((pg_sha512_ctx *) ctx->data); + pg_sha512_init(&ctx->data.sha512); break; } @@ -123,30 +118,31 @@ pg_cryptohash_init(pg_cryptohash_ctx *ctx) * pg_cryptohash_update * * Update a hash context. Note that this implementation is designed - * to never fail, so this always returns 0. + * to never fail, so this always returns 0 except if the caller has + * given a NULL context. */ int pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len) { if (ctx == NULL) - return 0; + return -1; switch (ctx->type) { case PG_MD5: - pg_md5_update((pg_md5_ctx *) ctx->data, data, len); + pg_md5_update(&ctx->data.md5, data, len); break; case PG_SHA224: - pg_sha224_update((pg_sha224_ctx *) ctx->data, data, len); + pg_sha224_update(&ctx->data.sha224, data, len); break; case PG_SHA256: - pg_sha256_update((pg_sha256_ctx *) ctx->data, data, len); + pg_sha256_update(&ctx->data.sha256, data, len); break; case PG_SHA384: - pg_sha384_update((pg_sha384_ctx *) ctx->data, data, len); + pg_sha384_update(&ctx->data.sha384, data, len); break; case PG_SHA512: - pg_sha512_update((pg_sha512_ctx *) ctx->data, data, len); + pg_sha512_update(&ctx->data.sha512, data, len); break; } @@ -157,30 +153,31 @@ pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len) * pg_cryptohash_final * * Finalize a hash context. Note that this implementation is designed - * to never fail, so this always returns 0. + * to never fail, so this always returns 0 except if the caller has + * given a NULL context. */ int pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest) { if (ctx == NULL) - return 0; + return -1; switch (ctx->type) { case PG_MD5: - pg_md5_final((pg_md5_ctx *) ctx->data, dest); + pg_md5_final(&ctx->data.md5, dest); break; case PG_SHA224: - pg_sha224_final((pg_sha224_ctx *) ctx->data, dest); + pg_sha224_final(&ctx->data.sha224, dest); break; case PG_SHA256: - pg_sha256_final((pg_sha256_ctx *) ctx->data, dest); + pg_sha256_final(&ctx->data.sha256, dest); break; case PG_SHA384: - pg_sha384_final((pg_sha384_ctx *) ctx->data, dest); + pg_sha384_final(&ctx->data.sha384, dest); break; case PG_SHA512: - pg_sha512_final((pg_sha512_ctx *) ctx->data, dest); + pg_sha512_final(&ctx->data.sha512, dest); break; } @@ -198,26 +195,6 @@ pg_cryptohash_free(pg_cryptohash_ctx *ctx) if (ctx == NULL) return; - switch (ctx->type) - { - case PG_MD5: - explicit_bzero(ctx->data, sizeof(pg_md5_ctx)); - break; - case PG_SHA224: - explicit_bzero(ctx->data, sizeof(pg_sha224_ctx)); - break; - case PG_SHA256: - explicit_bzero(ctx->data, sizeof(pg_sha256_ctx)); - break; - case PG_SHA384: - explicit_bzero(ctx->data, sizeof(pg_sha384_ctx)); - break; - case PG_SHA512: - explicit_bzero(ctx->data, sizeof(pg_sha512_ctx)); - break; - } - - FREE(ctx->data); explicit_bzero(ctx, sizeof(pg_cryptohash_ctx)); FREE(ctx); } diff --git a/src/common/cryptohash_openssl.c b/src/common/cryptohash_openssl.c index 0fd6622576446..551ec392b60f3 100644 --- a/src/common/cryptohash_openssl.c +++ b/src/common/cryptohash_openssl.c @@ -31,11 +31,12 @@ #endif /* - * In backend, use palloc/pfree to ease the error handling. In frontend, - * use malloc to be able to return a failure status back to the caller. + * In the backend, use an allocation in TopMemoryContext to count for + * resowner cleanup handling. In the frontend, use malloc to be able + * to return a failure status back to the caller. */ #ifndef FRONTEND -#define ALLOC(size) palloc(size) +#define ALLOC(size) MemoryContextAlloc(TopMemoryContext, size) #define FREE(ptr) pfree(ptr) #else #define ALLOC(size) malloc(size) @@ -43,19 +44,21 @@ #endif /* - * Internal structure for pg_cryptohash_ctx->data. + * Internal pg_cryptohash_ctx structure. * * This tracks the resource owner associated to each EVP context data * for the backend. */ -typedef struct pg_cryptohash_state +struct pg_cryptohash_ctx { + pg_cryptohash_type type; + EVP_MD_CTX *evpctx; #ifndef FRONTEND ResourceOwner resowner; #endif -} pg_cryptohash_state; +}; /* * pg_cryptohash_create @@ -67,49 +70,42 @@ pg_cryptohash_ctx * pg_cryptohash_create(pg_cryptohash_type type) { pg_cryptohash_ctx *ctx; - pg_cryptohash_state *state; + + /* + * Make sure that the resource owner has space to remember this reference. + * This can error out with "out of memory", so do this before any other + * allocation to avoid leaking. + */ +#ifndef FRONTEND + ResourceOwnerEnlargeCryptoHash(CurrentResourceOwner); +#endif ctx = ALLOC(sizeof(pg_cryptohash_ctx)); if (ctx == NULL) return NULL; - - state = ALLOC(sizeof(pg_cryptohash_state)); - if (state == NULL) - { - explicit_bzero(ctx, sizeof(pg_cryptohash_ctx)); - FREE(ctx); - return NULL; - } - - ctx->data = state; + memset(ctx, 0, sizeof(pg_cryptohash_ctx)); ctx->type = type; -#ifndef FRONTEND - ResourceOwnerEnlargeCryptoHash(CurrentResourceOwner); -#endif - /* * Initialization takes care of assigning the correct type for OpenSSL. */ - state->evpctx = EVP_MD_CTX_create(); + ctx->evpctx = EVP_MD_CTX_create(); - if (state->evpctx == NULL) + if (ctx->evpctx == NULL) { - explicit_bzero(state, sizeof(pg_cryptohash_state)); explicit_bzero(ctx, sizeof(pg_cryptohash_ctx)); + FREE(ctx); #ifndef FRONTEND ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); #else - FREE(state); - FREE(ctx); return NULL; #endif } #ifndef FRONTEND - state->resowner = CurrentResourceOwner; + ctx->resowner = CurrentResourceOwner; ResourceOwnerRememberCryptoHash(CurrentResourceOwner, PointerGetDatum(ctx)); #endif @@ -126,29 +122,26 @@ int pg_cryptohash_init(pg_cryptohash_ctx *ctx) { int status = 0; - pg_cryptohash_state *state; if (ctx == NULL) - return 0; - - state = (pg_cryptohash_state *) ctx->data; + return -1; switch (ctx->type) { case PG_MD5: - status = EVP_DigestInit_ex(state->evpctx, EVP_md5(), NULL); + status = EVP_DigestInit_ex(ctx->evpctx, EVP_md5(), NULL); break; case PG_SHA224: - status = EVP_DigestInit_ex(state->evpctx, EVP_sha224(), NULL); + status = EVP_DigestInit_ex(ctx->evpctx, EVP_sha224(), NULL); break; case PG_SHA256: - status = EVP_DigestInit_ex(state->evpctx, EVP_sha256(), NULL); + status = EVP_DigestInit_ex(ctx->evpctx, EVP_sha256(), NULL); break; case PG_SHA384: - status = EVP_DigestInit_ex(state->evpctx, EVP_sha384(), NULL); + status = EVP_DigestInit_ex(ctx->evpctx, EVP_sha384(), NULL); break; case PG_SHA512: - status = EVP_DigestInit_ex(state->evpctx, EVP_sha512(), NULL); + status = EVP_DigestInit_ex(ctx->evpctx, EVP_sha512(), NULL); break; } @@ -167,13 +160,11 @@ int pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len) { int status = 0; - pg_cryptohash_state *state; if (ctx == NULL) - return 0; + return -1; - state = (pg_cryptohash_state *) ctx->data; - status = EVP_DigestUpdate(state->evpctx, data, len); + status = EVP_DigestUpdate(ctx->evpctx, data, len); /* OpenSSL internals return 1 on success, 0 on failure */ if (status <= 0) @@ -190,13 +181,11 @@ int pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest) { int status = 0; - pg_cryptohash_state *state; if (ctx == NULL) - return 0; + return -1; - state = (pg_cryptohash_state *) ctx->data; - status = EVP_DigestFinal_ex(state->evpctx, dest, 0); + status = EVP_DigestFinal_ex(ctx->evpctx, dest, 0); /* OpenSSL internals return 1 on success, 0 on failure */ if (status <= 0) @@ -212,21 +201,16 @@ pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest) void pg_cryptohash_free(pg_cryptohash_ctx *ctx) { - pg_cryptohash_state *state; - if (ctx == NULL) return; - state = (pg_cryptohash_state *) ctx->data; - EVP_MD_CTX_destroy(state->evpctx); + EVP_MD_CTX_destroy(ctx->evpctx); #ifndef FRONTEND - ResourceOwnerForgetCryptoHash(state->resowner, + ResourceOwnerForgetCryptoHash(ctx->resowner, PointerGetDatum(ctx)); #endif - explicit_bzero(state, sizeof(pg_cryptohash_state)); explicit_bzero(ctx, sizeof(pg_cryptohash_ctx)); - FREE(state); FREE(ctx); } diff --git a/src/include/common/cryptohash.h b/src/include/common/cryptohash.h index 4c3df8e5ae64b..3ecaf62113514 100644 --- a/src/include/common/cryptohash.h +++ b/src/include/common/cryptohash.h @@ -25,12 +25,8 @@ typedef enum PG_SHA512 } pg_cryptohash_type; -typedef struct pg_cryptohash_ctx -{ - pg_cryptohash_type type; - /* private area used by each hash implementation */ - void *data; -} pg_cryptohash_ctx; +/* opaque context, private to each cryptohash implementation */ +typedef struct pg_cryptohash_ctx pg_cryptohash_ctx; extern pg_cryptohash_ctx *pg_cryptohash_create(pg_cryptohash_type type); extern int pg_cryptohash_init(pg_cryptohash_ctx *ctx); diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 9cd047ba25ea6..f3957bad6c290 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -3196,7 +3196,6 @@ pg_conv_map pg_crc32 pg_crc32c pg_cryptohash_ctx -pg_cryptohash_state pg_cryptohash_type pg_ctype_cache pg_enc From 9486e7b666fd113f043d5f091fd42bc1ef72acd8 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 6 Jan 2021 22:02:35 -0500 Subject: [PATCH 054/240] Improve commentary in timeout.c. On re-reading I realized that I'd missed one race condition in the new timeout code. It's safe, but add a comment explaining it. Discussion: https://postgr.es/m/CA+hUKG+o6pbuHBJSGnud=TadsuXySWA7CCcPgCt2QE9F6_4iHQ@mail.gmail.com --- src/backend/utils/misc/timeout.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/backend/utils/misc/timeout.c b/src/backend/utils/misc/timeout.c index 88139ab82b688..95a273d9cfbdb 100644 --- a/src/backend/utils/misc/timeout.c +++ b/src/backend/utils/misc/timeout.c @@ -307,7 +307,14 @@ schedule_alarm(TimestampTz now) * signal is still coming. * * Other race conditions involved with setting/checking signal_pending - * are okay, for the reasons described above. + * are okay, for the reasons described above. One additional point is + * that the signal handler could fire after we set signal_due_at, but + * still before the setitimer() call. Then the handler could + * overwrite signal_due_at with a value it computes, which will be the + * same as or perhaps later than what we just computed. After we + * perform setitimer(), the net effect would be that signal_due_at + * gives a time later than when the interrupt will really happen; + * which is a safe situation. */ signal_due_at = nearest_timeout; signal_pending = true; From f7a1a805cb178653ea2a6c8991ad73b035af953e Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 6 Jan 2021 22:09:00 -0500 Subject: [PATCH 055/240] Fix bogus link in test comments. I apparently copied-and-pasted the wrong link in commit ca8217c10. Point it where it was meant to go. --- src/test/modules/test_regex/expected/test_regex.out | 2 +- src/test/modules/test_regex/sql/test_regex.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/modules/test_regex/expected/test_regex.out b/src/test/modules/test_regex/expected/test_regex.out index b62cbac697daf..ed1b0cbdb9b11 100644 --- a/src/test/modules/test_regex/expected/test_regex.out +++ b/src/test/modules/test_regex/expected/test_regex.out @@ -506,7 +506,7 @@ ERROR: invalid regular expression: quantifier operand invalid select * from test_regex('?', '', '-'); ERROR: invalid regular expression: quantifier operand invalid -- These two are not yet incorporated in Tcl, cf --- https://core.tcl-lang.org/tcl/artifact/106269fa65d96b83 +-- https://core.tcl-lang.org/tcl/tktview?name=5ea71fdcd3291c38 -- expectError 6.21 - {x(\w)(?=(\1))} ESUBREG select * from test_regex('x(\w)(?=(\1))', '', '-'); ERROR: invalid regular expression: invalid backreference number diff --git a/src/test/modules/test_regex/sql/test_regex.sql b/src/test/modules/test_regex/sql/test_regex.sql index 272dfc0cd6001..4676cd1a06075 100644 --- a/src/test/modules/test_regex/sql/test_regex.sql +++ b/src/test/modules/test_regex/sql/test_regex.sql @@ -171,7 +171,7 @@ select * from test_regex('+', '', '-'); select * from test_regex('?', '', '-'); -- These two are not yet incorporated in Tcl, cf --- https://core.tcl-lang.org/tcl/artifact/106269fa65d96b83 +-- https://core.tcl-lang.org/tcl/tktview?name=5ea71fdcd3291c38 -- expectError 6.21 - {x(\w)(?=(\1))} ESUBREG select * from test_regex('x(\w)(?=(\1))', '', '-'); -- expectMatch 6.22 HP {x(?=((foo)))} xfoo x From 0650ff23038bc3eb8d8fd851744db837d921e285 Mon Sep 17 00:00:00 2001 From: Fujii Masao Date: Fri, 8 Jan 2021 00:47:03 +0900 Subject: [PATCH 056/240] Add GUC to log long wait times on recovery conflicts. This commit adds GUC log_recovery_conflict_waits that controls whether a log message is produced when the startup process is waiting longer than deadlock_timeout for recovery conflicts. This is useful in determining if recovery conflicts prevent the recovery from applying WAL. Note that currently a log message is produced only when recovery conflict has not been resolved yet even after deadlock_timeout passes, i.e., only when the startup process is still waiting for recovery conflict even after deadlock_timeout. Author: Bertrand Drouvot, Masahiko Sawada Reviewed-by: Alvaro Herrera, Kyotaro Horiguchi, Fujii Masao Discussion: https://postgr.es/m/9a60178c-a853-1440-2cdc-c3af916cff59@amazon.com --- doc/src/sgml/config.sgml | 22 ++ doc/src/sgml/high-availability.sgml | 6 + src/backend/storage/buffer/bufmgr.c | 30 +++ src/backend/storage/ipc/standby.c | 199 +++++++++++++++--- src/backend/storage/lmgr/proc.c | 48 ++++- src/backend/utils/misc/guc.c | 10 +- src/backend/utils/misc/postgresql.conf.sample | 2 + src/include/storage/standby.h | 5 +- 8 files changed, 292 insertions(+), 30 deletions(-) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 15b94c96c084d..7c0a673a8dd42 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -6952,6 +6952,28 @@ log_line_prefix = '%m [%p] %q%u@%d/%a ' + + log_recovery_conflict_waits (boolean) + + log_recovery_conflict_waits configuration parameter + + + + + Controls whether a log message is produced when the startup process + is waiting longer than deadlock_timeout + for recovery conflicts. This is useful in determining if recovery + conflicts prevent the recovery from applying WAL. + + + + The default is off. This parameter can only be set + in the postgresql.conf file or on the server + command line. + + + + log_parameter_max_length (integer) diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml index 04f75020e44cb..efc382cb8d247 100644 --- a/doc/src/sgml/high-availability.sgml +++ b/doc/src/sgml/high-availability.sgml @@ -2071,6 +2071,12 @@ if (!triggered) server. The pg_stat_database system view also contains summary information.
+ + + Users can control whether a log message is produced when WAL replay is waiting + longer than deadlock_timeout for conflicts. This + is controlled by the parameter. + diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 8f2c482bc8433..71b5852224fcc 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -3809,6 +3809,8 @@ LockBufferForCleanup(Buffer buffer) { BufferDesc *bufHdr; char *new_status = NULL; + TimestampTz waitStart = 0; + bool logged_recovery_conflict = false; Assert(BufferIsPinned(buffer)); Assert(PinCountWaitBuf == NULL); @@ -3882,6 +3884,34 @@ LockBufferForCleanup(Buffer buffer) new_status[len] = '\0'; /* truncate off " waiting" */ } + /* + * Emit the log message if the startup process is waiting longer + * than deadlock_timeout for recovery conflict on buffer pin. + * + * Skip this if first time through because the startup process has + * not started waiting yet in this case. So, the wait start + * timestamp is set after this logic. + */ + if (waitStart != 0 && !logged_recovery_conflict) + { + TimestampTz now = GetCurrentTimestamp(); + + if (TimestampDifferenceExceeds(waitStart, now, + DeadlockTimeout)) + { + LogRecoveryConflict(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN, + waitStart, now, NULL); + logged_recovery_conflict = true; + } + } + + /* + * Set the wait start timestamp if logging is enabled and first + * time through. + */ + if (log_recovery_conflict_waits && waitStart == 0) + waitStart = GetCurrentTimestamp(); + /* Publish the bufid that Startup process waits on */ SetStartupBufferPinWaitBufId(buffer - 1); /* Set alarm and then wait to be signaled by UnpinBuffer() */ diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c index 77e81bdbc0f5e..d4b0f65ba20ba 100644 --- a/src/backend/storage/ipc/standby.c +++ b/src/backend/storage/ipc/standby.c @@ -39,6 +39,7 @@ int vacuum_defer_cleanup_age; int max_standby_archive_delay = 30 * 1000; int max_standby_streaming_delay = 30 * 1000; +bool log_recovery_conflict_waits = false; static HTAB *RecoveryLockLists; @@ -53,6 +54,7 @@ static void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlis static void SendRecoveryConflictWithBufferPin(ProcSignalReason reason); static XLogRecPtr LogCurrentRunningXacts(RunningTransactions CurrRunningXacts); static void LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks); +static const char *get_recovery_conflict_desc(ProcSignalReason reason); /* * Keep track of all the locks owned by a given transaction. @@ -218,15 +220,83 @@ WaitExceedsMaxStandbyDelay(uint32 wait_event_info) return false; } +/* + * Log the recovery conflict. + * + * wait_start is the timestamp when the caller started to wait. + * now is the timestamp when this function has been called. + * wait_list is the list of virtual transaction ids assigned to + * conflicting processes. + */ +void +LogRecoveryConflict(ProcSignalReason reason, TimestampTz wait_start, + TimestampTz now, VirtualTransactionId *wait_list) +{ + long secs; + int usecs; + long msecs; + StringInfoData buf; + int nprocs = 0; + + TimestampDifference(wait_start, now, &secs, &usecs); + msecs = secs * 1000 + usecs / 1000; + usecs = usecs % 1000; + + if (wait_list) + { + VirtualTransactionId *vxids; + + /* Construct a string of list of the conflicting processes */ + vxids = wait_list; + while (VirtualTransactionIdIsValid(*vxids)) + { + PGPROC *proc = BackendIdGetProc(vxids->backendId); + + /* proc can be NULL if the target backend is not active */ + if (proc) + { + if (nprocs == 0) + { + initStringInfo(&buf); + appendStringInfo(&buf, "%d", proc->pid); + } + else + appendStringInfo(&buf, ", %d", proc->pid); + + nprocs++; + } + + vxids++; + } + } + + /* + * If wait_list is specified, report the list of PIDs of active + * conflicting backends in a detail message. Note that if all the backends + * in the list are not active, no detail message is logged. + */ + ereport(LOG, + errmsg("recovery still waiting after %ld.%03d ms: %s", + msecs, usecs, _(get_recovery_conflict_desc(reason))), + nprocs > 0 ? errdetail_log_plural("Conflicting process: %s.", + "Conflicting processes: %s.", + nprocs, buf.data) : 0); + + if (nprocs > 0) + pfree(buf.data); +} + /* * This is the main executioner for any query backend that conflicts with * recovery processing. Judgement has already been passed on it within * a specific rmgr. Here we just issue the orders to the procs. The procs * then throw the required error as instructed. * - * If report_waiting is true, "waiting" is reported in PS display if necessary. - * If the caller has already reported that, report_waiting should be false. - * Otherwise, "waiting" is reported twice unexpectedly. + * If report_waiting is true, "waiting" is reported in PS display and the + * wait for recovery conflict is reported in the log, if necessary. If + * the caller is responsible for reporting them, report_waiting should be + * false. Otherwise, both the caller and this function report the same + * thing unexpectedly. */ static void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, @@ -234,15 +304,16 @@ ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, bool report_waiting) { TimestampTz waitStart = 0; - char *new_status; + char *new_status = NULL; + bool logged_recovery_conflict = false; /* Fast exit, to avoid a kernel call if there's no work to be done. */ if (!VirtualTransactionIdIsValid(*waitlist)) return; - if (report_waiting) + /* Set the wait start timestamp for reporting */ + if (report_waiting && (log_recovery_conflict_waits || update_process_title)) waitStart = GetCurrentTimestamp(); - new_status = NULL; /* we haven't changed the ps display */ while (VirtualTransactionIdIsValid(*waitlist)) { @@ -252,25 +323,6 @@ ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, /* wait until the virtual xid is gone */ while (!VirtualXactLock(*waitlist, false)) { - /* - * Report via ps if we have been waiting for more than 500 msec - * (should that be configurable?) - */ - if (update_process_title && new_status == NULL && report_waiting && - TimestampDifferenceExceeds(waitStart, GetCurrentTimestamp(), - 500)) - { - const char *old_status; - int len; - - old_status = get_ps_display(&len); - new_status = (char *) palloc(len + 8 + 1); - memcpy(new_status, old_status, len); - strcpy(new_status + len, " waiting"); - set_ps_display(new_status); - new_status[len] = '\0'; /* truncate off " waiting" */ - } - /* Is it time to kill it? */ if (WaitExceedsMaxStandbyDelay(wait_event_info)) { @@ -289,6 +341,50 @@ ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, if (pid != 0) pg_usleep(5000L); } + + if (waitStart != 0 && (!logged_recovery_conflict || new_status == NULL)) + { + TimestampTz now = 0; + bool maybe_log_conflict; + bool maybe_update_title; + + maybe_log_conflict = (log_recovery_conflict_waits && !logged_recovery_conflict); + maybe_update_title = (update_process_title && new_status == NULL); + + /* Get the current timestamp if not report yet */ + if (maybe_log_conflict || maybe_update_title) + now = GetCurrentTimestamp(); + + /* + * Report via ps if we have been waiting for more than 500 + * msec (should that be configurable?) + */ + if (maybe_update_title && + TimestampDifferenceExceeds(waitStart, now, 500)) + { + const char *old_status; + int len; + + old_status = get_ps_display(&len); + new_status = (char *) palloc(len + 8 + 1); + memcpy(new_status, old_status, len); + strcpy(new_status + len, " waiting"); + set_ps_display(new_status); + new_status[len] = '\0'; /* truncate off " waiting" */ + } + + /* + * Emit the log message if the startup process is waiting + * longer than deadlock_timeout for recovery conflict on + * buffer pin. + */ + if (maybe_log_conflict && + TimestampDifferenceExceeds(waitStart, now, DeadlockTimeout)) + { + LogRecoveryConflict(reason, waitStart, now, waitlist); + logged_recovery_conflict = true; + } + } } /* The virtual transaction is gone now, wait for the next one */ @@ -405,9 +501,18 @@ ResolveRecoveryConflictWithDatabase(Oid dbid) * hot-standby backend processes. If deadlock_timeout is reached in * this function, all the backends holding the conflicting locks are * requested to check themselves for deadlocks. + * + * logging_conflict should be true if the recovery conflict has not been + * logged yet even though logging is enabled. After deadlock_timeout is + * reached and the request for deadlock check is sent, we wait again to + * be signaled by the release of the lock if logging_conflict is false. + * Otherwise we return without waiting again so that the caller can report + * the recovery conflict. In this case, then, this function is called again + * with logging_conflict=false (because the recovery conflict has already + * been logged) and we will wait again for the lock to be released. */ void -ResolveRecoveryConflictWithLock(LOCKTAG locktag) +ResolveRecoveryConflictWithLock(LOCKTAG locktag, bool logging_conflict) { TimestampTz ltime; @@ -494,6 +599,15 @@ ResolveRecoveryConflictWithLock(LOCKTAG locktag) backends++; } + /* + * Exit if the recovery conflict has not been logged yet even though + * logging is enabled, so that the caller can log that. Then + * RecoveryConflictWithLock() is called again and we will wait again + * for the lock to be released. + */ + if (logging_conflict) + goto cleanup; + /* * Wait again here to be signaled by the release of the Relation Lock, * to prevent the subsequent RecoveryConflictWithLock() from causing @@ -1209,3 +1323,36 @@ LogStandbyInvalidations(int nmsgs, SharedInvalidationMessage *msgs, nmsgs * sizeof(SharedInvalidationMessage)); XLogInsert(RM_STANDBY_ID, XLOG_INVALIDATIONS); } + +/* Return the description of recovery conflict */ +static const char * +get_recovery_conflict_desc(ProcSignalReason reason) +{ + const char *reasonDesc = gettext_noop("unknown reason"); + + switch (reason) + { + case PROCSIG_RECOVERY_CONFLICT_BUFFERPIN: + reasonDesc = gettext_noop("recovery conflict on buffer pin"); + break; + case PROCSIG_RECOVERY_CONFLICT_LOCK: + reasonDesc = gettext_noop("recovery conflict on lock"); + break; + case PROCSIG_RECOVERY_CONFLICT_TABLESPACE: + reasonDesc = gettext_noop("recovery conflict on tablespace"); + break; + case PROCSIG_RECOVERY_CONFLICT_SNAPSHOT: + reasonDesc = gettext_noop("recovery conflict on snapshot"); + break; + case PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK: + reasonDesc = gettext_noop("recovery conflict on buffer deadlock"); + break; + case PROCSIG_RECOVERY_CONFLICT_DATABASE: + reasonDesc = gettext_noop("recovery conflict on database"); + break; + default: + break; + } + + return reasonDesc; +} diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 0366a7cc004e4..db0cfaa360031 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -1064,8 +1064,10 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable) LWLock *partitionLock = LockHashPartitionLock(hashcode); PROC_QUEUE *waitQueue = &(lock->waitProcs); LOCKMASK myHeldLocks = MyProc->heldLocks; + TimestampTz standbyWaitStart = 0; bool early_deadlock = false; bool allow_autovacuum_cancel = true; + bool logged_recovery_conflict = false; ProcWaitStatus myWaitStatus; PGPROC *proc; PGPROC *leader = MyProc->lockGroupLeader; @@ -1261,6 +1263,14 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable) else enable_timeout_after(DEADLOCK_TIMEOUT, DeadlockTimeout); } + else if (log_recovery_conflict_waits) + { + /* + * Set the wait start timestamp if logging is enabled and in hot + * standby. + */ + standbyWaitStart = GetCurrentTimestamp(); + } /* * If somebody wakes us between LWLockRelease and WaitLatch, the latch @@ -1280,8 +1290,42 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable) { if (InHotStandby) { - /* Set a timer and wait for that or for the Lock to be granted */ - ResolveRecoveryConflictWithLock(locallock->tag.lock); + bool maybe_log_conflict = + (standbyWaitStart != 0 && !logged_recovery_conflict); + + /* Set a timer and wait for that or for the lock to be granted */ + ResolveRecoveryConflictWithLock(locallock->tag.lock, + maybe_log_conflict); + + /* + * Emit the log message if the startup process is waiting longer + * than deadlock_timeout for recovery conflict on lock. + */ + if (maybe_log_conflict) + { + TimestampTz now = GetCurrentTimestamp(); + + if (TimestampDifferenceExceeds(standbyWaitStart, now, + DeadlockTimeout)) + { + VirtualTransactionId *vxids; + int cnt; + + vxids = GetLockConflicts(&locallock->tag.lock, + AccessExclusiveLock, &cnt); + + /* + * Log the recovery conflict and the list of PIDs of + * backends holding the conflicting lock. Note that we do + * logging even if there are no such backends right now + * because the startup process here has already waited + * longer than deadlock_timeout. + */ + LogRecoveryConflict(PROCSIG_RECOVERY_CONFLICT_LOCK, + standbyWaitStart, now, cnt > 0 ? vxids : NULL); + logged_recovery_conflict = true; + } + } } else { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index daf9c127cde67..17579eeaca9c6 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1573,7 +1573,15 @@ static struct config_bool ConfigureNamesBool[] = false, NULL, NULL, NULL }, - + { + {"log_recovery_conflict_waits", PGC_SIGHUP, LOGGING_WHAT, + gettext_noop("Logs standby recovery conflict waits."), + NULL + }, + &log_recovery_conflict_waits, + false, + NULL, NULL, NULL + }, { {"log_hostname", PGC_SIGHUP, LOGGING_WHAT, gettext_noop("Logs the host name in the connection logs."), diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 033aa335a012b..8930a94fff5a5 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -552,6 +552,8 @@ # %% = '%' # e.g. '<%u%%%d> ' #log_lock_waits = off # log lock waits >= deadlock_timeout +#log_recovery_conflict_waits = off # log standby recovery conflict waits + # >= deadlock_timeout #log_parameter_max_length = -1 # when logging statements, limit logged # bind-parameter values to N bytes; # -1 means print in full, 0 disables diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h index 9b5cc01c97b53..a0f3e0bdf09e1 100644 --- a/src/include/storage/standby.h +++ b/src/include/storage/standby.h @@ -23,6 +23,7 @@ extern int vacuum_defer_cleanup_age; extern int max_standby_archive_delay; extern int max_standby_streaming_delay; +extern bool log_recovery_conflict_waits; extern void InitRecoveryTransactionEnvironment(void); extern void ShutdownRecoveryTransactionEnvironment(void); @@ -32,12 +33,14 @@ extern void ResolveRecoveryConflictWithSnapshot(TransactionId latestRemovedXid, extern void ResolveRecoveryConflictWithTablespace(Oid tsid); extern void ResolveRecoveryConflictWithDatabase(Oid dbid); -extern void ResolveRecoveryConflictWithLock(LOCKTAG locktag); +extern void ResolveRecoveryConflictWithLock(LOCKTAG locktag, bool logging_conflict); extern void ResolveRecoveryConflictWithBufferPin(void); extern void CheckRecoveryConflictDeadlock(void); extern void StandbyDeadLockHandler(void); extern void StandbyTimeoutHandler(void); extern void StandbyLockTimeoutHandler(void); +extern void LogRecoveryConflict(ProcSignalReason reason, TimestampTz wait_start, + TimestampTz cur_ts, VirtualTransactionId *wait_list); /* * Standby Rmgr (RM_STANDBY_ID) From ebb5457cfa514972847a2d03b5b4fd46f69bdc9b Mon Sep 17 00:00:00 2001 From: Tomas Vondra Date: Thu, 7 Jan 2021 17:31:58 +0100 Subject: [PATCH 057/240] Minor fixes in COPY progress docs Author: Justin Pryzby Discussion: https://postgr.es/m/CAFp7Qwr6_FmRM6pCO0x_a0mymOfX_Gg+FEKet4XaTGSW=LitKQ@mail.gmail.com --- doc/src/sgml/monitoring.sgml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index 43fe8ae383eb9..3cdb1aff3c8fc 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -6414,9 +6414,9 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid, Whenever COPY is running, the pg_stat_progress_copy view will contain one row - for each backend that is currently running COPY command. - The table bellow describes the information that will be reported and provide - information how to interpret it. + for each backend that is currently running a COPY command. + The table below describes the information that will be reported and provides + information about how to interpret it. @@ -6445,7 +6445,7 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid, - datid text + datid oid OID of the database to which this backend is connected. @@ -6467,7 +6467,7 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid, OID of the table on which the COPY command is executed. - It is set to 0 if SELECT query is provided. + It is set to 0 if copying from a SELECT query. From b8d0cda53377515ac61357ec4a60e85ca873f486 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 7 Jan 2021 11:45:08 -0500 Subject: [PATCH 058/240] Further second thoughts about idle_session_timeout patch. On reflection, the order of operations in PostgresMain() is wrong. These timeouts ought to be shut down before, not after, we do the post-command-read CHECK_FOR_INTERRUPTS, to guarantee that any timeout error will be detected there rather than at some ill-defined later point (possibly after having wasted a lot of work). This is really an error in the original idle_in_transaction_timeout patch, so back-patch to 9.6 where that was introduced. --- src/backend/tcop/postgres.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2b53ebf97dc48..28055680aad73 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -4323,22 +4323,11 @@ PostgresMain(int argc, char *argv[], firstchar = ReadCommand(&input_message); /* - * (4) disable async signal conditions again. + * (4) turn off the idle-in-transaction and idle-session timeouts, if + * active. We do this before step (5) so that any last-moment timeout + * is certain to be detected in step (5). * - * Query cancel is supposed to be a no-op when there is no query in - * progress, so if a query cancel arrived while we were idle, just - * reset QueryCancelPending. ProcessInterrupts() has that effect when - * it's called when DoingCommandRead is set, so check for interrupts - * before resetting DoingCommandRead. - */ - CHECK_FOR_INTERRUPTS(); - DoingCommandRead = false; - - /* - * (5) turn off the idle-in-transaction and idle-session timeouts, if - * active. - * - * At most one of these two will be active, so there's no need to + * At most one of these timeouts will be active, so there's no need to * worry about combining the timeout.c calls into one. */ if (idle_in_transaction_timeout_enabled) @@ -4352,6 +4341,18 @@ PostgresMain(int argc, char *argv[], idle_session_timeout_enabled = false; } + /* + * (5) disable async signal conditions again. + * + * Query cancel is supposed to be a no-op when there is no query in + * progress, so if a query cancel arrived while we were idle, just + * reset QueryCancelPending. ProcessInterrupts() has that effect when + * it's called when DoingCommandRead is set, so check for interrupts + * before resetting DoingCommandRead. + */ + CHECK_FOR_INTERRUPTS(); + DoingCommandRead = false; + /* * (6) check for any other interesting events that happened while we * slept. From 9ffe2278372d7549547176c23564a5b3404d072e Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 7 Jan 2021 20:36:09 -0500 Subject: [PATCH 059/240] Adjust createdb TAP tests to work on recent OpenBSD. We found last February that the error-case tests added by commit 008cf0409 failed on OpenBSD, because that platform doesn't really check locale names. At the time it seemed that that was only an issue for LC_CTYPE, but testing on a more recent version of OpenBSD shows that it's now equally lax about LC_COLLATE. Rather than dropping the LC_COLLATE test too, put back LC_CTYPE (reverting c4b0edb07), and adjust these tests to accept the different error message that we get if setlocale() doesn't reject a bogus locale name. The point of these tests is not really what the backend does with the locale name, but to show that createdb quotes funny locale names safely; so we're not losing test reliability this way. Back-patch as appropriate. Discussion: https://postgr.es/m/231373.1610058324@sss.pgh.pa.us --- src/bin/scripts/t/020_createdb.pl | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/bin/scripts/t/020_createdb.pl b/src/bin/scripts/t/020_createdb.pl index 89de674265a16..983dbb1d37f1e 100644 --- a/src/bin/scripts/t/020_createdb.pl +++ b/src/bin/scripts/t/020_createdb.pl @@ -3,7 +3,7 @@ use PostgresNode; use TestLib; -use Test::More tests => 19; +use Test::More tests => 22; program_help_ok('createdb'); program_version_ok('createdb'); @@ -31,12 +31,20 @@ 1, [qr/^$/], [qr/^createdb: error: "foo'; SELECT '1" is not a valid encoding name/s], - 'createdb with incorrect --lc-collate'); + 'createdb with incorrect --encoding'); $node->command_checks_all( [ 'createdb', '--lc-collate', "foo'; SELECT '1", 'foobar2' ], 1, [qr/^$/], [ - qr/^createdb: error: database creation failed: ERROR: invalid locale name/s + qr/^createdb: error: database creation failed: ERROR: invalid locale name|^createdb: error: database creation failed: ERROR: new collation \(foo'; SELECT '1\) is incompatible with the collation of the template database/s ], 'createdb with incorrect --lc-collate'); +$node->command_checks_all( + [ 'createdb', '--lc-ctype', "foo'; SELECT '1", 'foobar2' ], + 1, + [qr/^$/], + [ + qr/^createdb: error: database creation failed: ERROR: invalid locale name|^createdb: error: database creation failed: ERROR: new LC_CTYPE \(foo'; SELECT '1\) is incompatible with the LC_CTYPE of the template database/s + ], + 'createdb with incorrect --lc-ctype'); From 15b824da97afb45f47e51b6b5b7e5eca09e5d03d Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Fri, 8 Jan 2021 10:37:03 +0900 Subject: [PATCH 060/240] Fix and simplify some code related to cryptohashes This commit addresses two issues: - In pgcrypto, MD5 computation called pg_cryptohash_{init,update,final} without checking for the result status. - Simplify pg_checksum_raw_context to use only one variable for all the SHA2 options available in checksum manifests. Reported-by: Heikki Linnakangas Discussion: https://postgr.es/m/f62f26bb-47a5-8411-46e5-4350823e06a5@iki.fi --- contrib/pgcrypto/internal.c | 9 +++-- src/common/checksum_helper.c | 59 ++++++++++++---------------- src/include/common/checksum_helper.h | 5 +-- 3 files changed, 32 insertions(+), 41 deletions(-) diff --git a/contrib/pgcrypto/internal.c b/contrib/pgcrypto/internal.c index ea377bdf83ae9..79ce5135992d4 100644 --- a/contrib/pgcrypto/internal.c +++ b/contrib/pgcrypto/internal.c @@ -96,7 +96,8 @@ int_md5_update(PX_MD *h, const uint8 *data, unsigned dlen) { pg_cryptohash_ctx *ctx = (pg_cryptohash_ctx *) h->p.ptr; - pg_cryptohash_update(ctx, data, dlen); + if (pg_cryptohash_update(ctx, data, dlen) < 0) + elog(ERROR, "could not update %s context", "MD5"); } static void @@ -104,7 +105,8 @@ int_md5_reset(PX_MD *h) { pg_cryptohash_ctx *ctx = (pg_cryptohash_ctx *) h->p.ptr; - pg_cryptohash_init(ctx); + if (pg_cryptohash_init(ctx) < 0) + elog(ERROR, "could not initialize %s context", "MD5"); } static void @@ -112,7 +114,8 @@ int_md5_finish(PX_MD *h, uint8 *dst) { pg_cryptohash_ctx *ctx = (pg_cryptohash_ctx *) h->p.ptr; - pg_cryptohash_final(ctx, dst); + if (pg_cryptohash_final(ctx, dst) < 0) + elog(ERROR, "could not finalize %s context", "MD5"); } static void diff --git a/src/common/checksum_helper.c b/src/common/checksum_helper.c index f6b49de405e5e..2881b2c178d7c 100644 --- a/src/common/checksum_helper.c +++ b/src/common/checksum_helper.c @@ -93,42 +93,42 @@ pg_checksum_init(pg_checksum_context *context, pg_checksum_type type) INIT_CRC32C(context->raw_context.c_crc32c); break; case CHECKSUM_TYPE_SHA224: - context->raw_context.c_sha224 = pg_cryptohash_create(PG_SHA224); - if (context->raw_context.c_sha224 == NULL) + context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA224); + if (context->raw_context.c_sha2 == NULL) return -1; - if (pg_cryptohash_init(context->raw_context.c_sha224) < 0) + if (pg_cryptohash_init(context->raw_context.c_sha2) < 0) { - pg_cryptohash_free(context->raw_context.c_sha224); + pg_cryptohash_free(context->raw_context.c_sha2); return -1; } break; case CHECKSUM_TYPE_SHA256: - context->raw_context.c_sha256 = pg_cryptohash_create(PG_SHA256); - if (context->raw_context.c_sha256 == NULL) + context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA256); + if (context->raw_context.c_sha2 == NULL) return -1; - if (pg_cryptohash_init(context->raw_context.c_sha256) < 0) + if (pg_cryptohash_init(context->raw_context.c_sha2) < 0) { - pg_cryptohash_free(context->raw_context.c_sha256); + pg_cryptohash_free(context->raw_context.c_sha2); return -1; } break; case CHECKSUM_TYPE_SHA384: - context->raw_context.c_sha384 = pg_cryptohash_create(PG_SHA384); - if (context->raw_context.c_sha384 == NULL) + context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA384); + if (context->raw_context.c_sha2 == NULL) return -1; - if (pg_cryptohash_init(context->raw_context.c_sha384) < 0) + if (pg_cryptohash_init(context->raw_context.c_sha2) < 0) { - pg_cryptohash_free(context->raw_context.c_sha384); + pg_cryptohash_free(context->raw_context.c_sha2); return -1; } break; case CHECKSUM_TYPE_SHA512: - context->raw_context.c_sha512 = pg_cryptohash_create(PG_SHA512); - if (context->raw_context.c_sha512 == NULL) + context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA512); + if (context->raw_context.c_sha2 == NULL) return -1; - if (pg_cryptohash_init(context->raw_context.c_sha512) < 0) + if (pg_cryptohash_init(context->raw_context.c_sha2) < 0) { - pg_cryptohash_free(context->raw_context.c_sha512); + pg_cryptohash_free(context->raw_context.c_sha2); return -1; } break; @@ -154,19 +154,10 @@ pg_checksum_update(pg_checksum_context *context, const uint8 *input, COMP_CRC32C(context->raw_context.c_crc32c, input, len); break; case CHECKSUM_TYPE_SHA224: - if (pg_cryptohash_update(context->raw_context.c_sha224, input, len) < 0) - return -1; - break; case CHECKSUM_TYPE_SHA256: - if (pg_cryptohash_update(context->raw_context.c_sha256, input, len) < 0) - return -1; - break; case CHECKSUM_TYPE_SHA384: - if (pg_cryptohash_update(context->raw_context.c_sha384, input, len) < 0) - return -1; - break; case CHECKSUM_TYPE_SHA512: - if (pg_cryptohash_update(context->raw_context.c_sha512, input, len) < 0) + if (pg_cryptohash_update(context->raw_context.c_sha2, input, len) < 0) return -1; break; } @@ -207,27 +198,27 @@ pg_checksum_final(pg_checksum_context *context, uint8 *output) memcpy(output, &context->raw_context.c_crc32c, retval); break; case CHECKSUM_TYPE_SHA224: - if (pg_cryptohash_final(context->raw_context.c_sha224, output) < 0) + if (pg_cryptohash_final(context->raw_context.c_sha2, output) < 0) return -1; - pg_cryptohash_free(context->raw_context.c_sha224); + pg_cryptohash_free(context->raw_context.c_sha2); retval = PG_SHA224_DIGEST_LENGTH; break; case CHECKSUM_TYPE_SHA256: - if (pg_cryptohash_final(context->raw_context.c_sha256, output) < 0) + if (pg_cryptohash_final(context->raw_context.c_sha2, output) < 0) return -1; - pg_cryptohash_free(context->raw_context.c_sha256); + pg_cryptohash_free(context->raw_context.c_sha2); retval = PG_SHA224_DIGEST_LENGTH; break; case CHECKSUM_TYPE_SHA384: - if (pg_cryptohash_final(context->raw_context.c_sha384, output) < 0) + if (pg_cryptohash_final(context->raw_context.c_sha2, output) < 0) return -1; - pg_cryptohash_free(context->raw_context.c_sha384); + pg_cryptohash_free(context->raw_context.c_sha2); retval = PG_SHA384_DIGEST_LENGTH; break; case CHECKSUM_TYPE_SHA512: - if (pg_cryptohash_final(context->raw_context.c_sha512, output) < 0) + if (pg_cryptohash_final(context->raw_context.c_sha2, output) < 0) return -1; - pg_cryptohash_free(context->raw_context.c_sha512); + pg_cryptohash_free(context->raw_context.c_sha2); retval = PG_SHA512_DIGEST_LENGTH; break; } diff --git a/src/include/common/checksum_helper.h b/src/include/common/checksum_helper.h index ebdf1ccf447f1..cac7570ea1377 100644 --- a/src/include/common/checksum_helper.h +++ b/src/include/common/checksum_helper.h @@ -42,10 +42,7 @@ typedef enum pg_checksum_type typedef union pg_checksum_raw_context { pg_crc32c c_crc32c; - pg_cryptohash_ctx *c_sha224; - pg_cryptohash_ctx *c_sha256; - pg_cryptohash_ctx *c_sha384; - pg_cryptohash_ctx *c_sha512; + pg_cryptohash_ctx *c_sha2; } pg_checksum_raw_context; /* From afcc8772edcec687d87b6f762ca6113229af7291 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 8 Jan 2021 12:16:00 -0500 Subject: [PATCH 061/240] Fix ancient bug in parsing of BRE-mode regular expressions. brenext(), when parsing a '*' quantifier, forgot to return any "value" for the token; per the equivalent case in next(), it should return value 1 to indicate that greedy rather than non-greedy behavior is wanted. The result is that the compiled regexp could behave like 'x*?' rather than the intended 'x*', if we were unlucky enough to have a zero in v->nextvalue at this point. That seems to happen with some reliability if we have '.*' at the beginning of a BRE-mode regexp, although that depends on the initial contents of a stack-allocated struct, so it's not guaranteed to fail. Found by Alexander Lakhin using valgrind testing. This bug seems to be aboriginal in Spencer's code, so back-patch all the way. Discussion: https://postgr.es/m/16814-6c5e3edd2bdf0d50@postgresql.org --- src/backend/regex/regc_lex.c | 2 +- src/test/modules/test_regex/expected/test_regex.out | 8 ++++++++ src/test/modules/test_regex/sql/test_regex.sql | 2 ++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/backend/regex/regc_lex.c b/src/backend/regex/regc_lex.c index 38617b79fd146..ca2bce48312aa 100644 --- a/src/backend/regex/regc_lex.c +++ b/src/backend/regex/regc_lex.c @@ -994,7 +994,7 @@ brenext(struct vars *v, case CHR('*'): if (LASTTYPE(EMPTY) || LASTTYPE('(') || LASTTYPE('^')) RETV(PLAIN, c); - RET('*'); + RETV('*', 1); break; case CHR('['): if (HAVE(6) && *(v->now + 0) == CHR('[') && diff --git a/src/test/modules/test_regex/expected/test_regex.out b/src/test/modules/test_regex/expected/test_regex.out index ed1b0cbdb9b11..0dc2265d8b2dd 100644 --- a/src/test/modules/test_regex/expected/test_regex.out +++ b/src/test/modules/test_regex/expected/test_regex.out @@ -614,6 +614,14 @@ ERROR: invalid regular expression: quantifier operand invalid -- expectError 7.15 - a*+ BADRPT select * from test_regex('a*+', '', '-'); ERROR: invalid regular expression: quantifier operand invalid +-- test for ancient brenext() bug; not currently in Tcl +select * from test_regex('.*b', 'aaabbb', 'b'); + test_regex +------------ + {0} + {aaabbb} +(2 rows) + -- doing 8 "braces" -- expectMatch 8.1 NQ "a{0,1}" "" "" select * from test_regex('a{0,1}', '', 'NQ'); diff --git a/src/test/modules/test_regex/sql/test_regex.sql b/src/test/modules/test_regex/sql/test_regex.sql index 4676cd1a06075..1a2bfa6235727 100644 --- a/src/test/modules/test_regex/sql/test_regex.sql +++ b/src/test/modules/test_regex/sql/test_regex.sql @@ -214,6 +214,8 @@ select * from test_regex('a?*', '', '-'); select * from test_regex('a+*', '', '-'); -- expectError 7.15 - a*+ BADRPT select * from test_regex('a*+', '', '-'); +-- test for ancient brenext() bug; not currently in Tcl +select * from test_regex('.*b', 'aaabbb', 'b'); -- doing 8 "braces" From 39d4a153105f0693d93f593a23e5144e2bd031ef Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 8 Jan 2021 18:12:07 -0500 Subject: [PATCH 062/240] Fix plpgsql tests for debug_invalidate_system_caches_always. Commit c9d529848 resulted in having a couple more places where the error context stack for a failure varies depending on debug_invalidate_system_caches_always (nee CLOBBER_CACHE_ALWAYS). This is not very surprising, since we have to re-parse cached plans if the plan cache is clobbered. Stabilize the expected test output by hiding the context stack in these places, as we've done elsewhere in this test script. (Another idea worth considering, now that we have debug_invalidate_system_caches_always, is to force it to zero for these test cases. That seems like it'd risk reducing the coverage of cache-clobber testing, which might or might not be worth being able to verify that we get the expected error output in normal cases. For the moment I just stuck with the existing technique.) In passing, update comments that referred to CLOBBER_CACHE_ALWAYS. Per buildfarm member hyrax. --- src/pl/plpgsql/src/expected/plpgsql_cache.out | 8 ++++---- .../plpgsql/src/expected/plpgsql_cache_1.out | 8 ++++---- src/pl/plpgsql/src/expected/plpgsql_record.out | 18 ++++++++++++------ src/pl/plpgsql/src/sql/plpgsql_cache.sql | 8 ++++---- src/pl/plpgsql/src/sql/plpgsql_record.sql | 16 ++++++++++++---- 5 files changed, 36 insertions(+), 22 deletions(-) diff --git a/src/pl/plpgsql/src/expected/plpgsql_cache.out b/src/pl/plpgsql/src/expected/plpgsql_cache.out index c2cf0136050f0..cc0c57b8794f5 100644 --- a/src/pl/plpgsql/src/expected/plpgsql_cache.out +++ b/src/pl/plpgsql/src/expected/plpgsql_cache.out @@ -3,10 +3,10 @@ -- -- These tests logically belong in plpgsql_record.sql, and perhaps someday -- can be merged back into it. For now, however, their results are different --- between regular and CLOBBER_CACHE_ALWAYS builds, so we must have two +-- depending on debug_invalidate_system_caches_always, so we must have two -- expected-output files to cover both cases. To minimize the maintenance -- effort resulting from that, this file should contain only tests that --- do have different results under CLOBBER_CACHE_ALWAYS. +-- do have different results under debug_invalidate_system_caches_always. -- -- check behavior with changes of a named rowtype create table c_mutable(f1 int, f2 text); @@ -21,7 +21,7 @@ select c_sillyaddone(42); alter table c_mutable drop column f1; alter table c_mutable add column f1 float8; -- currently, this fails due to cached plan for "r.f1 + 1" expression --- (but a CLOBBER_CACHE_ALWAYS build will succeed) +-- (but if debug_invalidate_system_caches_always is on, it will succeed) select c_sillyaddone(42); ERROR: type of parameter 4 (double precision) does not match that when preparing the plan (integer) CONTEXT: PL/pgSQL function c_sillyaddone(integer) line 1 at RETURN @@ -52,7 +52,7 @@ select show_result_type('select 1 as a'); (1 row) -- currently this fails due to cached plan for pg_typeof expression --- (but a CLOBBER_CACHE_ALWAYS build will succeed) +-- (but if debug_invalidate_system_caches_always is on, it will succeed) select show_result_type('select 2.0 as a'); ERROR: type of parameter 5 (numeric) does not match that when preparing the plan (integer) CONTEXT: SQL statement "select pg_typeof(r.a)" diff --git a/src/pl/plpgsql/src/expected/plpgsql_cache_1.out b/src/pl/plpgsql/src/expected/plpgsql_cache_1.out index 0ac2c64a15c75..2a42875747ea8 100644 --- a/src/pl/plpgsql/src/expected/plpgsql_cache_1.out +++ b/src/pl/plpgsql/src/expected/plpgsql_cache_1.out @@ -3,10 +3,10 @@ -- -- These tests logically belong in plpgsql_record.sql, and perhaps someday -- can be merged back into it. For now, however, their results are different --- between regular and CLOBBER_CACHE_ALWAYS builds, so we must have two +-- depending on debug_invalidate_system_caches_always, so we must have two -- expected-output files to cover both cases. To minimize the maintenance -- effort resulting from that, this file should contain only tests that --- do have different results under CLOBBER_CACHE_ALWAYS. +-- do have different results under debug_invalidate_system_caches_always. -- -- check behavior with changes of a named rowtype create table c_mutable(f1 int, f2 text); @@ -21,7 +21,7 @@ select c_sillyaddone(42); alter table c_mutable drop column f1; alter table c_mutable add column f1 float8; -- currently, this fails due to cached plan for "r.f1 + 1" expression --- (but a CLOBBER_CACHE_ALWAYS build will succeed) +-- (but if debug_invalidate_system_caches_always is on, it will succeed) select c_sillyaddone(42); c_sillyaddone --------------- @@ -55,7 +55,7 @@ select show_result_type('select 1 as a'); (1 row) -- currently this fails due to cached plan for pg_typeof expression --- (but a CLOBBER_CACHE_ALWAYS build will succeed) +-- (but if debug_invalidate_system_caches_always is on, it will succeed) select show_result_type('select 2.0 as a'); show_result_type ------------------------ diff --git a/src/pl/plpgsql/src/expected/plpgsql_record.out b/src/pl/plpgsql/src/expected/plpgsql_record.out index 6e835c0751b22..86d0665924172 100644 --- a/src/pl/plpgsql/src/expected/plpgsql_record.out +++ b/src/pl/plpgsql/src/expected/plpgsql_record.out @@ -426,8 +426,8 @@ select getf1(row(1,2)); 1 (1 row) --- a CLOBBER_CACHE_ALWAYS build will report this error with a different --- context stack than other builds, so suppress context output +-- the context stack is different when debug_invalidate_system_caches_always +-- is set, so suppress context output \set SHOW_CONTEXT never select getf1(row(1,2)::two_int8s); ERROR: record "x" has no field "f1" @@ -507,9 +507,12 @@ select sillyaddone(42); -- test for change of type of column f1 should be here someday; -- for now see plpgsql_cache test alter table mutable drop column f1; +-- the context stack is different when debug_invalidate_system_caches_always +-- is set, so suppress context output +\set SHOW_CONTEXT never select sillyaddone(42); -- fail ERROR: record "r" has no field "f1" -CONTEXT: PL/pgSQL function sillyaddone(integer) line 1 at assignment +\set SHOW_CONTEXT errors create function getf3(x mutable) returns int language plpgsql as $$ begin return x.f3; end $$; select getf3(null::mutable); -- doesn't work yet @@ -524,8 +527,8 @@ select getf3(null::mutable); -- now it works (1 row) alter table mutable drop column f3; --- a CLOBBER_CACHE_ALWAYS build will report this error with a different --- context stack than other builds, so suppress context output +-- the context stack is different when debug_invalidate_system_caches_always +-- is set, so suppress context output \set SHOW_CONTEXT never select getf3(null::mutable); -- fails again ERROR: record "x" has no field "f3" @@ -549,9 +552,12 @@ select sillyaddtwo(42); (1 row) drop table mutable2; +-- the context stack is different when debug_invalidate_system_caches_always +-- is set, so suppress context output +\set SHOW_CONTEXT never select sillyaddtwo(42); -- fail ERROR: type "mutable2" does not exist -CONTEXT: PL/pgSQL function sillyaddtwo(integer) line 1 at assignment +\set SHOW_CONTEXT errors create table mutable2(f0 text, f1 int, f2 text); select sillyaddtwo(42); sillyaddtwo diff --git a/src/pl/plpgsql/src/sql/plpgsql_cache.sql b/src/pl/plpgsql/src/sql/plpgsql_cache.sql index f3b64d9209fd0..061f674c9a6ea 100644 --- a/src/pl/plpgsql/src/sql/plpgsql_cache.sql +++ b/src/pl/plpgsql/src/sql/plpgsql_cache.sql @@ -3,10 +3,10 @@ -- -- These tests logically belong in plpgsql_record.sql, and perhaps someday -- can be merged back into it. For now, however, their results are different --- between regular and CLOBBER_CACHE_ALWAYS builds, so we must have two +-- depending on debug_invalidate_system_caches_always, so we must have two -- expected-output files to cover both cases. To minimize the maintenance -- effort resulting from that, this file should contain only tests that --- do have different results under CLOBBER_CACHE_ALWAYS. +-- do have different results under debug_invalidate_system_caches_always. -- -- check behavior with changes of a named rowtype @@ -20,7 +20,7 @@ alter table c_mutable drop column f1; alter table c_mutable add column f1 float8; -- currently, this fails due to cached plan for "r.f1 + 1" expression --- (but a CLOBBER_CACHE_ALWAYS build will succeed) +-- (but if debug_invalidate_system_caches_always is on, it will succeed) select c_sillyaddone(42); -- but it's OK if we force plan rebuilding @@ -42,7 +42,7 @@ $$; select show_result_type('select 1 as a'); -- currently this fails due to cached plan for pg_typeof expression --- (but a CLOBBER_CACHE_ALWAYS build will succeed) +-- (but if debug_invalidate_system_caches_always is on, it will succeed) select show_result_type('select 2.0 as a'); -- but it's OK if we force plan rebuilding diff --git a/src/pl/plpgsql/src/sql/plpgsql_record.sql b/src/pl/plpgsql/src/sql/plpgsql_record.sql index be10f00b1e6e4..722048c7308b0 100644 --- a/src/pl/plpgsql/src/sql/plpgsql_record.sql +++ b/src/pl/plpgsql/src/sql/plpgsql_record.sql @@ -257,8 +257,8 @@ create function getf1(x record) returns int language plpgsql as $$ begin return x.f1; end $$; select getf1(1); select getf1(row(1,2)); --- a CLOBBER_CACHE_ALWAYS build will report this error with a different --- context stack than other builds, so suppress context output +-- the context stack is different when debug_invalidate_system_caches_always +-- is set, so suppress context output \set SHOW_CONTEXT never select getf1(row(1,2)::two_int8s); \set SHOW_CONTEXT errors @@ -316,7 +316,11 @@ select sillyaddone(42); -- for now see plpgsql_cache test alter table mutable drop column f1; +-- the context stack is different when debug_invalidate_system_caches_always +-- is set, so suppress context output +\set SHOW_CONTEXT never select sillyaddone(42); -- fail +\set SHOW_CONTEXT errors create function getf3(x mutable) returns int language plpgsql as $$ begin return x.f3; end $$; @@ -324,8 +328,8 @@ select getf3(null::mutable); -- doesn't work yet alter table mutable add column f3 int; select getf3(null::mutable); -- now it works alter table mutable drop column f3; --- a CLOBBER_CACHE_ALWAYS build will report this error with a different --- context stack than other builds, so suppress context output +-- the context stack is different when debug_invalidate_system_caches_always +-- is set, so suppress context output \set SHOW_CONTEXT never select getf3(null::mutable); -- fails again \set SHOW_CONTEXT errors @@ -342,7 +346,11 @@ select sillyaddtwo(42); -- fail create table mutable2(f1 int, f2 text); select sillyaddtwo(42); drop table mutable2; +-- the context stack is different when debug_invalidate_system_caches_always +-- is set, so suppress context output +\set SHOW_CONTEXT never select sillyaddtwo(42); -- fail +\set SHOW_CONTEXT errors create table mutable2(f0 text, f1 int, f2 text); select sillyaddtwo(42); select sillyaddtwo(43); From e33d004900f76c35759293fdedd4861b198fbf5b Mon Sep 17 00:00:00 2001 From: Amit Kapila Date: Sat, 9 Jan 2021 15:45:38 +0530 Subject: [PATCH 063/240] Fix the test for decoding of two-phase transactions. Commit 5a3574d7b3 added the test for decoding of two-phase transactions during the build of a consistent snapshot. The test forgot to skip empty xacts which can lead to decoding of extra empty transactions due to background activity by autovacuum. Per report by buildfarm. Reported-by: Tom Lane Discussion: https://postgr.es/m/363512.1610171267@sss.pgh.pa.us --- contrib/test_decoding/expected/twophase_snapshot.out | 4 ++-- contrib/test_decoding/specs/twophase_snapshot.spec | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/test_decoding/expected/twophase_snapshot.out b/contrib/test_decoding/expected/twophase_snapshot.out index 3b7f23b5b4585..14d93876462ed 100644 --- a/contrib/test_decoding/expected/twophase_snapshot.out +++ b/contrib/test_decoding/expected/twophase_snapshot.out @@ -22,14 +22,14 @@ step s1init: <... completed> init step s1insert: INSERT INTO do_write DEFAULT VALUES; -step s1start: SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', 'false', 'two-phase-commit', '1'); +step s1start: SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', 'false', 'skip-empty-xacts', '1', 'two-phase-commit', '1'); data BEGIN table public.do_write: INSERT: id[integer]:2 COMMIT step s2cp: COMMIT PREPARED 'test1'; -step s1start: SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', 'false', 'two-phase-commit', '1'); +step s1start: SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', 'false', 'skip-empty-xacts', '1', 'two-phase-commit', '1'); data BEGIN diff --git a/contrib/test_decoding/specs/twophase_snapshot.spec b/contrib/test_decoding/specs/twophase_snapshot.spec index bcaf68c6dc3ac..3e700404e0e5f 100644 --- a/contrib/test_decoding/specs/twophase_snapshot.spec +++ b/contrib/test_decoding/specs/twophase_snapshot.spec @@ -16,7 +16,7 @@ session "s1" setup { SET synchronous_commit=on; } step "s1init" {SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');} -step "s1start" {SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', 'false', 'two-phase-commit', '1');} +step "s1start" {SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', 'false', 'skip-empty-xacts', '1', 'two-phase-commit', '1');} step "s1insert" { INSERT INTO do_write DEFAULT VALUES; } session "s2" From 01334c92fa09dc496a444a4f206854ef37247258 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Sat, 9 Jan 2021 12:11:16 -0500 Subject: [PATCH 064/240] doc: expand description of how non-SELECT queries are processed The previous description of how the executor processes non-SELECT queries was very dense, causing lack of clarity. This expanded text spells it out more simply. Reported-by: fotis.koutoupas@gmail.com Discussion: https://postgr.es/m/160912275508.676.17469511338925622905@wrigleys.postgresql.org Backpatch-through: 9.5 --- doc/src/sgml/arch-dev.sgml | 50 +++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/doc/src/sgml/arch-dev.sgml b/doc/src/sgml/arch-dev.sgml index 7883c3cd827ce..ade0ad97d8e17 100644 --- a/doc/src/sgml/arch-dev.sgml +++ b/doc/src/sgml/arch-dev.sgml @@ -529,26 +529,36 @@ - The executor mechanism is used to evaluate all four basic SQL query types: - SELECT, INSERT, UPDATE, and - DELETE. For SELECT, the top-level executor - code only needs to send each row returned by the query plan tree off - to the client. For INSERT, each returned row is inserted - into the target table specified for the INSERT. This is - done in a special top-level plan node called ModifyTable. - (A simple - INSERT ... VALUES command creates a trivial plan tree - consisting of a single Result node, which computes just one - result row, and ModifyTable above it to perform the insertion. - But INSERT ... SELECT can demand the full power - of the executor mechanism.) For UPDATE, the planner arranges - that each computed row includes all the updated column values, plus - the TID (tuple ID, or row ID) of the original target row; - this data is fed into a ModifyTable node, which uses the - information to create a new updated row and mark the old row deleted. - For DELETE, the only column that is actually returned by the - plan is the TID, and the ModifyTable node simply uses the TID - to visit each target row and mark it deleted. + The executor mechanism is used to evaluate all four basic SQL query + types: SELECT, INSERT, + UPDATE, and DELETE. + For SELECT, the top-level executor code + only needs to send each row returned by the query plan tree + off to the client. INSERT ... SELECT, + UPDATE, and DELETE + are effectively SELECTs under a special + top-level plan node called ModifyTable. + + + + INSERT ... SELECT feeds the rows up + to ModifyTable for insertion. For + UPDATE, the planner arranges that each + computed row includes all the updated column values, plus the + TID (tuple ID, or row ID) of the original + target row; this data is fed up to the ModifyTable + node, which uses the information to create a new updated row and + mark the old row deleted. For DELETE, the only + column that is actually returned by the plan is the TID, and the + ModifyTable node simply uses the TID to visit each + target row and mark it deleted. + + + + A simple INSERT ... VALUES command creates a + trivial plan tree consisting of a single Result + node, which computes just one result row, feeding that up + toModifyTable to perform the insertion. From 13a021f3e8c99915b3cc0cb2021a948d9c71ff32 Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Mon, 11 Jan 2021 14:37:13 +1300 Subject: [PATCH 065/240] Provide pg_preadv() and pg_pwritev(). Provide synchronous vectored file I/O routines. These map to preadv() and pwritev(), with fallback implementations for systems that don't have them. Also provide a wrapper pg_pwritev_with_retry() that automatically retries on short writes. Reviewed-by: Tom Lane Reviewed-by: Andres Freund Discussion: https://postgr.es/m/CA%2BhUKGJA%2Bu-220VONeoREBXJ9P3S94Y7J%2BkqCnTYmahvZJwM%3Dg%40mail.gmail.com --- configure | 30 +--------- configure.ac | 9 ++- src/include/pg_config.h.in | 15 +++++ src/include/port.h | 2 + src/include/port/pg_iovec.h | 59 ++++++++++++++++++++ src/port/Makefile | 2 + src/port/pread.c | 43 ++++++++++++++- src/port/pwrite.c | 107 +++++++++++++++++++++++++++++++++++- src/tools/msvc/Solution.pm | 5 ++ 9 files changed, 238 insertions(+), 34 deletions(-) create mode 100644 src/include/port/pg_iovec.h diff --git a/configure b/configure index e51b8ce6ec350..b917a2a1c9dbf 100755 --- a/configure +++ b/configure @@ -13061,7 +13061,7 @@ $as_echo "#define HAVE_STDBOOL_H 1" >>confdefs.h fi -for ac_header in atomic.h copyfile.h execinfo.h getopt.h ifaddrs.h langinfo.h mbarrier.h poll.h sys/epoll.h sys/event.h sys/ipc.h sys/prctl.h sys/procctl.h sys/pstat.h sys/resource.h sys/select.h sys/sem.h sys/shm.h sys/sockio.h sys/tas.h sys/un.h termios.h ucred.h wctype.h +for ac_header in atomic.h copyfile.h execinfo.h getopt.h ifaddrs.h langinfo.h mbarrier.h poll.h sys/epoll.h sys/event.h sys/ipc.h sys/prctl.h sys/procctl.h sys/pstat.h sys/resource.h sys/select.h sys/sem.h sys/shm.h sys/sockio.h sys/tas.h sys/uio.h sys/un.h termios.h ucred.h wctype.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" @@ -15155,7 +15155,7 @@ fi LIBS_including_readline="$LIBS" LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'` -for ac_func in backtrace_symbols clock_gettime copyfile fdatasync getifaddrs getpeerucred getrlimit kqueue mbstowcs_l memset_s poll posix_fallocate ppoll pstat pthread_is_threaded_np readlink setproctitle setproctitle_fast setsid shm_open strchrnul strsignal symlink sync_file_range uselocale wcstombs_l +for ac_func in backtrace_symbols clock_gettime copyfile fdatasync getifaddrs getpeerucred getrlimit kqueue mbstowcs_l memset_s poll posix_fallocate ppoll pread preadv pstat pthread_is_threaded_np pwrite pwritev readlink readv setproctitle setproctitle_fast setsid shm_open strchrnul strsignal symlink sync_file_range uselocale wcstombs_l writev do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" @@ -15832,32 +15832,6 @@ esac fi -ac_fn_c_check_func "$LINENO" "pread" "ac_cv_func_pread" -if test "x$ac_cv_func_pread" = xyes; then : - $as_echo "#define HAVE_PREAD 1" >>confdefs.h - -else - case " $LIBOBJS " in - *" pread.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS pread.$ac_objext" - ;; -esac - -fi - -ac_fn_c_check_func "$LINENO" "pwrite" "ac_cv_func_pwrite" -if test "x$ac_cv_func_pwrite" = xyes; then : - $as_echo "#define HAVE_PWRITE 1" >>confdefs.h - -else - case " $LIBOBJS " in - *" pwrite.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS pwrite.$ac_objext" - ;; -esac - -fi - ac_fn_c_check_func "$LINENO" "random" "ac_cv_func_random" if test "x$ac_cv_func_random" = xyes; then : $as_echo "#define HAVE_RANDOM 1" >>confdefs.h diff --git a/configure.ac b/configure.ac index 054839f0f25b3..838d47dc22e2a 100644 --- a/configure.ac +++ b/configure.ac @@ -1331,6 +1331,7 @@ AC_CHECK_HEADERS(m4_normalize([ sys/shm.h sys/sockio.h sys/tas.h + sys/uio.h sys/un.h termios.h ucred.h @@ -1660,9 +1661,14 @@ AC_CHECK_FUNCS(m4_normalize([ poll posix_fallocate ppoll + pread + preadv pstat pthread_is_threaded_np + pwrite + pwritev readlink + readv setproctitle setproctitle_fast setsid @@ -1673,6 +1679,7 @@ AC_CHECK_FUNCS(m4_normalize([ sync_file_range uselocale wcstombs_l + writev ])) # These typically are compiler builtins, for which AC_CHECK_FUNCS fails. @@ -1733,8 +1740,6 @@ AC_REPLACE_FUNCS(m4_normalize([ inet_aton link mkdtemp - pread - pwrite random srandom strlcat diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index ddaa9e8e18215..f4d9f3b408d9f 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -412,6 +412,9 @@ /* Define to 1 if you have the `pread' function. */ #undef HAVE_PREAD +/* Define to 1 if you have the `preadv' function. */ +#undef HAVE_PREADV + /* Define to 1 if you have the `pstat' function. */ #undef HAVE_PSTAT @@ -430,6 +433,9 @@ /* Define to 1 if you have the `pwrite' function. */ #undef HAVE_PWRITE +/* Define to 1 if you have the `pwritev' function. */ +#undef HAVE_PWRITEV + /* Define to 1 if you have the `random' function. */ #undef HAVE_RANDOM @@ -445,6 +451,9 @@ /* Define to 1 if you have the `readlink' function. */ #undef HAVE_READLINK +/* Define to 1 if you have the `readv' function. */ +#undef HAVE_READV + /* Define to 1 if you have the global variable 'rl_completion_append_character'. */ #undef HAVE_RL_COMPLETION_APPEND_CHARACTER @@ -629,6 +638,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UCRED_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_UIO_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UN_H @@ -683,6 +695,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_WINLDAP_H +/* Define to 1 if you have the `writev' function. */ +#undef HAVE_WRITEV + /* Define to 1 if you have the `X509_get_signature_nid' function. */ #undef HAVE_X509_GET_SIGNATURE_NID diff --git a/src/include/port.h b/src/include/port.h index 3e9d4fcd3769a..6486db9fddec0 100644 --- a/src/include/port.h +++ b/src/include/port.h @@ -431,6 +431,8 @@ extern ssize_t pg_pread(int fd, void *buf, size_t nbyte, off_t offset); extern ssize_t pg_pwrite(int fd, const void *buf, size_t nbyte, off_t offset); #endif +/* For pg_pwritev() and pg_preadv(), see port/pg_iovec.h. */ + #if !HAVE_DECL_STRLCAT extern size_t strlcat(char *dst, const char *src, size_t siz); #endif diff --git a/src/include/port/pg_iovec.h b/src/include/port/pg_iovec.h new file mode 100644 index 0000000000000..335f35bf0ebb0 --- /dev/null +++ b/src/include/port/pg_iovec.h @@ -0,0 +1,59 @@ +/*------------------------------------------------------------------------- + * + * pg_iovec.h + * Header for the vectored I/O functions in src/port/p{read,write}.c. + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/port/pg_iovec.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_IOVEC_H +#define PG_IOVEC_H + +#include + +#ifdef HAVE_SYS_UIO_H +#include +#endif + +/* If is missing, define our own POSIX-compatible iovec struct. */ +#ifndef HAVE_SYS_UIO_H +struct iovec +{ + void *iov_base; + size_t iov_len; +}; +#endif + +/* + * If didn't define IOV_MAX, define our own. POSIX requires at + * least 16. + */ +#ifndef IOV_MAX +#define IOV_MAX 16 +#endif + +/* Define a reasonable maximum that is safe to use on the stack. */ +#define PG_IOV_MAX Min(IOV_MAX, 32) + +#ifdef HAVE_PREADV +#define pg_preadv preadv +#else +extern ssize_t pg_preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset); +#endif + +#ifdef HAVE_PWRITEV +#define pg_pwritev pwritev +#else +extern ssize_t pg_pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset); +#endif + +extern ssize_t pg_pwritev_with_retry(int fd, + const struct iovec *iov, + int iovcnt, + off_t offset); + +#endif /* PG_IOVEC_H */ diff --git a/src/port/Makefile b/src/port/Makefile index e41b005c4f1bf..bc4923ce840e1 100644 --- a/src/port/Makefile +++ b/src/port/Makefile @@ -53,6 +53,8 @@ OBJS = \ pgstrcasecmp.o \ pgstrsignal.o \ pqsignal.o \ + pread.o \ + pwrite.o \ qsort.o \ qsort_arg.o \ quotes.o \ diff --git a/src/port/pread.c b/src/port/pread.c index 486f07a7dffcc..a5ae2759fa0e5 100644 --- a/src/port/pread.c +++ b/src/port/pread.c @@ -1,7 +1,7 @@ /*------------------------------------------------------------------------- * * pread.c - * Implementation of pread(2) for platforms that lack one. + * Implementation of pread[v](2) for platforms that lack one. * * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * @@ -9,7 +9,8 @@ * src/port/pread.c * * Note that this implementation changes the current file position, unlike - * the POSIX function, so we use the name pg_pread(). + * the POSIX function, so we use the name pg_pread(). Likewise for the + * iovec version. * *------------------------------------------------------------------------- */ @@ -23,6 +24,9 @@ #include #endif +#include "port/pg_iovec.h" + +#ifndef HAVE_PREAD ssize_t pg_pread(int fd, void *buf, size_t size, off_t offset) { @@ -56,3 +60,38 @@ pg_pread(int fd, void *buf, size_t size, off_t offset) return read(fd, buf, size); #endif } +#endif + +#ifndef HAVE_PREADV +ssize_t +pg_preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) +{ +#ifdef HAVE_READV + if (iovcnt == 1) + return pg_pread(fd, iov[0].iov_base, iov[0].iov_len, offset); + if (lseek(fd, offset, SEEK_SET) < 0) + return -1; + return readv(fd, iov, iovcnt); +#else + ssize_t sum = 0; + ssize_t part; + + for (int i = 0; i < iovcnt; ++i) + { + part = pg_pread(fd, iov[i].iov_base, iov[i].iov_len, offset); + if (part < 0) + { + if (i == 0) + return -1; + else + return sum; + } + sum += part; + offset += part; + if (part < iov[i].iov_len) + return sum; + } + return sum; +#endif +} +#endif diff --git a/src/port/pwrite.c b/src/port/pwrite.c index 282b27115e509..e029f44bc0ce0 100644 --- a/src/port/pwrite.c +++ b/src/port/pwrite.c @@ -1,7 +1,7 @@ /*------------------------------------------------------------------------- * * pwrite.c - * Implementation of pwrite(2) for platforms that lack one. + * Implementation of pwrite[v](2) for platforms that lack one. * * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * @@ -9,7 +9,8 @@ * src/port/pwrite.c * * Note that this implementation changes the current file position, unlike - * the POSIX function, so we use the name pg_pwrite(). + * the POSIX function, so we use the name pg_pwrite(). Likewise for the + * iovec version. * *------------------------------------------------------------------------- */ @@ -23,6 +24,9 @@ #include #endif +#include "port/pg_iovec.h" + +#ifndef HAVE_PWRITE ssize_t pg_pwrite(int fd, const void *buf, size_t size, off_t offset) { @@ -53,3 +57,102 @@ pg_pwrite(int fd, const void *buf, size_t size, off_t offset) return write(fd, buf, size); #endif } +#endif + +#ifndef HAVE_PWRITEV +ssize_t +pg_pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) +{ +#ifdef HAVE_WRITEV + if (iovcnt == 1) + return pg_pwrite(fd, iov[0].iov_base, iov[0].iov_len, offset); + if (lseek(fd, offset, SEEK_SET) < 0) + return -1; + return writev(fd, iov, iovcnt); +#else + ssize_t sum = 0; + ssize_t part; + + for (int i = 0; i < iovcnt; ++i) + { + part = pg_pwrite(fd, iov[i].iov_base, iov[i].iov_len, offset); + if (part < 0) + { + if (i == 0) + return -1; + else + return sum; + } + sum += part; + offset += part; + if (part < iov[i].iov_len) + return sum; + } + return sum; +#endif +} +#endif + +/* + * A convenience wrapper for pg_pwritev() that retries on partial write. If an + * error is returned, it is unspecified how much has been written. + */ +ssize_t +pg_pwritev_with_retry(int fd, const struct iovec *iov, int iovcnt, off_t offset) +{ + struct iovec iov_copy[PG_IOV_MAX]; + ssize_t sum = 0; + ssize_t part; + + /* We'd better have space to make a copy, in case we need to retry. */ + if (iovcnt > PG_IOV_MAX) + { + errno = EINVAL; + return -1; + } + + for (;;) + { + /* Write as much as we can. */ + part = pg_pwritev(fd, iov, iovcnt, offset); + if (part < 0) + return -1; + +#ifdef SIMULATE_SHORT_WRITE + part = Min(part, 4096); +#endif + + /* Count our progress. */ + sum += part; + offset += part; + + /* Step over iovecs that are done. */ + while (iovcnt > 0 && iov->iov_len <= part) + { + part -= iov->iov_len; + ++iov; + --iovcnt; + } + + /* Are they all done? */ + if (iovcnt == 0) + { + if (part > 0) + elog(ERROR, "unexpectedly wrote more than requested"); + break; + } + + /* + * Move whatever's left to the front of our mutable copy and adjust the + * leading iovec. + */ + Assert(iovcnt > 0); + memmove(iov_copy, iov, sizeof(*iov) * iovcnt); + Assert(iov->iov_len > part); + iov_copy[0].iov_base = (char *) iov_copy[0].iov_base + part; + iov_copy[0].iov_len -= part; + iov = iov_copy; + } + + return sum; +} diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm index 95d4e826b1d05..59a42bea97a7f 100644 --- a/src/tools/msvc/Solution.pm +++ b/src/tools/msvc/Solution.pm @@ -329,17 +329,20 @@ sub GenerateFiles HAVE_PPC_LWARX_MUTEX_HINT => undef, HAVE_PPOLL => undef, HAVE_PREAD => undef, + HAVE_PREADV => undef, HAVE_PSTAT => undef, HAVE_PS_STRINGS => undef, HAVE_PTHREAD => undef, HAVE_PTHREAD_IS_THREADED_NP => undef, HAVE_PTHREAD_PRIO_INHERIT => undef, HAVE_PWRITE => undef, + HAVE_PWRITEV => undef, HAVE_RANDOM => undef, HAVE_READLINE_H => undef, HAVE_READLINE_HISTORY_H => undef, HAVE_READLINE_READLINE_H => undef, HAVE_READLINK => undef, + HAVE_READV => undef, HAVE_RL_COMPLETION_APPEND_CHARACTER => undef, HAVE_RL_COMPLETION_MATCHES => undef, HAVE_RL_COMPLETION_SUPPRESS_QUOTE => undef, @@ -400,6 +403,7 @@ sub GenerateFiles HAVE_SYS_TAS_H => undef, HAVE_SYS_TYPES_H => 1, HAVE_SYS_UCRED_H => undef, + HAVE_SYS_UIO_H => undef, HAVE_SYS_UN_H => undef, HAVE_TERMIOS_H => undef, HAVE_TYPEOF => undef, @@ -418,6 +422,7 @@ sub GenerateFiles HAVE_WINLDAP_H => undef, HAVE_WCSTOMBS_L => 1, HAVE_WCTYPE_H => 1, + HAVE_WRITEV => undef, HAVE_X509_GET_SIGNATURE_NID => 1, HAVE_X86_64_POPCNTQ => undef, HAVE__BOOL => undef, From ce6a71fa5300cf00adf32c9daee302c523609709 Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Mon, 11 Jan 2021 14:41:39 +1300 Subject: [PATCH 066/240] Use vectored I/O to fill new WAL segments. Instead of making many block-sized write() calls to fill a new WAL file with zeroes, make a smaller number of pwritev() calls (or various emulations). The actual number depends on the OS's IOV_MAX, which PG_IOV_MAX currently caps at 32. That means we'll write 256kB per call on typical systems. We may want to tune the number later with more experience. Reviewed-by: Tom Lane Reviewed-by: Andres Freund Discussion: https://postgr.es/m/CA%2BhUKGJA%2Bu-220VONeoREBXJ9P3S94Y7J%2BkqCnTYmahvZJwM%3Dg%40mail.gmail.com --- src/backend/access/transam/xlog.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index ede93ad7fdde2..b18257c198078 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -48,6 +48,7 @@ #include "pg_trace.h" #include "pgstat.h" #include "port/atomics.h" +#include "port/pg_iovec.h" #include "postmaster/bgwriter.h" #include "postmaster/startup.h" #include "postmaster/walwriter.h" @@ -3270,7 +3271,6 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool use_lock) XLogSegNo installed_segno; XLogSegNo max_segno; int fd; - int nbytes; int save_errno; XLogFilePath(path, ThisTimeLineID, logsegno, wal_segment_size); @@ -3317,6 +3317,9 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool use_lock) save_errno = 0; if (wal_init_zero) { + struct iovec iov[PG_IOV_MAX]; + int blocks; + /* * Zero-fill the file. With this setting, we do this the hard way to * ensure that all the file space has really been allocated. On @@ -3326,15 +3329,28 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool use_lock) * indirect blocks are down on disk. Therefore, fdatasync(2) or * O_DSYNC will be sufficient to sync future writes to the log file. */ - for (nbytes = 0; nbytes < wal_segment_size; nbytes += XLOG_BLCKSZ) + + /* Prepare to write out a lot of copies of our zero buffer at once. */ + for (int i = 0; i < lengthof(iov); ++i) { - errno = 0; - if (write(fd, zbuffer.data, XLOG_BLCKSZ) != XLOG_BLCKSZ) + iov[i].iov_base = zbuffer.data; + iov[i].iov_len = XLOG_BLCKSZ; + } + + /* Loop, writing as many blocks as we can for each system call. */ + blocks = wal_segment_size / XLOG_BLCKSZ; + for (int i = 0; i < blocks;) + { + int iovcnt = Min(blocks - i, lengthof(iov)); + off_t offset = i * XLOG_BLCKSZ; + + if (pg_pwritev_with_retry(fd, iov, iovcnt, offset) < 0) { - /* if write didn't set errno, assume no disk space */ - save_errno = errno ? errno : ENOSPC; + save_errno = errno; break; } + + i += iovcnt; } } else From ffa2e4670123124b92f037d335a1e844c3782d3f Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 11 Jan 2021 13:12:09 -0500 Subject: [PATCH 067/240] In libpq, always append new error messages to conn->errorMessage. Previously, we had an undisciplined mish-mash of printfPQExpBuffer and appendPQExpBuffer calls to report errors within libpq. This commit establishes a uniform rule that appendPQExpBuffer[Str] should be used. conn->errorMessage is reset only at the start of an application request, and then accumulates messages till we're done. We can remove no less than three different ad-hoc mechanisms that were used to get the effect of concatenation of error messages within a sequence of operations. Although this makes things quite a bit cleaner conceptually, the main reason to do it is to make the world safer for the multiple-target-host feature that was added awhile back. Previously, there were many cases in which an error occurring during an individual host connection attempt would wipe out the record of what had happened during previous attempts. (The reporting is still inadequate, in that it can be hard to tell which host got the failure, but that seems like a matter for a separate commit.) Currently, lo_import and lo_export contain exceptions to the "never use printfPQExpBuffer" rule. If we changed them, we'd risk reporting an incidental lo_close failure before the actual read or write failure, which would be confusing, not least because lo_close happened after the main failure. We could improve this by inventing an internal version of lo_close that doesn't reset the errorMessage; but we'd also need a version of PQfn() that does that, and it didn't quite seem worth the trouble for now. Discussion: https://postgr.es/m/BN6PR05MB3492948E4FD76C156E747E8BC9160@BN6PR05MB3492.namprd05.prod.outlook.com --- src/interfaces/libpq/fe-auth-scram.c | 124 +++++---- src/interfaces/libpq/fe-auth.c | 169 ++++++------ src/interfaces/libpq/fe-connect.c | 317 +++++++++-------------- src/interfaces/libpq/fe-exec.c | 281 +++++++++----------- src/interfaces/libpq/fe-gssapi-common.c | 9 +- src/interfaces/libpq/fe-lobj.c | 210 ++++++++------- src/interfaces/libpq/fe-misc.c | 54 ++-- src/interfaces/libpq/fe-protocol2.c | 36 ++- src/interfaces/libpq/fe-protocol3.c | 51 ++-- src/interfaces/libpq/fe-secure-common.c | 24 +- src/interfaces/libpq/fe-secure-gssapi.c | 28 +- src/interfaces/libpq/fe-secure-openssl.c | 124 ++++----- src/interfaces/libpq/fe-secure.c | 28 +- src/interfaces/libpq/libpq-int.h | 18 +- 14 files changed, 699 insertions(+), 774 deletions(-) diff --git a/src/interfaces/libpq/fe-auth-scram.c b/src/interfaces/libpq/fe-auth-scram.c index b76f0befd0b87..002469540a9b7 100644 --- a/src/interfaces/libpq/fe-auth-scram.c +++ b/src/interfaces/libpq/fe-auth-scram.c @@ -208,14 +208,14 @@ pg_fe_scram_exchange(void *opaq, char *input, int inputlen, { if (inputlen == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("malformed SCRAM message (empty message)\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("malformed SCRAM message (empty message)\n")); goto error; } if (inputlen != strlen(input)) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("malformed SCRAM message (length mismatch)\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("malformed SCRAM message (length mismatch)\n")); goto error; } } @@ -258,15 +258,15 @@ pg_fe_scram_exchange(void *opaq, char *input, int inputlen, */ if (!verify_server_signature(state, success)) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not verify server signature\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("could not verify server signature\n")); goto error; } if (!*success) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("incorrect server signature\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("incorrect server signature\n")); } *done = true; state->state = FE_SCRAM_FINISHED; @@ -274,8 +274,8 @@ pg_fe_scram_exchange(void *opaq, char *input, int inputlen, default: /* shouldn't happen */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("invalid SCRAM exchange state\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("invalid SCRAM exchange state\n")); goto error; } return; @@ -287,6 +287,11 @@ pg_fe_scram_exchange(void *opaq, char *input, int inputlen, /* * Read value for an attribute part of a SCRAM message. + * + * The buffer at **input is destructively modified, and *input is + * advanced over the "attr=value" string and any following comma. + * + * On failure, append an error message to *errorMessage and return NULL. */ static char * read_attr_value(char **input, char attr, PQExpBuffer errorMessage) @@ -296,7 +301,7 @@ read_attr_value(char **input, char attr, PQExpBuffer errorMessage) if (*begin != attr) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("malformed SCRAM message (attribute \"%c\" expected)\n"), attr); return NULL; @@ -305,7 +310,7 @@ read_attr_value(char **input, char attr, PQExpBuffer errorMessage) if (*begin != '=') { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("malformed SCRAM message (expected character \"=\" for attribute \"%c\")\n"), attr); return NULL; @@ -346,8 +351,8 @@ build_client_first_message(fe_scram_state *state) */ if (!pg_strong_random(raw_nonce, SCRAM_RAW_NONCE_LEN)) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not generate nonce\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("could not generate nonce\n")); return NULL; } @@ -356,16 +361,16 @@ build_client_first_message(fe_scram_state *state) state->client_nonce = malloc(encoded_len + 1); if (state->client_nonce == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return NULL; } encoded_len = pg_b64_encode(raw_nonce, SCRAM_RAW_NONCE_LEN, state->client_nonce, encoded_len); if (encoded_len < 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not encode nonce\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("could not encode nonce\n")); return NULL; } state->client_nonce[encoded_len] = '\0'; @@ -431,8 +436,8 @@ build_client_first_message(fe_scram_state *state) oom_error: termPQExpBuffer(&buf); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return NULL; } @@ -508,8 +513,8 @@ build_client_final_message(fe_scram_state *state) free(cbind_data); free(cbind_input); termPQExpBuffer(&buf); - printfPQExpBuffer(&conn->errorMessage, - "could not encode cbind data for channel binding\n"); + appendPQExpBufferStr(&conn->errorMessage, + "could not encode cbind data for channel binding\n"); return NULL; } buf.len += encoded_cbind_len; @@ -523,8 +528,8 @@ build_client_final_message(fe_scram_state *state) * Shouldn't happen. */ termPQExpBuffer(&buf); - printfPQExpBuffer(&conn->errorMessage, - "channel binding not supported by this build\n"); + appendPQExpBufferStr(&conn->errorMessage, + "channel binding not supported by this build\n"); return NULL; #endif /* HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH */ } @@ -553,8 +558,8 @@ build_client_final_message(fe_scram_state *state) client_proof)) { termPQExpBuffer(&buf); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not calculate client proof\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("could not calculate client proof\n")); return NULL; } @@ -569,8 +574,8 @@ build_client_final_message(fe_scram_state *state) if (encoded_len < 0) { termPQExpBuffer(&buf); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not encode client proof\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("could not encode client proof\n")); return NULL; } buf.len += encoded_len; @@ -585,8 +590,8 @@ build_client_final_message(fe_scram_state *state) oom_error: termPQExpBuffer(&buf); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return NULL; } @@ -606,8 +611,8 @@ read_server_first_message(fe_scram_state *state, char *input) state->server_first_message = strdup(input); if (state->server_first_message == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return false; } @@ -616,7 +621,7 @@ read_server_first_message(fe_scram_state *state, char *input) &conn->errorMessage); if (nonce == NULL) { - /* read_attr_value() has generated an error string */ + /* read_attr_value() has appended an error string */ return false; } @@ -624,31 +629,31 @@ read_server_first_message(fe_scram_state *state, char *input) if (strlen(nonce) < strlen(state->client_nonce) || memcmp(nonce, state->client_nonce, strlen(state->client_nonce)) != 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("invalid SCRAM response (nonce mismatch)\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("invalid SCRAM response (nonce mismatch)\n")); return false; } state->nonce = strdup(nonce); if (state->nonce == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return false; } encoded_salt = read_attr_value(&input, 's', &conn->errorMessage); if (encoded_salt == NULL) { - /* read_attr_value() has generated an error string */ + /* read_attr_value() has appended an error string */ return false; } decoded_salt_len = pg_b64_dec_len(strlen(encoded_salt)); state->salt = malloc(decoded_salt_len); if (state->salt == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return false; } state->saltlen = pg_b64_decode(encoded_salt, @@ -657,28 +662,28 @@ read_server_first_message(fe_scram_state *state, char *input) decoded_salt_len); if (state->saltlen < 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("malformed SCRAM message (invalid salt)\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("malformed SCRAM message (invalid salt)\n")); return false; } iterations_str = read_attr_value(&input, 'i', &conn->errorMessage); if (iterations_str == NULL) { - /* read_attr_value() has generated an error string */ + /* read_attr_value() has appended an error string */ return false; } state->iterations = strtol(iterations_str, &endptr, 10); if (*endptr != '\0' || state->iterations < 1) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("malformed SCRAM message (invalid iteration count)\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("malformed SCRAM message (invalid iteration count)\n")); return false; } if (*input != '\0') - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("malformed SCRAM message (garbage at end of server-first-message)\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("malformed SCRAM message (garbage at end of server-first-message)\n")); return true; } @@ -697,8 +702,8 @@ read_server_final_message(fe_scram_state *state, char *input) state->server_final_message = strdup(input); if (!state->server_final_message) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return false; } @@ -708,7 +713,12 @@ read_server_final_message(fe_scram_state *state, char *input) char *errmsg = read_attr_value(&input, 'e', &conn->errorMessage); - printfPQExpBuffer(&conn->errorMessage, + if (errmsg == NULL) + { + /* read_attr_value() has appended an error message */ + return false; + } + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("error received from server in SCRAM exchange: %s\n"), errmsg); return false; @@ -719,20 +729,20 @@ read_server_final_message(fe_scram_state *state, char *input) &conn->errorMessage); if (encoded_server_signature == NULL) { - /* read_attr_value() has generated an error message */ + /* read_attr_value() has appended an error message */ return false; } if (*input != '\0') - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("malformed SCRAM message (garbage at end of server-final-message)\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("malformed SCRAM message (garbage at end of server-final-message)\n")); server_signature_len = pg_b64_dec_len(strlen(encoded_server_signature)); decoded_server_signature = malloc(server_signature_len); if (!decoded_server_signature) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return false; } @@ -743,8 +753,8 @@ read_server_final_message(fe_scram_state *state, char *input) if (server_signature_len != SCRAM_KEY_LEN) { free(decoded_server_signature); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("malformed SCRAM message (invalid server signature)\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("malformed SCRAM message (invalid server signature)\n")); return false; } memcpy(state->ServerSignature, decoded_server_signature, SCRAM_KEY_LEN); diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c index a25fe4dd17a8e..168b3df52bfce 100644 --- a/src/interfaces/libpq/fe-auth.c +++ b/src/interfaces/libpq/fe-auth.c @@ -72,7 +72,7 @@ pg_GSS_continue(PGconn *conn, int payloadlen) ginbuf.value = malloc(payloadlen); if (!ginbuf.value) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory allocating GSSAPI buffer (%d)\n"), payloadlen); return STATUS_ERROR; @@ -154,15 +154,15 @@ pg_GSS_startup(PGconn *conn, int payloadlen) if (!(host && host[0] != '\0')) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("host name must be specified\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("host name must be specified\n")); return STATUS_ERROR; } if (conn->gctx) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("duplicate GSS authentication request\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("duplicate GSS authentication request\n")); return STATUS_ERROR; } @@ -195,10 +195,10 @@ pg_SSPI_error(PGconn *conn, const char *mprefix, SECURITY_STATUS r) FORMAT_MESSAGE_FROM_SYSTEM, NULL, r, 0, sysmsg, sizeof(sysmsg), NULL) == 0) - printfPQExpBuffer(&conn->errorMessage, "%s: SSPI error %x\n", + appendPQExpBuffer(&conn->errorMessage, "%s: SSPI error %x\n", mprefix, (unsigned int) r); else - printfPQExpBuffer(&conn->errorMessage, "%s: %s (%x)\n", + appendPQExpBuffer(&conn->errorMessage, "%s: %s (%x)\n", mprefix, sysmsg, (unsigned int) r); } @@ -226,7 +226,7 @@ pg_SSPI_continue(PGconn *conn, int payloadlen) inputbuf = malloc(payloadlen); if (!inputbuf) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory allocating SSPI buffer (%d)\n"), payloadlen); return STATUS_ERROR; @@ -286,7 +286,8 @@ pg_SSPI_continue(PGconn *conn, int payloadlen) conn->sspictx = malloc(sizeof(CtxtHandle)); if (conn->sspictx == NULL) { - printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return STATUS_ERROR; } memcpy(conn->sspictx, &newContext, sizeof(CtxtHandle)); @@ -305,7 +306,8 @@ pg_SSPI_continue(PGconn *conn, int payloadlen) * authentication. Keep check in case it shows up with other * authentication methods later. */ - printfPQExpBuffer(&conn->errorMessage, "SSPI returned invalid number of output buffers\n"); + appendPQExpBufferStr(&conn->errorMessage, + "SSPI returned invalid number of output buffers\n"); return STATUS_ERROR; } @@ -345,8 +347,8 @@ pg_SSPI_startup(PGconn *conn, int use_negotiate, int payloadlen) if (conn->sspictx) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("duplicate SSPI authentication request\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("duplicate SSPI authentication request\n")); return STATUS_ERROR; } @@ -356,7 +358,8 @@ pg_SSPI_startup(PGconn *conn, int use_negotiate, int payloadlen) conn->sspicred = malloc(sizeof(CredHandle)); if (conn->sspicred == NULL) { - printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return STATUS_ERROR; } @@ -384,14 +387,15 @@ pg_SSPI_startup(PGconn *conn, int use_negotiate, int payloadlen) */ if (!(host && host[0] != '\0')) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("host name must be specified\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("host name must be specified\n")); return STATUS_ERROR; } conn->sspitarget = malloc(strlen(conn->krbsrvname) + strlen(host) + 2); if (!conn->sspitarget) { - printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return STATUS_ERROR; } sprintf(conn->sspitarget, "%s/%s", conn->krbsrvname, host); @@ -425,15 +429,15 @@ pg_SASL_init(PGconn *conn, int payloadlen) if (conn->channel_binding[0] == 'r' && /* require */ !conn->ssl_in_use) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("channel binding required, but SSL not in use\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("channel binding required, but SSL not in use\n")); goto error; } if (conn->sasl_state) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("duplicate SASL authentication request\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("duplicate SASL authentication request\n")); goto error; } @@ -448,8 +452,8 @@ pg_SASL_init(PGconn *conn, int payloadlen) { if (pqGets(&mechanism_buf, conn)) { - printfPQExpBuffer(&conn->errorMessage, - "fe_sendauth: invalid authentication request from server: invalid list of authentication mechanisms\n"); + appendPQExpBufferStr(&conn->errorMessage, + "fe_sendauth: invalid authentication request from server: invalid list of authentication mechanisms\n"); goto error; } if (PQExpBufferDataBroken(mechanism_buf)) @@ -488,8 +492,8 @@ pg_SASL_init(PGconn *conn, int payloadlen) */ if (conn->channel_binding[0] == 'r') /* require */ { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("channel binding is required, but client does not support it\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("channel binding is required, but client does not support it\n")); goto error; } #endif @@ -505,8 +509,8 @@ pg_SASL_init(PGconn *conn, int payloadlen) * the client and server supported it. The SCRAM exchange * checks for that, to prevent downgrade attacks. */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("server offered SCRAM-SHA-256-PLUS authentication over a non-SSL connection\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("server offered SCRAM-SHA-256-PLUS authentication over a non-SSL connection\n")); goto error; } } @@ -517,16 +521,16 @@ pg_SASL_init(PGconn *conn, int payloadlen) if (!selected_mechanism) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("none of the server's SASL authentication mechanisms are supported\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("none of the server's SASL authentication mechanisms are supported\n")); goto error; } if (conn->channel_binding[0] == 'r' && /* require */ strcmp(selected_mechanism, SCRAM_SHA_256_PLUS_NAME) != 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("channel binding is required, but server did not offer an authentication method that supports channel binding\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("channel binding is required, but server did not offer an authentication method that supports channel binding\n")); goto error; } @@ -546,8 +550,8 @@ pg_SASL_init(PGconn *conn, int payloadlen) password = conn->pgpass; if (password == NULL || password[0] == '\0') { - printfPQExpBuffer(&conn->errorMessage, - PQnoPasswordSupplied); + appendPQExpBufferStr(&conn->errorMessage, + PQnoPasswordSupplied); goto error; } @@ -607,8 +611,8 @@ pg_SASL_init(PGconn *conn, int payloadlen) termPQExpBuffer(&mechanism_buf); if (initialresponse) free(initialresponse); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return STATUS_ERROR; } @@ -631,7 +635,7 @@ pg_SASL_continue(PGconn *conn, int payloadlen, bool final) challenge = malloc(payloadlen + 1); if (!challenge) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory allocating SASL buffer (%d)\n"), payloadlen); return STATUS_ERROR; @@ -656,8 +660,8 @@ pg_SASL_continue(PGconn *conn, int payloadlen, bool final) if (outputlen != 0) free(output); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("AuthenticationSASLFinal received from server, but SASL authentication was not completed\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("AuthenticationSASLFinal received from server, but SASL authentication was not completed\n")); return STATUS_ERROR; } if (outputlen != 0) @@ -726,15 +730,15 @@ pg_local_sendauth(PGconn *conn) { char sebuf[PG_STRERROR_R_BUFLEN]; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, "pg_local_sendauth: sendmsg: %s\n", strerror_r(errno, sebuf, sizeof(sebuf))); return STATUS_ERROR; } return STATUS_OK; #else - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("SCM_CRED authentication method not supported\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("SCM_CRED authentication method not supported\n")); return STATUS_ERROR; #endif } @@ -766,8 +770,8 @@ pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq) crypt_pwd = malloc(2 * (MD5_PASSWD_LEN + 1)); if (!crypt_pwd) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return STATUS_ERROR; } @@ -832,14 +836,14 @@ check_expected_areq(AuthRequest areq, PGconn *conn) case AUTH_REQ_OK: if (!pg_fe_scram_channel_bound(conn->sasl_state)) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("channel binding required, but server authenticated client without channel binding\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("channel binding required, but server authenticated client without channel binding\n")); result = false; } break; default: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("channel binding required but not supported by server's authentication request\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("channel binding required but not supported by server's authentication request\n")); result = false; break; } @@ -862,6 +866,8 @@ check_expected_areq(AuthRequest areq, PGconn *conn) int pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) { + int oldmsglen; + if (!check_expected_areq(areq, conn)) return STATUS_ERROR; @@ -871,13 +877,13 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) break; case AUTH_REQ_KRB4: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("Kerberos 4 authentication not supported\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("Kerberos 4 authentication not supported\n")); return STATUS_ERROR; case AUTH_REQ_KRB5: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("Kerberos 5 authentication not supported\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("Kerberos 5 authentication not supported\n")); return STATUS_ERROR; #if defined(ENABLE_GSS) || defined(ENABLE_SSPI) @@ -947,8 +953,8 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) /* No GSSAPI *or* SSPI support */ case AUTH_REQ_GSS: case AUTH_REQ_GSS_CONT: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("GSSAPI authentication not supported\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("GSSAPI authentication not supported\n")); return STATUS_ERROR; #endif /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */ @@ -979,16 +985,16 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) */ #if !defined(ENABLE_GSS) case AUTH_REQ_SSPI: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("SSPI authentication not supported\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("SSPI authentication not supported\n")); return STATUS_ERROR; #endif /* !define(ENABLE_GSS) */ #endif /* ENABLE_SSPI */ case AUTH_REQ_CRYPT: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("Crypt authentication not supported\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("Crypt authentication not supported\n")); return STATUS_ERROR; case AUTH_REQ_MD5: @@ -1002,14 +1008,14 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) password = conn->pgpass; if (password == NULL || password[0] == '\0') { - printfPQExpBuffer(&conn->errorMessage, - PQnoPasswordSupplied); + appendPQExpBufferStr(&conn->errorMessage, + PQnoPasswordSupplied); return STATUS_ERROR; } if (pg_password_sendauth(conn, password, areq) != STATUS_OK) { - printfPQExpBuffer(&conn->errorMessage, - "fe_sendauth: error sending password authentication\n"); + appendPQExpBufferStr(&conn->errorMessage, + "fe_sendauth: error sending password authentication\n"); return STATUS_ERROR; } break; @@ -1032,17 +1038,18 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) case AUTH_REQ_SASL_FIN: if (conn->sasl_state == NULL) { - printfPQExpBuffer(&conn->errorMessage, - "fe_sendauth: invalid authentication request from server: AUTH_REQ_SASL_CONT without AUTH_REQ_SASL\n"); + appendPQExpBufferStr(&conn->errorMessage, + "fe_sendauth: invalid authentication request from server: AUTH_REQ_SASL_CONT without AUTH_REQ_SASL\n"); return STATUS_ERROR; } + oldmsglen = conn->errorMessage.len; if (pg_SASL_continue(conn, payloadlen, (areq == AUTH_REQ_SASL_FIN)) != STATUS_OK) { - /* Use error message, if set already */ - if (conn->errorMessage.len == 0) - printfPQExpBuffer(&conn->errorMessage, - "fe_sendauth: error in SASL authentication\n"); + /* Use this message if pg_SASL_continue didn't supply one */ + if (conn->errorMessage.len == oldmsglen) + appendPQExpBufferStr(&conn->errorMessage, + "fe_sendauth: error in SASL authentication\n"); return STATUS_ERROR; } break; @@ -1053,7 +1060,7 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) break; default: - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("authentication method %u not supported\n"), areq); return STATUS_ERROR; } @@ -1067,7 +1074,7 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) * * Returns a pointer to malloc'd space containing whatever name the user * has authenticated to the system. If there is an error, return NULL, - * and put a suitable error message in *errorMessage if that's not NULL. + * and append a suitable error message to *errorMessage if that's not NULL. */ char * pg_fe_getauthname(PQExpBuffer errorMessage) @@ -1100,7 +1107,7 @@ pg_fe_getauthname(PQExpBuffer errorMessage) if (GetUserName(username, &namesize)) name = username; else if (errorMessage) - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("user name lookup failure: error code %lu\n"), GetLastError()); #else @@ -1110,12 +1117,12 @@ pg_fe_getauthname(PQExpBuffer errorMessage) else if (errorMessage) { if (pwerr != 0) - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("could not look up local user ID %d: %s\n"), (int) user_id, strerror_r(pwerr, pwdbuf, sizeof(pwdbuf))); else - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("local user with ID %d does not exist\n"), (int) user_id); } @@ -1125,8 +1132,8 @@ pg_fe_getauthname(PQExpBuffer errorMessage) { result = strdup(name); if (result == NULL && errorMessage) - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); } pgunlock_thread(); @@ -1196,6 +1203,8 @@ PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, if (!conn) return NULL; + resetPQExpBuffer(&conn->errorMessage); + /* If no algorithm was given, ask the server. */ if (algorithm == NULL) { @@ -1217,8 +1226,8 @@ PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, if (PQntuples(res) != 1 || PQnfields(res) != 1) { PQclear(res); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("unexpected shape of result set returned for SHOW\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("unexpected shape of result set returned for SHOW\n")); return NULL; } val = PQgetvalue(res, 0, 0); @@ -1226,8 +1235,8 @@ PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, if (strlen(val) > MAX_ALGORITHM_NAME_LEN) { PQclear(res); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("password_encryption value too long\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("password_encryption value too long\n")); return NULL; } strcpy(algobuf, val); @@ -1266,15 +1275,15 @@ PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, } else { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("unrecognized password encryption algorithm \"%s\"\n"), algorithm); return NULL; } if (!crypt_pwd) - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return crypt_pwd; } diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index a834ce8cf05d0..61a1fa6a14aad 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -755,7 +755,9 @@ PQconnectStartParams(const char *const *keywords, PQconninfoOption *connOptions; /* - * Allocate memory for the conn structure + * Allocate memory for the conn structure. Note that we also expect this + * to initialize conn->errorMessage to empty. All subsequent steps during + * connection initialization will only append to that buffer. */ conn = makeEmptyPGconn(); if (conn == NULL) @@ -831,7 +833,9 @@ PQconnectStart(const char *conninfo) PGconn *conn; /* - * Allocate memory for the conn structure + * Allocate memory for the conn structure. Note that we also expect this + * to initialize conn->errorMessage to empty. All subsequent steps during + * connection initialization will only append to that buffer. */ conn = makeEmptyPGconn(); if (conn == NULL) @@ -889,8 +893,8 @@ fillPGconn(PGconn *conn, PQconninfoOption *connOptions) *connmember = strdup(tmp); if (*connmember == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return false; } } @@ -1072,7 +1076,7 @@ connectOptions2(PGconn *conn) if (more || i != conn->nconnhost) { conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not match %d host names to %d hostaddr values\n"), count_comma_separated_elems(conn->pghost), conn->nconnhost); return false; @@ -1153,7 +1157,7 @@ connectOptions2(PGconn *conn) else if (more || i != conn->nconnhost) { conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not match %d port numbers to %d hosts\n"), count_comma_separated_elems(conn->pgport), conn->nconnhost); return false; @@ -1246,7 +1250,7 @@ connectOptions2(PGconn *conn) && strcmp(conn->channel_binding, "require") != 0) { conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid %s value: \"%s\"\n"), "channel_binding", conn->channel_binding); return false; @@ -1272,7 +1276,7 @@ connectOptions2(PGconn *conn) && strcmp(conn->sslmode, "verify-full") != 0) { conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid %s value: \"%s\"\n"), "sslmode", conn->sslmode); return false; @@ -1293,7 +1297,7 @@ connectOptions2(PGconn *conn) case 'r': /* "require" */ case 'v': /* "verify-ca" or "verify-full" */ conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("sslmode value \"%s\" invalid when SSL support is not compiled in\n"), conn->sslmode); return false; @@ -1314,7 +1318,7 @@ connectOptions2(PGconn *conn) if (!sslVerifyProtocolVersion(conn->ssl_min_protocol_version)) { conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid %s value: \"%s\"\n"), "ssl_min_protocol_version", conn->ssl_min_protocol_version); @@ -1323,7 +1327,7 @@ connectOptions2(PGconn *conn) if (!sslVerifyProtocolVersion(conn->ssl_max_protocol_version)) { conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid %s value: \"%s\"\n"), "ssl_max_protocol_version", conn->ssl_max_protocol_version); @@ -1341,8 +1345,8 @@ connectOptions2(PGconn *conn) conn->ssl_max_protocol_version)) { conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("invalid SSL protocol version range\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("invalid SSL protocol version range\n")); return false; } @@ -1356,7 +1360,7 @@ connectOptions2(PGconn *conn) strcmp(conn->gssencmode, "require") != 0) { conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid %s value: \"%s\"\n"), "gssencmode", conn->gssencmode); @@ -1366,7 +1370,7 @@ connectOptions2(PGconn *conn) if (strcmp(conn->gssencmode, "require") == 0) { conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("gssencmode value \"%s\" invalid when GSSAPI support is not compiled in\n"), conn->gssencmode); return false; @@ -1401,7 +1405,7 @@ connectOptions2(PGconn *conn) && strcmp(conn->target_session_attrs, "read-write") != 0) { conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid %s value: \"%s\"\n"), "target_settion_attrs", conn->target_session_attrs); @@ -1420,8 +1424,8 @@ connectOptions2(PGconn *conn) oom_error: conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return false; } @@ -1487,7 +1491,9 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, PGconn *conn; /* - * Allocate memory for the conn structure + * Allocate memory for the conn structure. Note that we also expect this + * to initialize conn->errorMessage to empty. All subsequent steps during + * connection initialization will only append to that buffer. */ conn = makeEmptyPGconn(); if (conn == NULL) @@ -1596,8 +1602,8 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, oom_error: conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return conn; } @@ -2017,8 +2023,8 @@ connectDBStart(PGconn *conn) */ if (!pg_link_canary_is_frontend()) { - printfPQExpBuffer(&conn->errorMessage, - "libpq is incorrectly linked to backend functions\n"); + appendPQExpBufferStr(&conn->errorMessage, + "libpq is incorrectly linked to backend functions\n"); goto connect_errReturn; } @@ -2026,14 +2032,6 @@ connectDBStart(PGconn *conn) conn->inStart = conn->inCursor = conn->inEnd = 0; conn->outCount = 0; - /* - * Ensure errorMessage is empty, too. PQconnectPoll will append messages - * to it in the process of scanning for a working server. Thus, if we - * fail to connect to multiple hosts, the final error message will include - * details about each failure. - */ - resetPQExpBuffer(&conn->errorMessage); - /* * Set up to try to connect to the first host. (Setting whichhost = -1 is * a bit of a cheat, but PQconnectPoll will advance it to 0 before @@ -2139,12 +2137,6 @@ connectDBComplete(PGconn *conn) switch (flag) { case PGRES_POLLING_OK: - - /* - * Reset stored error messages since we now have a working - * connection - */ - resetPQExpBuffer(&conn->errorMessage); return 1; /* success! */ case PGRES_POLLING_READING: @@ -2189,46 +2181,6 @@ connectDBComplete(PGconn *conn) } } -/* - * This subroutine saves conn->errorMessage, which will be restored back by - * restoreErrorMessage subroutine. Returns false on OOM failure. - */ -static bool -saveErrorMessage(PGconn *conn, PQExpBuffer savedMessage) -{ - initPQExpBuffer(savedMessage); - appendPQExpBufferStr(savedMessage, - conn->errorMessage.data); - if (PQExpBufferBroken(savedMessage)) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); - return false; - } - /* Clear whatever is in errorMessage now */ - resetPQExpBuffer(&conn->errorMessage); - return true; -} - -/* - * Restores saved error messages back to conn->errorMessage, prepending them - * to whatever is in conn->errorMessage already. (This does the right thing - * if anything's been added to conn->errorMessage since saveErrorMessage.) - */ -static void -restoreErrorMessage(PGconn *conn, PQExpBuffer savedMessage) -{ - appendPQExpBufferStr(savedMessage, conn->errorMessage.data); - resetPQExpBuffer(&conn->errorMessage); - appendPQExpBufferStr(&conn->errorMessage, savedMessage->data); - /* If any step above hit OOM, just report that */ - if (PQExpBufferBroken(savedMessage) || - PQExpBufferBroken(&conn->errorMessage)) - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); - termPQExpBuffer(savedMessage); -} - /* ---------------- * PQconnectPoll * @@ -2264,7 +2216,6 @@ PQconnectPoll(PGconn *conn) PGresult *res; char sebuf[PG_STRERROR_R_BUFLEN]; int optval; - PQExpBufferData savedMessage; if (conn == NULL) return PGRES_POLLING_FAILED; @@ -2954,12 +2905,8 @@ PQconnectPoll(PGconn *conn) EnvironmentOptions); if (!startpacket) { - /* - * will not appendbuffer here, since it's likely to also - * run out of memory - */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); goto error_return; } @@ -3448,7 +3395,6 @@ PQconnectPoll(PGconn *conn) * avoid the Kerberos code doing a hostname look-up. */ res = pg_fe_sendauth(areq, msgLength, conn); - conn->errorMessage.len = strlen(conn->errorMessage.data); /* OK, we have processed the message; mark data consumed */ conn->inStart = conn->inCursor; @@ -3576,24 +3522,16 @@ PQconnectPoll(PGconn *conn) strcmp(conn->target_session_attrs, "read-write") == 0) { /* - * Save existing error messages across the PQsendQuery - * attempt. This is necessary because PQsendQuery is - * going to reset conn->errorMessage, so we would lose - * error messages related to previous hosts we have tried - * and failed to connect to. + * We use PQsendQueryContinue so that conn->errorMessage + * does not get cleared. We need to preserve any error + * messages related to previous hosts we have tried and + * failed to connect to. */ - if (!saveErrorMessage(conn, &savedMessage)) - goto error_return; - conn->status = CONNECTION_OK; - if (!PQsendQuery(conn, - "SHOW transaction_read_only")) - { - restoreErrorMessage(conn, &savedMessage); + if (!PQsendQueryContinue(conn, + "SHOW transaction_read_only")) goto error_return; - } conn->status = CONNECTION_CHECK_WRITABLE; - restoreErrorMessage(conn, &savedMessage); return PGRES_POLLING_READING; } @@ -3673,20 +3611,13 @@ PQconnectPoll(PGconn *conn) const char *displayed_host; const char *displayed_port; - if (!saveErrorMessage(conn, &savedMessage)) - goto error_return; - conn->status = CONNECTION_OK; if (!PQconsumeInput(conn)) - { - restoreErrorMessage(conn, &savedMessage); goto error_return; - } if (PQisBusy(conn)) { conn->status = CONNECTION_CHECK_WRITABLE; - restoreErrorMessage(conn, &savedMessage); return PGRES_POLLING_READING; } @@ -3701,7 +3632,6 @@ PQconnectPoll(PGconn *conn) { /* Not writable; fail this connection. */ PQclear(res); - restoreErrorMessage(conn, &savedMessage); /* Append error report to conn->errorMessage. */ if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS) @@ -3732,7 +3662,6 @@ PQconnectPoll(PGconn *conn) /* Session is read-write, so we're good. */ PQclear(res); - termPQExpBuffer(&savedMessage); /* * Finish reading any remaining messages before being @@ -3748,7 +3677,6 @@ PQconnectPoll(PGconn *conn) */ if (res) PQclear(res); - restoreErrorMessage(conn, &savedMessage); /* Append error report to conn->errorMessage. */ if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS) @@ -4157,6 +4085,9 @@ closePGconn(PGconn *conn) /* * Close the connection, reset all transient state, flush I/O buffers. + * Note that this includes clearing conn->errorMessage; we're no longer + * interested in any failures associated with the old connection, and we + * want a clean slate for any new connection attempt. */ pqDropConnection(conn, true); conn->status = CONNECTION_BAD; /* Well, not really _bad_ - just absent */ @@ -4212,7 +4143,7 @@ PQreset(PGconn *conn) conn->events[i].passThrough)) { conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("PGEventProc \"%s\" failed during PGEVT_CONNRESET event\n"), conn->events[i].name); break; @@ -4272,7 +4203,7 @@ PQresetPoll(PGconn *conn) conn->events[i].passThrough)) { conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("PGEventProc \"%s\" failed during PGEVT_CONNRESET event\n"), conn->events[i].name); return PGRES_POLLING_FAILED; @@ -4569,7 +4500,7 @@ pqPacketSend(PGconn *conn, char pack_type, * 2 if a connection could not be established, and * 3 if a fatal error occurred. * - * An error message is returned in the third argument for return codes 1 and 3. + * An error message is appended to *errorMessage for return codes 1 and 3. */ static int ldapServiceLookup(const char *purl, PQconninfoOption *options, @@ -4607,7 +4538,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, if ((url = strdup(purl)) == NULL) { - printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, libpq_gettext("out of memory\n")); return 3; } @@ -4619,7 +4550,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, if (pg_strncasecmp(url, LDAP_URL, strlen(LDAP_URL)) != 0) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("invalid LDAP URL \"%s\": scheme must be ldap://\n"), purl); free(url); return 3; @@ -4634,7 +4565,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, p = strchr(url + strlen(LDAP_URL), '/'); if (p == NULL || *(p + 1) == '\0' || *(p + 1) == '?') { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("invalid LDAP URL \"%s\": missing distinguished name\n"), purl); free(url); @@ -4646,7 +4577,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, /* attribute */ if ((p = strchr(dn, '?')) == NULL || *(p + 1) == '\0' || *(p + 1) == '?') { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("invalid LDAP URL \"%s\": must have exactly one attribute\n"), purl); free(url); @@ -4658,7 +4589,9 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, /* scope */ if ((p = strchr(attrs[0], '?')) == NULL || *(p + 1) == '\0' || *(p + 1) == '?') { - printfPQExpBuffer(errorMessage, libpq_gettext("invalid LDAP URL \"%s\": must have search scope (base/one/sub)\n"), purl); + appendPQExpBuffer(errorMessage, + libpq_gettext("invalid LDAP URL \"%s\": must have search scope (base/one/sub)\n"), + purl); free(url); return 3; } @@ -4668,8 +4601,9 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, /* filter */ if ((p = strchr(scopestr, '?')) == NULL || *(p + 1) == '\0' || *(p + 1) == '?') { - printfPQExpBuffer(errorMessage, - libpq_gettext("invalid LDAP URL \"%s\": no filter\n"), purl); + appendPQExpBuffer(errorMessage, + libpq_gettext("invalid LDAP URL \"%s\": no filter\n"), + purl); free(url); return 3; } @@ -4689,7 +4623,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, lport = strtol(portstr, &endptr, 10); if (*portstr == '\0' || *endptr != '\0' || errno || lport < 0 || lport > 65535) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("invalid LDAP URL \"%s\": invalid port number\n"), purl); free(url); @@ -4701,7 +4635,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, /* Allow only one attribute */ if (strchr(attrs[0], ',') != NULL) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("invalid LDAP URL \"%s\": must have exactly one attribute\n"), purl); free(url); @@ -4717,7 +4651,9 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, scope = LDAP_SCOPE_SUBTREE; else { - printfPQExpBuffer(errorMessage, libpq_gettext("invalid LDAP URL \"%s\": must have search scope (base/one/sub)\n"), purl); + appendPQExpBuffer(errorMessage, + libpq_gettext("invalid LDAP URL \"%s\": must have search scope (base/one/sub)\n"), + purl); free(url); return 3; } @@ -4725,8 +4661,8 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, /* initialize LDAP structure */ if ((ld = ldap_init(hostname, port)) == NULL) { - printfPQExpBuffer(errorMessage, - libpq_gettext("could not create LDAP structure\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("could not create LDAP structure\n")); free(url); return 3; } @@ -4801,7 +4737,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, { if (res != NULL) ldap_msgfree(res); - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("lookup on LDAP server failed: %s\n"), ldap_err2string(rc)); ldap_unbind(ld); @@ -4812,9 +4748,9 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, /* complain if there was not exactly one result */ if ((rc = ldap_count_entries(ld, res)) != 1) { - printfPQExpBuffer(errorMessage, - rc ? libpq_gettext("more than one entry found on LDAP lookup\n") - : libpq_gettext("no entry found on LDAP lookup\n")); + appendPQExpBufferStr(errorMessage, + rc ? libpq_gettext("more than one entry found on LDAP lookup\n") + : libpq_gettext("no entry found on LDAP lookup\n")); ldap_msgfree(res); ldap_unbind(ld); free(url); @@ -4825,8 +4761,8 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, if ((entry = ldap_first_entry(ld, res)) == NULL) { /* should never happen */ - printfPQExpBuffer(errorMessage, - libpq_gettext("no entry found on LDAP lookup\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("no entry found on LDAP lookup\n")); ldap_msgfree(res); ldap_unbind(ld); free(url); @@ -4836,8 +4772,8 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, /* get values */ if ((values = ldap_get_values_len(ld, entry, attrs[0])) == NULL) { - printfPQExpBuffer(errorMessage, - libpq_gettext("attribute has no values on LDAP lookup\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("attribute has no values on LDAP lookup\n")); ldap_msgfree(res); ldap_unbind(ld); free(url); @@ -4849,8 +4785,8 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, if (values[0] == NULL) { - printfPQExpBuffer(errorMessage, - libpq_gettext("attribute has no values on LDAP lookup\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("attribute has no values on LDAP lookup\n")); ldap_value_free_len(values); ldap_unbind(ld); return 1; @@ -4862,8 +4798,8 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, size += values[i]->bv_len + 1; if ((result = malloc(size)) == NULL) { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); ldap_value_free_len(values); ldap_unbind(ld); return 3; @@ -4901,7 +4837,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, } else if (ld_is_nl_cr(*p)) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("missing \"=\" after \"%s\" in connection info string\n"), optname); free(result); @@ -4920,7 +4856,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, } else if (!ld_is_sp_tab(*p)) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("missing \"=\" after \"%s\" in connection info string\n"), optname); free(result); @@ -4981,8 +4917,8 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, options[i].val = strdup(optval); if (!options[i].val) { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); free(result); return 3; } @@ -4993,7 +4929,7 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, } if (!found_keyword) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("invalid connection option \"%s\"\n"), optname); free(result); @@ -5009,8 +4945,8 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options, if (state == 5 || state == 6) { - printfPQExpBuffer(errorMessage, - libpq_gettext("unterminated quoted string in connection info string\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("unterminated quoted string in connection info string\n")); return 3; } @@ -5090,7 +5026,7 @@ parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage) last_file: if (!group_found) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("definition of service \"%s\" not found\n"), service); return 3; } @@ -5117,7 +5053,7 @@ parseServiceFile(const char *serviceFile, f = fopen(serviceFile, "r"); if (f == NULL) { - printfPQExpBuffer(errorMessage, libpq_gettext("service file \"%s\" not found\n"), + appendPQExpBuffer(errorMessage, libpq_gettext("service file \"%s\" not found\n"), serviceFile); return 1; } @@ -5193,7 +5129,7 @@ parseServiceFile(const char *serviceFile, val = strchr(line, '='); if (val == NULL) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("syntax error in service file \"%s\", line %d\n"), serviceFile, linenr); @@ -5204,7 +5140,7 @@ parseServiceFile(const char *serviceFile, if (strcmp(key, "service") == 0) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("nested service specifications not supported in service file \"%s\", line %d\n"), serviceFile, linenr); @@ -5225,8 +5161,8 @@ parseServiceFile(const char *serviceFile, options[i].val = strdup(val); if (!options[i].val) { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); result = 3; goto exit; } @@ -5237,7 +5173,7 @@ parseServiceFile(const char *serviceFile, if (!found_keyword) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("syntax error in service file \"%s\", line %d\n"), serviceFile, linenr); @@ -5307,8 +5243,8 @@ conninfo_init(PQExpBuffer errorMessage) options = (PQconninfoOption *) malloc(sizeof(PQconninfoOption) * sizeof(PQconninfoOptions) / sizeof(PQconninfoOptions[0])); if (options == NULL) { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); return NULL; } opt_dest = options; @@ -5328,7 +5264,7 @@ conninfo_init(PQExpBuffer errorMessage) * Connection string parser * * Returns a malloc'd PQconninfoOption array, if parsing is successful. - * Otherwise, NULL is returned and an error message is left in errorMessage. + * Otherwise, NULL is returned and an error message is added to errorMessage. * * If use_defaults is true, default values are filled in (from a service file, * environment variables, etc). @@ -5406,8 +5342,8 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage, /* Need a modifiable copy of the input string */ if ((buf = strdup(conninfo)) == NULL) { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); PQconninfoFree(options); return NULL; } @@ -5445,7 +5381,7 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage, /* Check that there is a following '=' */ if (*cp != '=') { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("missing \"=\" after \"%s\" in connection info string\n"), pname); PQconninfoFree(options); @@ -5494,8 +5430,8 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage, { if (*cp == '\0') { - printfPQExpBuffer(errorMessage, - libpq_gettext("unterminated quoted string in connection info string\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("unterminated quoted string in connection info string\n")); PQconninfoFree(options); free(buf); return NULL; @@ -5551,7 +5487,7 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage, * * If successful, a malloc'd PQconninfoOption array is returned. * If not successful, NULL is returned and an error message is - * left in errorMessage. + * appended to errorMessage. * Defaults are supplied (from a service file, environment variables, etc) * for unspecified options, but only if use_defaults is true. * @@ -5630,7 +5566,7 @@ conninfo_array_parse(const char *const *keywords, const char *const *values, /* Check for invalid connection option */ if (option->keyword == NULL) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("invalid connection option \"%s\"\n"), pname); PQconninfoFree(options); @@ -5662,8 +5598,8 @@ conninfo_array_parse(const char *const *keywords, const char *const *values, options[k].val = strdup(str_option->val); if (!options[k].val) { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); PQconninfoFree(options); PQconninfoFree(dbname_options); return NULL; @@ -5691,8 +5627,8 @@ conninfo_array_parse(const char *const *keywords, const char *const *values, option->val = strdup(pvalue); if (!option->val) { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); PQconninfoFree(options); PQconninfoFree(dbname_options); return NULL; @@ -5763,8 +5699,8 @@ conninfo_add_defaults(PQconninfoOption *options, PQExpBuffer errorMessage) if (!option->val) { if (errorMessage) - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); return false; } continue; @@ -5787,8 +5723,8 @@ conninfo_add_defaults(PQconninfoOption *options, PQExpBuffer errorMessage) if (!option->val) { if (errorMessage) - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); return false; } continue; @@ -5805,8 +5741,8 @@ conninfo_add_defaults(PQconninfoOption *options, PQExpBuffer errorMessage) if (!option->val) { if (errorMessage) - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); return false; } continue; @@ -5906,8 +5842,8 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri, initPQExpBuffer(&portbuf); if (PQExpBufferDataBroken(hostbuf) || PQExpBufferDataBroken(portbuf)) { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); goto cleanup; } @@ -5915,8 +5851,8 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri, buf = strdup(uri); if (buf == NULL) { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, + libpq_gettext("out of memory\n")); goto cleanup; } start = buf; @@ -5926,7 +5862,7 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri, if (prefix_len == 0) { /* Should never happen */ - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("invalid URI propagated to internal parser routine: \"%s\"\n"), uri); goto cleanup; @@ -6003,14 +5939,14 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri, ++p; if (!*p) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("end of string reached when looking for matching \"]\" in IPv6 host address in URI: \"%s\"\n"), uri); goto cleanup; } if (p == host) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("IPv6 host address may not be empty in URI: \"%s\"\n"), uri); goto cleanup; @@ -6025,7 +5961,7 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri, */ if (*p && *p != ':' && *p != '/' && *p != '?' && *p != ',') { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("unexpected character \"%c\" at position %d in URI (expected \":\" or \"/\"): \"%s\"\n"), *p, (int) (p - buf + 1), uri); goto cleanup; @@ -6142,6 +6078,7 @@ conninfo_uri_parse_params(char *params, char *value = NULL; char *p = params; bool malloced = false; + int oldmsglen; /* * Scan the params string for '=' and '&', marking the end of keyword @@ -6154,7 +6091,7 @@ conninfo_uri_parse_params(char *params, /* Was there '=' already? */ if (value != NULL) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("extra key/value separator \"=\" in URI query parameter: \"%s\"\n"), keyword); return false; @@ -6174,7 +6111,7 @@ conninfo_uri_parse_params(char *params, /* Was there '=' at all? */ if (value == NULL) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("missing key/value separator \"=\" in URI query parameter: \"%s\"\n"), keyword); return false; @@ -6220,12 +6157,13 @@ conninfo_uri_parse_params(char *params, * otherwise. At this point both keyword and value are not * URI-encoded. */ + oldmsglen = errorMessage->len; if (!conninfo_storeval(connOptions, keyword, value, errorMessage, true, false)) { /* Insert generic message if conninfo_storeval didn't give one. */ - if (errorMessage->len == 0) - printfPQExpBuffer(errorMessage, + if (errorMessage->len == oldmsglen) + appendPQExpBuffer(errorMessage, libpq_gettext("invalid URI query parameter: \"%s\"\n"), keyword); /* And fail. */ @@ -6272,7 +6210,7 @@ conninfo_uri_decode(const char *str, PQExpBuffer errorMessage) buf = malloc(strlen(str) + 1); if (buf == NULL) { - printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, libpq_gettext("out of memory\n")); return NULL; } p = buf; @@ -6299,7 +6237,7 @@ conninfo_uri_decode(const char *str, PQExpBuffer errorMessage) */ if (!(get_hexdigit(*q++, &hi) && get_hexdigit(*q++, &lo))) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("invalid percent-encoded token: \"%s\"\n"), str); free(buf); @@ -6309,7 +6247,7 @@ conninfo_uri_decode(const char *str, PQExpBuffer errorMessage) c = (hi << 4) | lo; if (c == 0) { - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("forbidden value %%00 in percent-encoded value: \"%s\"\n"), str); free(buf); @@ -6404,7 +6342,7 @@ conninfo_storeval(PQconninfoOption *connOptions, if (option == NULL) { if (!ignoreMissing) - printfPQExpBuffer(errorMessage, + appendPQExpBuffer(errorMessage, libpq_gettext("invalid connection option \"%s\"\n"), keyword); return NULL; @@ -6422,7 +6360,7 @@ conninfo_storeval(PQconninfoOption *connOptions, value_copy = strdup(value); if (value_copy == NULL) { - printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n")); + appendPQExpBufferStr(errorMessage, libpq_gettext("out of memory\n")); return NULL; } } @@ -6469,7 +6407,10 @@ PQconninfo(PGconn *conn) if (conn == NULL) return NULL; - /* We don't actually report any errors here, but callees want a buffer */ + /* + * We don't actually report any errors here, but callees want a buffer, + * and we prefer not to trash the conn's errorMessage. + */ initPQExpBuffer(&errorBuf); if (PQExpBufferDataBroken(errorBuf)) return NULL; /* out of memory already :-( */ diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index d48f0fd587b88..e730753387615 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -53,7 +53,8 @@ static bool static_std_strings = false; static PGEvent *dupEvents(PGEvent *events, int count, size_t *memSize); static bool pqAddTuple(PGresult *res, PGresAttValue *tup, const char **errmsgp); -static bool PQsendQueryStart(PGconn *conn); +static int PQsendQueryInternal(PGconn *conn, const char *query, bool newQuery); +static bool PQsendQueryStart(PGconn *conn, bool newQuery); static int PQsendQueryGuts(PGconn *conn, const char *command, const char *stmtName, @@ -667,25 +668,6 @@ pqSetResultError(PGresult *res, const char *msg) res->errMsg = NULL; } -/* - * pqCatenateResultError - - * concatenate a new error message to the one already in a PGresult - */ -void -pqCatenateResultError(PGresult *res, const char *msg) -{ - PQExpBufferData errorBuf; - - if (!res || !msg) - return; - initPQExpBuffer(&errorBuf); - if (res->errMsg) - appendPQExpBufferStr(&errorBuf, res->errMsg); - appendPQExpBufferStr(&errorBuf, msg); - pqSetResultError(res, errorBuf.data); - termPQExpBuffer(&errorBuf); -} - /* * PQclear - * free's the memory associated with a PGresult @@ -759,68 +741,46 @@ pqClearAsyncResult(PGconn *conn) /* * This subroutine deletes any existing async result, sets conn->result * to a PGresult with status PGRES_FATAL_ERROR, and stores the current - * contents of conn->errorMessage into that result. It differs from a - * plain call on PQmakeEmptyPGresult() in that if there is already an - * async result with status PGRES_FATAL_ERROR, the current error message - * is APPENDED to the old error message instead of replacing it. This - * behavior lets us report multiple error conditions properly, if necessary. - * (An example where this is needed is when the backend sends an 'E' message - * and immediately closes the connection --- we want to report both the - * backend error and the connection closure error.) + * contents of conn->errorMessage into that result. */ void pqSaveErrorResult(PGconn *conn) { - /* - * If no old async result, just let PQmakeEmptyPGresult make one. Likewise - * if old result is not an error message. - */ - if (conn->result == NULL || - conn->result->resultStatus != PGRES_FATAL_ERROR || - conn->result->errMsg == NULL) - { - pqClearAsyncResult(conn); - conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); - } - else - { - /* Else, concatenate error message to existing async result. */ - pqCatenateResultError(conn->result, conn->errorMessage.data); - } + pqClearAsyncResult(conn); + conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); } /* - * As above, and append conn->write_err_msg to whatever other error we have. - * This is used when we've detected a write failure and have exhausted our - * chances of reporting something else instead. + * As above, after appending conn->write_err_msg to whatever other error we + * have. This is used when we've detected a write failure and have exhausted + * our chances of reporting something else instead. */ static void pqSaveWriteError(PGconn *conn) { /* - * Ensure conn->result is an error result, and add anything in - * conn->errorMessage to it. + * If write_err_msg is null because of previous strdup failure, do what we + * can. (It's likely our machinations here will get OOM failures as well, + * but might as well try.) */ - pqSaveErrorResult(conn); - - /* - * Now append write_err_msg to that. If it's null because of previous - * strdup failure, do what we can. (It's likely our machinations here are - * all getting OOM failures as well, but ...) - */ - if (conn->write_err_msg && conn->write_err_msg[0] != '\0') - pqCatenateResultError(conn->result, conn->write_err_msg); + if (conn->write_err_msg) + { + appendPQExpBufferStr(&conn->errorMessage, conn->write_err_msg); + /* Avoid possibly appending the same message twice */ + conn->write_err_msg[0] = '\0'; + } else - pqCatenateResultError(conn->result, - libpq_gettext("write to server failed\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("write to server failed\n")); + + pqSaveErrorResult(conn); } /* * This subroutine prepares an async result object for return to the caller. * If there is not already an async result object, build an error object * using whatever is in conn->errorMessage. In any case, clear the async - * result storage and make sure PQerrorMessage will agree with the result's - * error string. + * result storage. */ PGresult * pqPrepareAsyncResult(PGconn *conn) @@ -835,16 +795,6 @@ pqPrepareAsyncResult(PGconn *conn) res = conn->result; if (!res) res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); - else - { - /* - * Make sure PQerrorMessage agrees with result; it could be different - * if we have concatenated messages. - */ - resetPQExpBuffer(&conn->errorMessage); - appendPQExpBufferStr(&conn->errorMessage, - PQresultErrorMessage(res)); - } /* * Replace conn->result with next_result, if any. In the normal case @@ -1229,18 +1179,33 @@ pqRowProcessor(PGconn *conn, const char **errmsgp) * * Returns: 1 if successfully submitted * 0 if error (conn->errorMessage is set) + * + * PQsendQueryContinue is a non-exported version that behaves identically + * except that it doesn't reset conn->errorMessage. */ int PQsendQuery(PGconn *conn, const char *query) { - if (!PQsendQueryStart(conn)) + return PQsendQueryInternal(conn, query, true); +} + +int +PQsendQueryContinue(PGconn *conn, const char *query) +{ + return PQsendQueryInternal(conn, query, false); +} + +static int +PQsendQueryInternal(PGconn *conn, const char *query, bool newQuery) +{ + if (!PQsendQueryStart(conn, newQuery)) return 0; /* check the argument */ if (!query) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("command string is a null pointer\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("command string is a null pointer\n")); return 0; } @@ -1291,20 +1256,20 @@ PQsendQueryParams(PGconn *conn, const int *paramFormats, int resultFormat) { - if (!PQsendQueryStart(conn)) + if (!PQsendQueryStart(conn, true)) return 0; /* check the arguments */ if (!command) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("command string is a null pointer\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("command string is a null pointer\n")); return 0; } if (nParams < 0 || nParams > 65535) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("number of parameters must be between 0 and 65535\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("number of parameters must be between 0 and 65535\n")); return 0; } @@ -1331,34 +1296,34 @@ PQsendPrepare(PGconn *conn, const char *stmtName, const char *query, int nParams, const Oid *paramTypes) { - if (!PQsendQueryStart(conn)) + if (!PQsendQueryStart(conn, true)) return 0; /* check the arguments */ if (!stmtName) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("statement name is a null pointer\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("statement name is a null pointer\n")); return 0; } if (!query) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("command string is a null pointer\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("command string is a null pointer\n")); return 0; } if (nParams < 0 || nParams > 65535) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("number of parameters must be between 0 and 65535\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("number of parameters must be between 0 and 65535\n")); return 0; } /* This isn't gonna work on a 2.0 server */ if (PG_PROTOCOL_MAJOR(conn->pversion) < 3) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("function requires at least protocol version 3.0\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("function requires at least protocol version 3.0\n")); return 0; } @@ -1432,20 +1397,20 @@ PQsendQueryPrepared(PGconn *conn, const int *paramFormats, int resultFormat) { - if (!PQsendQueryStart(conn)) + if (!PQsendQueryStart(conn, true)) return 0; /* check the arguments */ if (!stmtName) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("statement name is a null pointer\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("statement name is a null pointer\n")); return 0; } if (nParams < 0 || nParams > 65535) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("number of parameters must be between 0 and 65535\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("number of parameters must be between 0 and 65535\n")); return 0; } @@ -1464,26 +1429,29 @@ PQsendQueryPrepared(PGconn *conn, * Common startup code for PQsendQuery and sibling routines */ static bool -PQsendQueryStart(PGconn *conn) +PQsendQueryStart(PGconn *conn, bool newQuery) { if (!conn) return false; - /* clear the error string */ - resetPQExpBuffer(&conn->errorMessage); + /* + * If this is the beginning of a query cycle, reset the error buffer. + */ + if (newQuery) + resetPQExpBuffer(&conn->errorMessage); /* Don't try to send if we know there's no live connection. */ if (conn->status != CONNECTION_OK) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("no connection to the server\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("no connection to the server\n")); return false; } /* Can't send while already busy, either. */ if (conn->asyncStatus != PGASYNC_IDLE) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("another command is already in progress\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("another command is already in progress\n")); return false; } @@ -1520,8 +1488,8 @@ PQsendQueryGuts(PGconn *conn, /* This isn't gonna work on a 2.0 server */ if (PG_PROTOCOL_MAJOR(conn->pversion) < 3) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("function requires at least protocol version 3.0\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("function requires at least protocol version 3.0\n")); return 0; } @@ -1596,8 +1564,8 @@ PQsendQueryGuts(PGconn *conn, nbytes = paramLengths[i]; else { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("length must be given for binary parameter\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("length must be given for binary parameter\n")); goto sendFailed; } } @@ -1859,7 +1827,7 @@ PQgetResult(PGconn *conn) res = getCopyResult(conn, PGRES_COPY_BOTH); break; default: - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("unexpected asyncStatus: %d\n"), (int) conn->asyncStatus); res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); @@ -1879,7 +1847,7 @@ PQgetResult(PGconn *conn) if (!res->events[i].proc(PGEVT_RESULTCREATE, &evt, res->events[i].passThrough)) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("PGEventProc \"%s\" failed during PGEVT_RESULTCREATE event\n"), res->events[i].name); pqSetResultError(res, conn->errorMessage.data); @@ -2025,6 +1993,11 @@ PQexecStart(PGconn *conn) if (!conn) return false; + /* + * Since this is the beginning of a query cycle, reset the error buffer. + */ + resetPQExpBuffer(&conn->errorMessage); + /* * Silently discard any prior query result that application didn't eat. * This is probably poor design, but it's here for backward compatibility. @@ -2047,8 +2020,8 @@ PQexecStart(PGconn *conn) else { /* In older protocols we have to punt */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("COPY IN state must be terminated first\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("COPY IN state must be terminated first\n")); return false; } } @@ -2067,16 +2040,16 @@ PQexecStart(PGconn *conn) else { /* In older protocols we have to punt */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("COPY OUT state must be terminated first\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("COPY OUT state must be terminated first\n")); return false; } } else if (resultStatus == PGRES_COPY_BOTH) { /* We don't allow PQexec during COPY BOTH */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("PQexec not allowed during COPY BOTH\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("PQexec not allowed during COPY BOTH\n")); return false; } /* check for loss of connection, too */ @@ -2099,8 +2072,9 @@ PQexecFinish(PGconn *conn) /* * For backwards compatibility, return the last result if there are more - * than one --- but merge error messages if we get more than one error - * result. + * than one. (We used to have logic here to concatenate successive error + * messages, but now that happens automatically, since conn->errorMessage + * will continue to accumulate errors throughout this loop.) * * We have to stop if we see copy in/out/both, however. We will resume * parsing after application performs the data transfer. @@ -2111,23 +2085,7 @@ PQexecFinish(PGconn *conn) while ((result = PQgetResult(conn)) != NULL) { if (lastResult) - { - if (lastResult->resultStatus == PGRES_FATAL_ERROR && - result->resultStatus == PGRES_FATAL_ERROR) - { - pqCatenateResultError(lastResult, result->errMsg); - PQclear(result); - result = lastResult; - - /* - * Make sure PQerrorMessage agrees with concatenated result - */ - resetPQExpBuffer(&conn->errorMessage); - appendPQExpBufferStr(&conn->errorMessage, result->errMsg); - } - else - PQclear(lastResult); - } + PQclear(lastResult); lastResult = result; if (result->resultStatus == PGRES_COPY_IN || result->resultStatus == PGRES_COPY_OUT || @@ -2223,14 +2181,14 @@ PQsendDescribe(PGconn *conn, char desc_type, const char *desc_target) if (!desc_target) desc_target = ""; - if (!PQsendQueryStart(conn)) + if (!PQsendQueryStart(conn, true)) return 0; /* This isn't gonna work on a 2.0 server */ if (PG_PROTOCOL_MAJOR(conn->pversion) < 3) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("function requires at least protocol version 3.0\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("function requires at least protocol version 3.0\n")); return 0; } @@ -2321,8 +2279,8 @@ PQputCopyData(PGconn *conn, const char *buffer, int nbytes) if (conn->asyncStatus != PGASYNC_COPY_IN && conn->asyncStatus != PGASYNC_COPY_BOTH) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("no COPY in progress\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("no COPY in progress\n")); return -1; } @@ -2388,8 +2346,8 @@ PQputCopyEnd(PGconn *conn, const char *errormsg) if (conn->asyncStatus != PGASYNC_COPY_IN && conn->asyncStatus != PGASYNC_COPY_BOTH) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("no COPY in progress\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("no COPY in progress\n")); return -1; } @@ -2431,8 +2389,8 @@ PQputCopyEnd(PGconn *conn, const char *errormsg) if (errormsg) { /* Oops, no way to do this in 2.0 */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("function requires at least protocol version 3.0\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("function requires at least protocol version 3.0\n")); return -1; } else @@ -2450,7 +2408,6 @@ PQputCopyEnd(PGconn *conn, const char *errormsg) conn->asyncStatus = PGASYNC_COPY_OUT; else conn->asyncStatus = PGASYNC_BUSY; - resetPQExpBuffer(&conn->errorMessage); /* Try to flush data */ if (pqFlush(conn) < 0) @@ -2478,8 +2435,8 @@ PQgetCopyData(PGconn *conn, char **buffer, int async) if (conn->asyncStatus != PGASYNC_COPY_OUT && conn->asyncStatus != PGASYNC_COPY_BOTH) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("no COPY in progress\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("no COPY in progress\n")); return -2; } if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) @@ -2662,14 +2619,16 @@ PQfn(PGconn *conn, if (!conn) return NULL; - /* clear the error string */ + /* + * Since this is the beginning of a query cycle, reset the error buffer. + */ resetPQExpBuffer(&conn->errorMessage); if (conn->sock == PGINVALID_SOCKET || conn->asyncStatus != PGASYNC_IDLE || conn->result != NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("connection in wrong state\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("connection in wrong state\n")); return NULL; } @@ -3246,7 +3205,11 @@ PQsetnonblocking(PGconn *conn, int arg) * need to flush the send queue at this point in order to guarantee proper * behavior. this is ok because either they are making a transition _from_ * or _to_ blocking mode, either way we can block them. + * + * Clear errorMessage in case pqFlush adds to it. */ + resetPQExpBuffer(&conn->errorMessage); + /* if we are going from blocking to non-blocking flush here */ if (pqFlush(conn)) return -1; @@ -3388,8 +3351,8 @@ PQescapeStringInternal(PGconn *conn, if (error) *error = 1; if (conn) - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("incomplete multibyte character\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("incomplete multibyte character\n")); for (; i < len; i++) { if (((size_t) (target - to)) / 2 >= length) @@ -3419,6 +3382,9 @@ PQescapeStringConn(PGconn *conn, *error = 1; return 0; } + + resetPQExpBuffer(&conn->errorMessage); + return PQescapeStringInternal(conn, to, from, length, error, conn->client_encoding, conn->std_strings); @@ -3455,6 +3421,8 @@ PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident) if (!conn) return NULL; + resetPQExpBuffer(&conn->errorMessage); + /* Scan the string for characters that must be escaped. */ for (s = str; (s - str) < len && *s != '\0'; ++s) { @@ -3472,8 +3440,8 @@ PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident) /* Multibyte character overruns allowable length. */ if ((s - str) + charlen > len || memchr(s, 0, charlen) != NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("incomplete multibyte character\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("incomplete multibyte character\n")); return NULL; } @@ -3490,8 +3458,8 @@ PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident) result = rp = (char *) malloc(result_size); if (rp == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return NULL; } @@ -3655,8 +3623,8 @@ PQescapeByteaInternal(PGconn *conn, if (rp == NULL) { if (conn) - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return NULL; } @@ -3717,6 +3685,9 @@ PQescapeByteaConn(PGconn *conn, { if (!conn) return NULL; + + resetPQExpBuffer(&conn->errorMessage); + return PQescapeByteaInternal(conn, from, from_length, to_length, conn->std_strings, (conn->sversion >= 90000)); diff --git a/src/interfaces/libpq/fe-gssapi-common.c b/src/interfaces/libpq/fe-gssapi-common.c index c2e79bb55c5b4..b26fbf8a9f91e 100644 --- a/src/interfaces/libpq/fe-gssapi-common.c +++ b/src/interfaces/libpq/fe-gssapi-common.c @@ -46,7 +46,6 @@ void pg_GSS_error(const char *mprefix, PGconn *conn, OM_uint32 maj_stat, OM_uint32 min_stat) { - resetPQExpBuffer(&conn->errorMessage); appendPQExpBuffer(&conn->errorMessage, "%s:", mprefix); pg_GSS_error_int(&conn->errorMessage, maj_stat, GSS_C_GSS_CODE); appendPQExpBufferChar(&conn->errorMessage, ':'); @@ -94,8 +93,8 @@ pg_GSS_load_servicename(PGconn *conn) host = PQhost(conn); if (!(host && host[0] != '\0')) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("host name must be specified\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("host name must be specified\n")); return STATUS_ERROR; } @@ -107,8 +106,8 @@ pg_GSS_load_servicename(PGconn *conn) temp_gbuf.value = (char *) malloc(maxlen); if (!temp_gbuf.value) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return STATUS_ERROR; } snprintf(temp_gbuf.value, maxlen, "%s@%s", diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c index 432935061f041..b9c52eb50c24b 100644 --- a/src/interfaces/libpq/fe-lobj.c +++ b/src/interfaces/libpq/fe-lobj.c @@ -61,11 +61,8 @@ lo_open(PGconn *conn, Oid lobjId, int mode) PQArgBlock argv[2]; PGresult *res; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } + if (lo_initialize(conn) < 0) + return -1; argv[0].isint = 1; argv[0].len = 4; @@ -103,11 +100,8 @@ lo_close(PGconn *conn, int fd) int retval; int result_len; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } + if (lo_initialize(conn) < 0) + return -1; argv[0].isint = 1; argv[0].len = 4; @@ -141,17 +135,15 @@ lo_truncate(PGconn *conn, int fd, size_t len) int retval; int result_len; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } + if (lo_initialize(conn) < 0) + return -1; /* Must check this on-the-fly because it's not there pre-8.3 */ if (conn->lobjfuncs->fn_lo_truncate == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_truncate\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "lo_truncate"); return -1; } @@ -166,8 +158,8 @@ lo_truncate(PGconn *conn, int fd, size_t len) */ if (len > (size_t) INT_MAX) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("argument of lo_truncate exceeds integer range\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("argument of lo_truncate exceeds integer range\n")); return -1; } @@ -209,16 +201,14 @@ lo_truncate64(PGconn *conn, int fd, pg_int64 len) int retval; int result_len; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } + if (lo_initialize(conn) < 0) + return -1; if (conn->lobjfuncs->fn_lo_truncate64 == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_truncate64\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "lo_truncate64"); return -1; } @@ -261,11 +251,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len) PGresult *res; int result_len; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } + if (lo_initialize(conn) < 0) + return -1; /* * Long ago, somebody thought it'd be a good idea to declare this function @@ -275,8 +262,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len) */ if (len > (size_t) INT_MAX) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("argument of lo_read exceeds integer range\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("argument of lo_read exceeds integer range\n")); return -1; } @@ -316,11 +303,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len) int result_len; int retval; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } + if (lo_initialize(conn) < 0) + return -1; /* * Long ago, somebody thought it'd be a good idea to declare this function @@ -330,8 +314,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len) */ if (len > (size_t) INT_MAX) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("argument of lo_write exceeds integer range\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("argument of lo_write exceeds integer range\n")); return -1; } @@ -369,11 +353,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence) int retval; int result_len; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } + if (lo_initialize(conn) < 0) + return -1; argv[0].isint = 1; argv[0].len = 4; @@ -413,16 +394,14 @@ lo_lseek64(PGconn *conn, int fd, pg_int64 offset, int whence) pg_int64 retval; int result_len; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } + if (lo_initialize(conn) < 0) + return -1; if (conn->lobjfuncs->fn_lo_lseek64 == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_lseek64\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "lo_lseek64"); return -1; } @@ -469,11 +448,8 @@ lo_creat(PGconn *conn, int mode) int retval; int result_len; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return InvalidOid; - } + if (lo_initialize(conn) < 0) + return InvalidOid; argv[0].isint = 1; argv[0].len = 4; @@ -508,17 +484,15 @@ lo_create(PGconn *conn, Oid lobjId) int retval; int result_len; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return InvalidOid; - } + if (lo_initialize(conn) < 0) + return InvalidOid; /* Must check this on-the-fly because it's not there pre-8.1 */ if (conn->lobjfuncs->fn_lo_create == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_create\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "lo_create"); return InvalidOid; } @@ -552,11 +526,8 @@ lo_tell(PGconn *conn, int fd) PGresult *res; int result_len; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } + if (lo_initialize(conn) < 0) + return -1; argv[0].isint = 1; argv[0].len = 4; @@ -588,16 +559,14 @@ lo_tell64(PGconn *conn, int fd) PGresult *res; int result_len; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } + if (lo_initialize(conn) < 0) + return -1; if (conn->lobjfuncs->fn_lo_tell64 == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_tell64\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "lo_tell64"); return -1; } @@ -632,11 +601,8 @@ lo_unlink(PGconn *conn, Oid lobjId) int result_len; int retval; - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } + if (lo_initialize(conn) < 0) + return -1; argv[0].isint = 1; argv[0].len = 4; @@ -696,13 +662,19 @@ lo_import_internal(PGconn *conn, const char *filename, Oid oid) int lobj; char sebuf[PG_STRERROR_R_BUFLEN]; + if (conn == NULL) + return InvalidOid; + + /* Since this is the beginning of a query cycle, reset the error buffer */ + resetPQExpBuffer(&conn->errorMessage); + /* * open the file to be read in */ fd = open(filename, O_RDONLY | PG_BINARY, 0666); if (fd < 0) { /* error */ - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not open file \"%s\": %s\n"), filename, strerror_r(errno, sebuf, sizeof(sebuf))); return InvalidOid; @@ -757,6 +729,7 @@ lo_import_internal(PGconn *conn, const char *filename, Oid oid) (void) lo_close(conn, lobj); (void) close(fd); + /* deliberately overwrite any error from lo_close */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not read from file \"%s\": %s\n"), filename, @@ -811,6 +784,7 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename) int save_errno = errno; (void) lo_close(conn, lobj); + /* deliberately overwrite any error from lo_close */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not open file \"%s\": %s\n"), filename, @@ -831,6 +805,7 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename) (void) lo_close(conn, lobj); (void) close(fd); + /* deliberately overwrite any error from lo_close */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not write to file \"%s\": %s\n"), filename, @@ -855,7 +830,7 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename) /* if we already failed, don't overwrite that msg with a close error */ if (close(fd) != 0 && result >= 0) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not write to file \"%s\": %s\n"), filename, strerror_r(errno, sebuf, sizeof(sebuf))); result = -1; @@ -868,9 +843,11 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename) /* * lo_initialize * - * Initialize the large object interface for an existing connection. - * We ask the backend about the functions OID's in pg_proc for all - * functions that are required for large object operations. + * Initialize for a new large-object operation on an existing connection. + * Return 0 if OK, -1 on failure. + * + * If we haven't previously done so, we collect the function OIDs from + * pg_proc for all functions that are required for large object operations. */ static int lo_initialize(PGconn *conn) @@ -882,17 +859,26 @@ lo_initialize(PGconn *conn) const char *fname; Oid foid; - if (!conn) + /* Nothing we can do with no connection */ + if (conn == NULL) return -1; + /* Since this is the beginning of a query cycle, reset the error buffer */ + resetPQExpBuffer(&conn->errorMessage); + + /* Nothing else to do if we already collected info */ + if (conn->lobjfuncs != NULL) + return 0; + /* - * Allocate the structure to hold the functions OID's + * Allocate the structure to hold the function OIDs. We don't store it + * into the PGconn until it's successfully filled. */ lobjfuncs = (PGlobjfuncs *) malloc(sizeof(PGlobjfuncs)); if (lobjfuncs == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return -1; } MemSet((char *) lobjfuncs, 0, sizeof(PGlobjfuncs)); @@ -942,8 +928,8 @@ lo_initialize(PGconn *conn) { free(lobjfuncs); PQclear(res); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("query to initialize large object functions did not return data\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("query to initialize large object functions did not return data\n")); return -1; } @@ -991,57 +977,65 @@ lo_initialize(PGconn *conn) */ if (lobjfuncs->fn_lo_open == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_open\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "lo_open"); free(lobjfuncs); return -1; } if (lobjfuncs->fn_lo_close == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_close\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "lo_close"); free(lobjfuncs); return -1; } if (lobjfuncs->fn_lo_creat == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_creat\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "lo_creat"); free(lobjfuncs); return -1; } if (lobjfuncs->fn_lo_unlink == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_unlink\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "lo_unlink"); free(lobjfuncs); return -1; } if (lobjfuncs->fn_lo_lseek == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_lseek\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "lo_lseek"); free(lobjfuncs); return -1; } if (lobjfuncs->fn_lo_tell == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_tell\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "lo_tell"); free(lobjfuncs); return -1; } if (lobjfuncs->fn_lo_read == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function loread\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "loread"); free(lobjfuncs); return -1; } if (lobjfuncs->fn_lo_write == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lowrite\n")); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function %s\n"), + "lowrite"); free(lobjfuncs); return -1; } diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c index 6094f048f3052..2bfb6acd8953b 100644 --- a/src/interfaces/libpq/fe-misc.c +++ b/src/interfaces/libpq/fe-misc.c @@ -379,8 +379,8 @@ pqCheckOutBufferSpace(size_t bytes_needed, PGconn *conn) } /* realloc failed. Probably out of memory */ - printfPQExpBuffer(&conn->errorMessage, - "cannot allocate memory for output buffer\n"); + appendPQExpBufferStr(&conn->errorMessage, + "cannot allocate memory for output buffer\n"); return EOF; } @@ -473,8 +473,8 @@ pqCheckInBufferSpace(size_t bytes_needed, PGconn *conn) } /* realloc failed. Probably out of memory */ - printfPQExpBuffer(&conn->errorMessage, - "cannot allocate memory for input buffer\n"); + appendPQExpBufferStr(&conn->errorMessage, + "cannot allocate memory for input buffer\n"); return EOF; } @@ -619,8 +619,8 @@ pqReadData(PGconn *conn) if (conn->sock == PGINVALID_SOCKET) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("connection not open\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("connection not open\n")); return -1; } @@ -798,10 +798,10 @@ pqReadData(PGconn *conn) * means the connection has been closed. Cope. */ definitelyEOF: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("server closed the connection unexpectedly\n" - "\tThis probably means the server terminated abnormally\n" - "\tbefore or while processing the request.\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("server closed the connection unexpectedly\n" + "\tThis probably means the server terminated abnormally\n" + "\tbefore or while processing the request.\n")); /* Come here if lower-level code already set a suitable errorMessage */ definitelyFailed: @@ -836,6 +836,7 @@ pqSendSome(PGconn *conn, int len) { char *ptr = conn->outBuffer; int remaining = conn->outCount; + int oldmsglen = conn->errorMessage.len; int result = 0; /* @@ -862,13 +863,10 @@ pqSendSome(PGconn *conn, int len) if (conn->sock == PGINVALID_SOCKET) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("connection not open\n")); conn->write_failed = true; - /* Transfer error message to conn->write_err_msg, if possible */ + /* Insert error message into conn->write_err_msg, if possible */ /* (strdup failure is OK, we'll cope later) */ - conn->write_err_msg = strdup(conn->errorMessage.data); - resetPQExpBuffer(&conn->errorMessage); + conn->write_err_msg = strdup(libpq_gettext("connection not open\n")); /* Discard queued data; no chance it'll ever be sent */ conn->outCount = 0; return 0; @@ -915,14 +913,16 @@ pqSendSome(PGconn *conn, int len) * Transfer error message to conn->write_err_msg, if * possible (strdup failure is OK, we'll cope later). * - * Note: this assumes that pqsecure_write and its children - * will overwrite not append to conn->errorMessage. If - * that's ever changed, we could remember the length of - * conn->errorMessage at entry to this routine, and then - * save and delete just what was appended. + * We only want to transfer whatever has been appended to + * conn->errorMessage since we entered this routine. */ - conn->write_err_msg = strdup(conn->errorMessage.data); - resetPQExpBuffer(&conn->errorMessage); + if (!PQExpBufferBroken(&conn->errorMessage)) + { + conn->write_err_msg = strdup(conn->errorMessage.data + + oldmsglen); + conn->errorMessage.len = oldmsglen; + conn->errorMessage.data[oldmsglen] = '\0'; + } /* Discard queued data; no chance it'll ever be sent */ conn->outCount = 0; @@ -1056,8 +1056,8 @@ pqWaitTimed(int forRead, int forWrite, PGconn *conn, time_t finish_time) if (result == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("timeout expired\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("timeout expired\n")); return 1; } @@ -1101,8 +1101,8 @@ pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time) return -1; if (conn->sock == PGINVALID_SOCKET) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("invalid socket\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("invalid socket\n")); return -1; } @@ -1124,7 +1124,7 @@ pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time) { char sebuf[PG_STRERROR_R_BUFLEN]; - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("select() failed: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); } diff --git a/src/interfaces/libpq/fe-protocol2.c b/src/interfaces/libpq/fe-protocol2.c index ad6587f924ef5..6efa53d8b7187 100644 --- a/src/interfaces/libpq/fe-protocol2.c +++ b/src/interfaces/libpq/fe-protocol2.c @@ -83,7 +83,7 @@ pqSetenvPoll(PGconn *conn) return PGRES_POLLING_OK; default: - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid setenv state %c, probably indicative of memory corruption\n"), conn->setenv_state); goto error_return; @@ -380,7 +380,7 @@ pqSetenvPoll(PGconn *conn) } default: - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid state %c, " "probably indicative of memory corruption\n"), conn->setenv_state); @@ -493,8 +493,8 @@ pqParseInput2(PGconn *conn) PGRES_COMMAND_OK); if (!conn->result) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory")); pqSaveErrorResult(conn); } } @@ -528,8 +528,8 @@ pqParseInput2(PGconn *conn) PGRES_EMPTY_QUERY); if (!conn->result) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory")); pqSaveErrorResult(conn); } } @@ -622,7 +622,7 @@ pqParseInput2(PGconn *conn) * never arrives from the server during protocol 2.0. */ default: - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("unexpected response from server; first received character was \"%c\"\n"), id); /* build an error result holding the error message */ @@ -754,7 +754,7 @@ getRowDescriptions(PGconn *conn) if (!errmsg) errmsg = libpq_gettext("out of memory for query result"); - printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); + appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); /* * XXX: if PQmakeEmptyPGresult() fails, there's probably not much we can @@ -929,7 +929,7 @@ getAnotherTuple(PGconn *conn, bool binary) if (!errmsg) errmsg = libpq_gettext("out of memory for query result"); - printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); + appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); /* * XXX: if PQmakeEmptyPGresult() fails, there's probably not much we can @@ -1042,12 +1042,11 @@ pqGetErrorNotice2(PGconn *conn, bool isError) { pqClearAsyncResult(conn); /* redundant, but be safe */ conn->result = res; - resetPQExpBuffer(&conn->errorMessage); if (res && !PQExpBufferDataBroken(workBuf) && res->errMsg) appendPQExpBufferStr(&conn->errorMessage, res->errMsg); else - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory")); if (conn->xactStatus == PQTRANS_INTRANS) conn->xactStatus = PQTRANS_INERROR; } @@ -1203,8 +1202,8 @@ pqGetCopyData2(PGconn *conn, char **buffer, int async) *buffer = (char *) malloc(msgLength + 1); if (*buffer == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return -2; } memcpy(*buffer, &conn->inBuffer[conn->inStart], msgLength); @@ -1349,8 +1348,8 @@ pqEndcopy2(PGconn *conn) if (conn->asyncStatus != PGASYNC_COPY_IN && conn->asyncStatus != PGASYNC_COPY_OUT) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("no COPY in progress\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("no COPY in progress\n")); return 1; } @@ -1367,7 +1366,6 @@ pqEndcopy2(PGconn *conn) /* Return to active duty */ conn->asyncStatus = PGASYNC_BUSY; - resetPQExpBuffer(&conn->errorMessage); /* Wait for the completion response */ result = PQgetResult(conn); @@ -1526,7 +1524,7 @@ pqFunctionCall2(PGconn *conn, Oid fnid, else { /* The backend violates the protocol. */ - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("protocol error: id=0x%x\n"), id); pqSaveErrorResult(conn); @@ -1558,7 +1556,7 @@ pqFunctionCall2(PGconn *conn, Oid fnid, return PQmakeEmptyPGresult(conn, status); default: /* The backend violates the protocol. */ - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("protocol error: id=0x%x\n"), id); pqSaveErrorResult(conn); diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c index a4d6ee26749d4..e4ee9d69d256c 100644 --- a/src/interfaces/libpq/fe-protocol3.c +++ b/src/interfaces/libpq/fe-protocol3.c @@ -202,8 +202,8 @@ pqParseInput3(PGconn *conn) PGRES_COMMAND_OK); if (!conn->result) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory")); pqSaveErrorResult(conn); } } @@ -229,8 +229,8 @@ pqParseInput3(PGconn *conn) PGRES_EMPTY_QUERY); if (!conn->result) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory")); pqSaveErrorResult(conn); } } @@ -246,8 +246,8 @@ pqParseInput3(PGconn *conn) PGRES_COMMAND_OK); if (!conn->result) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory")); pqSaveErrorResult(conn); } } @@ -326,8 +326,8 @@ pqParseInput3(PGconn *conn) PGRES_COMMAND_OK); if (!conn->result) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory")); pqSaveErrorResult(conn); } } @@ -361,8 +361,8 @@ pqParseInput3(PGconn *conn) else { /* Set up to report error at end of query */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("server sent data (\"D\" message) without prior row description (\"T\" message)\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("server sent data (\"D\" message) without prior row description (\"T\" message)\n")); pqSaveErrorResult(conn); /* Discard the unexpected message */ conn->inCursor += msgLength; @@ -404,7 +404,7 @@ pqParseInput3(PGconn *conn) */ break; default: - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("unexpected response from server; first received character was \"%c\"\n"), id); /* build an error result holding the error message */ @@ -425,7 +425,7 @@ pqParseInput3(PGconn *conn) else { /* Trouble --- report it */ - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("message contents do not agree with length in message type \"%c\"\n"), id); /* build an error result holding the error message */ @@ -445,7 +445,7 @@ pqParseInput3(PGconn *conn) static void handleSyncLoss(PGconn *conn, char id, int msgLength) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("lost synchronization with server: got message type \"%c\", length %d\n"), id, msgLength); /* build an error result holding the error message */ @@ -621,7 +621,7 @@ getRowDescriptions(PGconn *conn, int msgLength) if (!errmsg) errmsg = libpq_gettext("out of memory for query result"); - printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); + appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); pqSaveErrorResult(conn); /* @@ -721,7 +721,7 @@ getParamDescriptions(PGconn *conn, int msgLength) */ if (!errmsg) errmsg = libpq_gettext("out of memory"); - printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); + appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); pqSaveErrorResult(conn); /* @@ -848,7 +848,7 @@ getAnotherTuple(PGconn *conn, int msgLength) if (!errmsg) errmsg = libpq_gettext("out of memory for query result"); - printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); + appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); pqSaveErrorResult(conn); /* @@ -950,8 +950,8 @@ pqGetErrorNotice3(PGconn *conn, bool isError) pqClearAsyncResult(conn); /* redundant, but be safe */ conn->result = res; if (PQExpBufferDataBroken(workBuf)) - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory")); else appendPQExpBufferStr(&conn->errorMessage, workBuf.data); } @@ -1695,8 +1695,8 @@ pqGetCopyData3(PGconn *conn, char **buffer, int async) *buffer = (char *) malloc(msgLength + 1); if (*buffer == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return -2; } memcpy(*buffer, &conn->inBuffer[conn->inCursor], msgLength); @@ -1728,8 +1728,8 @@ pqGetline3(PGconn *conn, char *s, int maxlen) conn->asyncStatus != PGASYNC_COPY_BOTH) || conn->copy_is_binary) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("PQgetline: not doing text COPY OUT\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("PQgetline: not doing text COPY OUT\n")); *s = '\0'; return EOF; } @@ -1834,8 +1834,8 @@ pqEndcopy3(PGconn *conn) conn->asyncStatus != PGASYNC_COPY_OUT && conn->asyncStatus != PGASYNC_COPY_BOTH) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("no COPY in progress\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("no COPY in progress\n")); return 1; } @@ -1868,7 +1868,6 @@ pqEndcopy3(PGconn *conn) /* Return to active duty */ conn->asyncStatus = PGASYNC_BUSY; - resetPQExpBuffer(&conn->errorMessage); /* * Non blocking connections may have to abort at this point. If everyone @@ -2091,7 +2090,7 @@ pqFunctionCall3(PGconn *conn, Oid fnid, break; default: /* The backend violates the protocol. */ - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("protocol error: id=0x%x\n"), id); pqSaveErrorResult(conn); diff --git a/src/interfaces/libpq/fe-secure-common.c b/src/interfaces/libpq/fe-secure-common.c index 45d36359a5d40..afa5d133e1593 100644 --- a/src/interfaces/libpq/fe-secure-common.c +++ b/src/interfaces/libpq/fe-secure-common.c @@ -94,8 +94,8 @@ pq_verify_peer_name_matches_certificate_name(PGconn *conn, if (!(host && host[0] != '\0')) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("host name must be specified\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("host name must be specified\n")); return -1; } @@ -106,8 +106,8 @@ pq_verify_peer_name_matches_certificate_name(PGconn *conn, name = malloc(namelen + 1); if (name == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return -1; } memcpy(name, namedata, namelen); @@ -120,8 +120,8 @@ pq_verify_peer_name_matches_certificate_name(PGconn *conn, if (namelen != strlen(name)) { free(name); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("SSL certificate's name contains embedded null\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("SSL certificate's name contains embedded null\n")); return -1; } @@ -167,8 +167,8 @@ pq_verify_peer_name_matches_certificate(PGconn *conn) /* Check that we have a hostname to compare with. */ if (!(host && host[0] != '\0')) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("host name must be specified for a verified SSL connection\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("host name must be specified for a verified SSL connection\n")); return false; } @@ -184,7 +184,7 @@ pq_verify_peer_name_matches_certificate(PGconn *conn) */ if (names_examined > 1) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_ngettext("server certificate for \"%s\" (and %d other name) does not match host name \"%s\"\n", "server certificate for \"%s\" (and %d other names) does not match host name \"%s\"\n", names_examined - 1), @@ -192,14 +192,14 @@ pq_verify_peer_name_matches_certificate(PGconn *conn) } else if (names_examined == 1) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("server certificate for \"%s\" does not match host name \"%s\"\n"), first_name, host); } else { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not get server's host name from server certificate\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("could not get server's host name from server certificate\n")); } } diff --git a/src/interfaces/libpq/fe-secure-gssapi.c b/src/interfaces/libpq/fe-secure-gssapi.c index 8c0ba69b7c071..c783a53734ee6 100644 --- a/src/interfaces/libpq/fe-secure-gssapi.c +++ b/src/interfaces/libpq/fe-secure-gssapi.c @@ -78,7 +78,7 @@ * * On success, returns the number of data bytes consumed (possibly less than * len). On failure, returns -1 with errno set appropriately. If the errno - * indicates a non-retryable error, a message is put into conn->errorMessage. + * indicates a non-retryable error, a message is added to conn->errorMessage. * For retryable errors, caller should call again (passing the same data) * once the socket is ready. */ @@ -106,8 +106,8 @@ pg_GSS_write(PGconn *conn, const void *ptr, size_t len) */ if (len < PqGSSSendConsumed) { - printfPQExpBuffer(&conn->errorMessage, - "GSSAPI caller failed to retransmit all data needing to be retried\n"); + appendPQExpBufferStr(&conn->errorMessage, + "GSSAPI caller failed to retransmit all data needing to be retried\n"); errno = EINVAL; return -1; } @@ -205,15 +205,15 @@ pg_GSS_write(PGconn *conn, const void *ptr, size_t len) if (conf_state == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("outgoing GSSAPI message would not use confidentiality\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("outgoing GSSAPI message would not use confidentiality\n")); errno = EIO; /* for lack of a better idea */ goto cleanup; } if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("client tried to send oversize GSSAPI packet (%zu > %zu)\n"), (size_t) output.length, PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)); @@ -258,7 +258,7 @@ pg_GSS_write(PGconn *conn, const void *ptr, size_t len) * * Returns the number of data bytes read, or on failure, returns -1 * with errno set appropriately. If the errno indicates a non-retryable - * error, a message is put into conn->errorMessage. For retryable errors, + * error, a message is added to conn->errorMessage. For retryable errors, * caller should call again once the socket is ready. */ ssize_t @@ -350,7 +350,7 @@ pg_GSS_read(PGconn *conn, void *ptr, size_t len) if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("oversize GSSAPI packet sent by the server (%zu > %zu)\n"), (size_t) input.length, PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)); @@ -399,8 +399,8 @@ pg_GSS_read(PGconn *conn, void *ptr, size_t len) if (conf_state == 0) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("incoming GSSAPI message did not use confidentiality\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("incoming GSSAPI message did not use confidentiality\n")); ret = -1; errno = EIO; /* for lack of a better idea */ goto cleanup; @@ -500,8 +500,8 @@ pqsecure_open_gss(PGconn *conn) PqGSSResultBuffer = malloc(PQ_GSS_RECV_BUFFER_SIZE); if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return PGRES_POLLING_FAILED; } PqGSSSendLength = PqGSSSendNext = PqGSSSendConsumed = 0; @@ -578,7 +578,7 @@ pqsecure_open_gss(PGconn *conn) PqGSSRecvLength += ret; - printfPQExpBuffer(&conn->errorMessage, "%s\n", PqGSSRecvBuffer + 1); + appendPQExpBuffer(&conn->errorMessage, "%s\n", PqGSSRecvBuffer + 1); return PGRES_POLLING_FAILED; } @@ -592,7 +592,7 @@ pqsecure_open_gss(PGconn *conn) input.length = pg_ntoh32(*(uint32 *) PqGSSRecvBuffer); if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("oversize GSSAPI packet sent by the server (%zu > %zu)\n"), (size_t) input.length, PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)); diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c index d63e4bb27972d..075f754e1fb61 100644 --- a/src/interfaces/libpq/fe-secure-openssl.c +++ b/src/interfaces/libpq/fe-secure-openssl.c @@ -181,8 +181,8 @@ pgtls_read(PGconn *conn, void *ptr, size_t len) if (n < 0) { /* Not supposed to happen, so we don't translate the msg */ - printfPQExpBuffer(&conn->errorMessage, - "SSL_read failed but did not provide error information\n"); + appendPQExpBufferStr(&conn->errorMessage, + "SSL_read failed but did not provide error information\n"); /* assume the connection is broken */ result_errno = ECONNRESET; } @@ -205,20 +205,20 @@ pgtls_read(PGconn *conn, void *ptr, size_t len) result_errno = SOCK_ERRNO; if (result_errno == EPIPE || result_errno == ECONNRESET) - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("server closed the connection unexpectedly\n" - "\tThis probably means the server terminated abnormally\n" - "\tbefore or while processing the request.\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("server closed the connection unexpectedly\n" + "\tThis probably means the server terminated abnormally\n" + "\tbefore or while processing the request.\n")); else - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: %s\n"), SOCK_STRERROR(result_errno, sebuf, sizeof(sebuf))); } else { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("SSL SYSCALL error: EOF detected\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("SSL SYSCALL error: EOF detected\n")); /* assume the connection is broken */ result_errno = ECONNRESET; n = -1; @@ -228,7 +228,7 @@ pgtls_read(PGconn *conn, void *ptr, size_t len) { char *errm = SSLerrmessage(ecode); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL error: %s\n"), errm); SSLerrfree(errm); /* assume the connection is broken */ @@ -243,13 +243,13 @@ pgtls_read(PGconn *conn, void *ptr, size_t len) * a clean connection closure, so we should not report it as a * server crash. */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("SSL connection has been closed unexpectedly\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("SSL connection has been closed unexpectedly\n")); result_errno = ECONNRESET; n = -1; break; default: - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("unrecognized SSL error code: %d\n"), err); /* assume the connection is broken */ @@ -290,8 +290,8 @@ pgtls_write(PGconn *conn, const void *ptr, size_t len) if (n < 0) { /* Not supposed to happen, so we don't translate the msg */ - printfPQExpBuffer(&conn->errorMessage, - "SSL_write failed but did not provide error information\n"); + appendPQExpBufferStr(&conn->errorMessage, + "SSL_write failed but did not provide error information\n"); /* assume the connection is broken */ result_errno = ECONNRESET; } @@ -312,20 +312,20 @@ pgtls_write(PGconn *conn, const void *ptr, size_t len) { result_errno = SOCK_ERRNO; if (result_errno == EPIPE || result_errno == ECONNRESET) - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("server closed the connection unexpectedly\n" - "\tThis probably means the server terminated abnormally\n" - "\tbefore or while processing the request.\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("server closed the connection unexpectedly\n" + "\tThis probably means the server terminated abnormally\n" + "\tbefore or while processing the request.\n")); else - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: %s\n"), SOCK_STRERROR(result_errno, sebuf, sizeof(sebuf))); } else { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("SSL SYSCALL error: EOF detected\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("SSL SYSCALL error: EOF detected\n")); /* assume the connection is broken */ result_errno = ECONNRESET; n = -1; @@ -335,7 +335,7 @@ pgtls_write(PGconn *conn, const void *ptr, size_t len) { char *errm = SSLerrmessage(ecode); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL error: %s\n"), errm); SSLerrfree(errm); /* assume the connection is broken */ @@ -350,13 +350,13 @@ pgtls_write(PGconn *conn, const void *ptr, size_t len) * a clean connection closure, so we should not report it as a * server crash. */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("SSL connection has been closed unexpectedly\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("SSL connection has been closed unexpectedly\n")); result_errno = ECONNRESET; n = -1; break; default: - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("unrecognized SSL error code: %d\n"), err); /* assume the connection is broken */ @@ -396,8 +396,8 @@ pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len) if (!OBJ_find_sigid_algs(X509_get_signature_nid(peer_cert), &algo_nid, NULL)) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not determine server certificate signature algorithm\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("could not determine server certificate signature algorithm\n")); return NULL; } @@ -417,7 +417,7 @@ pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len) algo_type = EVP_get_digestbynid(algo_nid); if (algo_type == NULL) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not find digest for NID %s\n"), OBJ_nid2sn(algo_nid)); return NULL; @@ -427,8 +427,8 @@ pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len) if (!X509_digest(peer_cert, algo_type, hash, &hash_size)) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not generate peer certificate hash\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("could not generate peer certificate hash\n")); return NULL; } @@ -436,8 +436,8 @@ pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len) cert_hash = malloc(hash_size); if (cert_hash == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return NULL; } memcpy(cert_hash, hash, hash_size); @@ -484,8 +484,8 @@ openssl_verify_peer_name_matches_certificate_name(PGconn *conn, ASN1_STRING *nam /* Should not happen... */ if (name_entry == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("SSL certificate's name entry is missing\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("SSL certificate's name entry is missing\n")); return -1; } @@ -811,7 +811,7 @@ initialize_SSL(PGconn *conn) { char *err = SSLerrmessage(ERR_get_error()); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not create SSL context: %s\n"), err); SSLerrfree(err); @@ -850,7 +850,7 @@ initialize_SSL(PGconn *conn) if (ssl_min_ver == -1) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid value \"%s\" for minimum SSL protocol version\n"), conn->ssl_min_protocol_version); SSL_CTX_free(SSL_context); @@ -861,7 +861,7 @@ initialize_SSL(PGconn *conn) { char *err = SSLerrmessage(ERR_get_error()); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not set minimum SSL protocol version: %s\n"), err); SSLerrfree(err); @@ -879,7 +879,7 @@ initialize_SSL(PGconn *conn) if (ssl_max_ver == -1) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid value \"%s\" for maximum SSL protocol version\n"), conn->ssl_max_protocol_version); SSL_CTX_free(SSL_context); @@ -890,7 +890,7 @@ initialize_SSL(PGconn *conn) { char *err = SSLerrmessage(ERR_get_error()); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not set maximum SSL protocol version: %s\n"), err); SSLerrfree(err); @@ -926,7 +926,7 @@ initialize_SSL(PGconn *conn) { char *err = SSLerrmessage(ERR_get_error()); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not read root certificate file \"%s\": %s\n"), fnbuf, err); SSLerrfree(err); @@ -970,11 +970,11 @@ initialize_SSL(PGconn *conn) * that it seems worth having a specialized error message for it. */ if (fnbuf[0] == '\0') - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not get home directory to locate root certificate file\n" "Either provide the file or change sslmode to disable server certificate verification.\n")); else - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("root certificate file \"%s\" does not exist\n" "Either provide the file or change sslmode to disable server certificate verification.\n"), fnbuf); SSL_CTX_free(SSL_context); @@ -1005,7 +1005,7 @@ initialize_SSL(PGconn *conn) */ if (errno != ENOENT && errno != ENOTDIR) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not open certificate file \"%s\": %s\n"), fnbuf, strerror_r(errno, sebuf, sizeof(sebuf))); SSL_CTX_free(SSL_context); @@ -1024,7 +1024,7 @@ initialize_SSL(PGconn *conn) { char *err = SSLerrmessage(ERR_get_error()); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not read certificate file \"%s\": %s\n"), fnbuf, err); SSLerrfree(err); @@ -1049,7 +1049,7 @@ initialize_SSL(PGconn *conn) { char *err = SSLerrmessage(ERR_get_error()); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not establish SSL connection: %s\n"), err); SSLerrfree(err); @@ -1087,8 +1087,8 @@ initialize_SSL(PGconn *conn) if (engine_str == NULL) { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); return -1; } @@ -1103,7 +1103,7 @@ initialize_SSL(PGconn *conn) { char *err = SSLerrmessage(ERR_get_error()); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not load SSL engine \"%s\": %s\n"), engine_str, err); SSLerrfree(err); @@ -1115,7 +1115,7 @@ initialize_SSL(PGconn *conn) { char *err = SSLerrmessage(ERR_get_error()); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not initialize SSL engine \"%s\": %s\n"), engine_str, err); SSLerrfree(err); @@ -1131,7 +1131,7 @@ initialize_SSL(PGconn *conn) { char *err = SSLerrmessage(ERR_get_error()); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not read private SSL key \"%s\" from engine \"%s\": %s\n"), engine_colon, engine_str, err); SSLerrfree(err); @@ -1145,7 +1145,7 @@ initialize_SSL(PGconn *conn) { char *err = SSLerrmessage(ERR_get_error()); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not load private SSL key \"%s\" from engine \"%s\": %s\n"), engine_colon, engine_str, err); SSLerrfree(err); @@ -1182,7 +1182,7 @@ initialize_SSL(PGconn *conn) if (stat(fnbuf, &buf) != 0) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("certificate present, but not private key file \"%s\"\n"), fnbuf); return -1; @@ -1190,7 +1190,7 @@ initialize_SSL(PGconn *conn) #ifndef WIN32 if (!S_ISREG(buf.st_mode) || buf.st_mode & (S_IRWXG | S_IRWXO)) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("private key file \"%s\" has group or world access; permissions should be u=rw (0600) or less\n"), fnbuf); return -1; @@ -1215,7 +1215,7 @@ initialize_SSL(PGconn *conn) */ if (SSL_use_PrivateKey_file(conn->ssl, fnbuf, SSL_FILETYPE_ASN1) != 1) { - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not load private key file \"%s\": %s\n"), fnbuf, err); SSLerrfree(err); @@ -1233,7 +1233,7 @@ initialize_SSL(PGconn *conn) { char *err = SSLerrmessage(ERR_get_error()); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("certificate does not match private key file \"%s\": %s\n"), fnbuf, err); SSLerrfree(err); @@ -1287,12 +1287,12 @@ open_client_SSL(PGconn *conn) char sebuf[PG_STRERROR_R_BUFLEN]; if (r == -1) - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); else - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("SSL SYSCALL error: EOF detected\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("SSL SYSCALL error: EOF detected\n")); pgtls_close(conn); return PGRES_POLLING_FAILED; } @@ -1300,7 +1300,7 @@ open_client_SSL(PGconn *conn) { char *err = SSLerrmessage(ecode); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL error: %s\n"), err); SSLerrfree(err); @@ -1350,7 +1350,7 @@ open_client_SSL(PGconn *conn) } default: - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("unrecognized SSL error code: %d\n"), err); pgtls_close(conn); @@ -1369,7 +1369,7 @@ open_client_SSL(PGconn *conn) { char *err = SSLerrmessage(ERR_get_error()); - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("certificate could not be obtained: %s\n"), err); SSLerrfree(err); diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c index 373c59cb0d629..67b1e78512973 100644 --- a/src/interfaces/libpq/fe-secure.c +++ b/src/interfaces/libpq/fe-secure.c @@ -205,8 +205,8 @@ pqsecure_close(PGconn *conn) /* * Read data from a secure connection. * - * On failure, this function is responsible for putting a suitable message - * into conn->errorMessage. The caller must still inspect errno, but only + * On failure, this function is responsible for appending a suitable message + * to conn->errorMessage. The caller must still inspect errno, but only * to determine whether to continue/retry after error. */ ssize_t @@ -263,14 +263,14 @@ pqsecure_raw_read(PGconn *conn, void *ptr, size_t len) case EPIPE: case ECONNRESET: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("server closed the connection unexpectedly\n" - "\tThis probably means the server terminated abnormally\n" - "\tbefore or while processing the request.\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("server closed the connection unexpectedly\n" + "\tThis probably means the server terminated abnormally\n" + "\tbefore or while processing the request.\n")); break; default: - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not receive data from server: %s\n"), SOCK_STRERROR(result_errno, sebuf, sizeof(sebuf))); @@ -287,8 +287,8 @@ pqsecure_raw_read(PGconn *conn, void *ptr, size_t len) /* * Write data to a secure connection. * - * On failure, this function is responsible for putting a suitable message - * into conn->errorMessage. The caller must still inspect errno, but only + * On failure, this function is responsible for appending a suitable message + * to conn->errorMessage. The caller must still inspect errno, but only * to determine whether to continue/retry after error. */ ssize_t @@ -376,14 +376,14 @@ pqsecure_raw_write(PGconn *conn, const void *ptr, size_t len) /* FALL THRU */ case ECONNRESET: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("server closed the connection unexpectedly\n" - "\tThis probably means the server terminated abnormally\n" - "\tbefore or while processing the request.\n")); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("server closed the connection unexpectedly\n" + "\tThis probably means the server terminated abnormally\n" + "\tbefore or while processing the request.\n")); break; default: - printfPQExpBuffer(&conn->errorMessage, + appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not send data to server: %s\n"), SOCK_STRERROR(result_errno, sebuf, sizeof(sebuf))); diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index e1018adb9e5db..4db498369c7be 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -522,7 +522,11 @@ struct pg_conn * connection */ #endif - /* Buffer for current error message */ + /* + * Buffer for current error message. This is cleared at the start of any + * connection attempt or query cycle; after that, all code should append + * messages to it, never overwrite. + */ PQExpBufferData errorMessage; /* expansible string */ /* Buffer for receiving various parts of messages */ @@ -600,7 +604,6 @@ extern pgthreadlock_t pg_g_threadlock; /* === in fe-exec.c === */ extern void pqSetResultError(PGresult *res, const char *msg); -extern void pqCatenateResultError(PGresult *res, const char *msg); extern void *pqResultAlloc(PGresult *res, size_t nBytes, bool isBinary); extern char *pqResultStrdup(PGresult *res, const char *str); extern void pqClearAsyncResult(PGconn *conn); @@ -612,6 +615,7 @@ extern void pqSaveMessageField(PGresult *res, char code, extern void pqSaveParameterStatus(PGconn *conn, const char *name, const char *value); extern int pqRowProcessor(PGconn *conn, const char **errmsgp); +extern int PQsendQueryContinue(PGconn *conn, const char *query); /* === in fe-protocol2.c === */ @@ -708,7 +712,7 @@ extern void pgtls_init_library(bool do_ssl, int do_crypto); * The conn parameter is only used to be able to pass back an error * message - no connection-local setup is made here. * - * Returns 0 if OK, -1 on failure (with a message in conn->errorMessage). + * Returns 0 if OK, -1 on failure (adding a message to conn->errorMessage). */ extern int pgtls_init(PGconn *conn); @@ -725,8 +729,8 @@ extern void pgtls_close(PGconn *conn); /* * Read data from a secure connection. * - * On failure, this function is responsible for putting a suitable message - * into conn->errorMessage. The caller must still inspect errno, but only + * On failure, this function is responsible for appending a suitable message + * to conn->errorMessage. The caller must still inspect errno, but only * to determine whether to continue/retry after error. */ extern ssize_t pgtls_read(PGconn *conn, void *ptr, size_t len); @@ -739,8 +743,8 @@ extern bool pgtls_read_pending(PGconn *conn); /* * Write data to a secure connection. * - * On failure, this function is responsible for putting a suitable message - * into conn->errorMessage. The caller must still inspect errno, but only + * On failure, this function is responsible for appending a suitable message + * to conn->errorMessage. The caller must still inspect errno, but only * to determine whether to continue/retry after error. */ extern ssize_t pgtls_write(PGconn *conn, const void *ptr, size_t len); From 800d93f314b0f7c10193e48b259f87800cb85d84 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 11 Jan 2021 13:43:19 -0500 Subject: [PATCH 068/240] Allow pg_regress.c wrappers to postprocess test result files. Add an optional callback to regression_main() that, if provided, is invoked on each test output file before we try to compare it to the expected-result file. The main and isolation test programs don't need this (yet). In pg_regress_ecpg, add a filter that eliminates target-host details from "could not connect" error reports. This filter doesn't do anything as of this commit, but it will be needed by the next one. In the long run we might want to provide some more general, perhaps pattern-based, filtering mechanism for test output. For now, this will solve the immediate problem. Discussion: https://postgr.es/m/BN6PR05MB3492948E4FD76C156E747E8BC9160@BN6PR05MB3492.namprd05.prod.outlook.com --- src/interfaces/ecpg/test/pg_regress_ecpg.c | 95 ++++++++++++++++++++-- src/test/isolation/isolation_main.c | 5 +- src/test/regress/pg_regress.c | 29 ++++--- src/test/regress/pg_regress.h | 24 ++++-- src/test/regress/pg_regress_main.c | 5 +- 5 files changed, 134 insertions(+), 24 deletions(-) diff --git a/src/interfaces/ecpg/test/pg_regress_ecpg.c b/src/interfaces/ecpg/test/pg_regress_ecpg.c index 31dd507ea0a02..8d43fd65bad68 100644 --- a/src/interfaces/ecpg/test/pg_regress_ecpg.c +++ b/src/interfaces/ecpg/test/pg_regress_ecpg.c @@ -23,13 +23,16 @@ #include "lib/stringinfo.h" +/* + * Create a filtered copy of sourcefile, removing any path + * appearing in #line directives; for example, replace + * #line x "./../bla/foo.h" with #line x "foo.h". + * This is needed because the path part can vary depending + * on compiler, platform, build options, etc. + */ static void -ecpg_filter(const char *sourcefile, const char *outfile) +ecpg_filter_source(const char *sourcefile, const char *outfile) { - /* - * Create a filtered copy of sourcefile, replacing #line x - * "./../bla/foo.h" with #line x "foo.h" - */ FILE *s, *t; StringInfoData linebuf; @@ -76,6 +79,66 @@ ecpg_filter(const char *sourcefile, const char *outfile) fclose(t); } +/* + * Remove the details of "could not connect to ...: " error messages + * in a test result file, since the target host/pathname and/or port + * can vary. Rewrite the result file in-place. + * + * At some point it might be interesting to unify this with + * ecpg_filter_source, but building a general pattern matcher + * is no fun, nor does it seem desirable to introduce a + * dependency on an external one. + */ +static void +ecpg_filter_stderr(const char *resultfile, const char *tmpfile) +{ + FILE *s, + *t; + StringInfoData linebuf; + + s = fopen(resultfile, "r"); + if (!s) + { + fprintf(stderr, "Could not open file %s for reading\n", resultfile); + exit(2); + } + t = fopen(tmpfile, "w"); + if (!t) + { + fprintf(stderr, "Could not open file %s for writing\n", tmpfile); + exit(2); + } + + initStringInfo(&linebuf); + + while (pg_get_line_buf(s, &linebuf)) + { + char *p1 = strstr(linebuf.data, "could not connect to "); + + if (p1) + { + char *p2 = strstr(p1, ": "); + + if (p2) + { + memmove(p1 + 17, p2, strlen(p2) + 1); + /* we don't bother to fix up linebuf.len */ + } + } + fputs(linebuf.data, t); + } + + pfree(linebuf.data); + fclose(s); + fclose(t); + if (rename(tmpfile, resultfile) != 0) + { + fprintf(stderr, "Could not overwrite file %s with %s\n", + resultfile, tmpfile); + exit(2); + } +} + /* * start an ecpg test process for specified file (including redirection), * and return process ID @@ -139,7 +202,7 @@ ecpg_start_test(const char *testname, add_stringlist_item(expectfiles, expectfile_source); add_stringlist_item(tags, "source"); - ecpg_filter(insource, outfile_source); + ecpg_filter_source(insource, outfile_source); snprintf(cmd, sizeof(cmd), "\"%s\" >\"%s\" 2>\"%s\"", @@ -167,6 +230,21 @@ ecpg_start_test(const char *testname, return pid; } +static void +ecpg_postprocess_result(const char *filename) +{ + int nlen = strlen(filename); + + /* Only stderr files require filtering, at the moment */ + if (nlen > 7 && strcmp(filename + nlen - 7, ".stderr") == 0) + { + char *tmpfile = psprintf("%s.tmp", filename); + + ecpg_filter_stderr(filename, tmpfile); + pfree(tmpfile); + } +} + static void ecpg_init(int argc, char *argv[]) { @@ -176,5 +254,8 @@ ecpg_init(int argc, char *argv[]) int main(int argc, char *argv[]) { - return regression_main(argc, argv, ecpg_init, ecpg_start_test); + return regression_main(argc, argv, + ecpg_init, + ecpg_start_test, + ecpg_postprocess_result); } diff --git a/src/test/isolation/isolation_main.c b/src/test/isolation/isolation_main.c index 50893aa3abb9a..eff9c4f2dfefe 100644 --- a/src/test/isolation/isolation_main.c +++ b/src/test/isolation/isolation_main.c @@ -145,5 +145,8 @@ isolation_init(int argc, char **argv) int main(int argc, char *argv[]) { - return regression_main(argc, argv, isolation_init, isolation_start_test); + return regression_main(argc, argv, + isolation_init, + isolation_start_test, + NULL /* no postfunc needed */ ); } diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c index 5cfb4c4a491ff..b284cc88c40e5 100644 --- a/src/test/regress/pg_regress.c +++ b/src/test/regress/pg_regress.c @@ -731,7 +731,7 @@ static void initialize_environment(void) { /* - * Set default application_name. (The test_function may choose to + * Set default application_name. (The test_start_function may choose to * override this, but if it doesn't, we have something useful in place.) */ setenv("PGAPPNAME", "pg_regress", 1); @@ -1616,7 +1616,8 @@ log_child_failure(int exitstatus) * Run all the tests specified in one schedule file */ static void -run_schedule(const char *schedule, test_function tfunc) +run_schedule(const char *schedule, test_start_function startfunc, + postprocess_result_function postfunc) { #define MAX_PARALLEL_TESTS 100 char *tests[MAX_PARALLEL_TESTS]; @@ -1730,7 +1731,7 @@ run_schedule(const char *schedule, test_function tfunc) if (num_tests == 1) { status(_("test %-28s ... "), tests[0]); - pids[0] = (tfunc) (tests[0], &resultfiles[0], &expectfiles[0], &tags[0]); + pids[0] = (startfunc) (tests[0], &resultfiles[0], &expectfiles[0], &tags[0]); INSTR_TIME_SET_CURRENT(starttimes[0]); wait_for_tests(pids, statuses, stoptimes, NULL, 1); /* status line is finished below */ @@ -1756,7 +1757,7 @@ run_schedule(const char *schedule, test_function tfunc) tests + oldest, i - oldest); oldest = i; } - pids[i] = (tfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]); + pids[i] = (startfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]); INSTR_TIME_SET_CURRENT(starttimes[i]); } wait_for_tests(pids + oldest, statuses + oldest, @@ -1769,7 +1770,7 @@ run_schedule(const char *schedule, test_function tfunc) status(_("parallel group (%d tests): "), num_tests); for (i = 0; i < num_tests; i++) { - pids[i] = (tfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]); + pids[i] = (startfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]); INSTR_TIME_SET_CURRENT(starttimes[i]); } wait_for_tests(pids, statuses, stoptimes, tests, num_tests); @@ -1801,6 +1802,8 @@ run_schedule(const char *schedule, test_function tfunc) { bool newdiff; + if (postfunc) + (*postfunc) (rl->str); newdiff = results_differ(tests[i], rl->str, el->str); if (newdiff && tl) { @@ -1867,7 +1870,8 @@ run_schedule(const char *schedule, test_function tfunc) * Run a single test */ static void -run_single_test(const char *test, test_function tfunc) +run_single_test(const char *test, test_start_function startfunc, + postprocess_result_function postfunc) { PID_TYPE pid; instr_time starttime; @@ -1882,7 +1886,7 @@ run_single_test(const char *test, test_function tfunc) bool differ = false; status(_("test %-28s ... "), test); - pid = (tfunc) (test, &resultfiles, &expectfiles, &tags); + pid = (startfunc) (test, &resultfiles, &expectfiles, &tags); INSTR_TIME_SET_CURRENT(starttime); wait_for_tests(&pid, &exit_status, &stoptime, NULL, 1); @@ -1900,6 +1904,8 @@ run_single_test(const char *test, test_function tfunc) { bool newdiff; + if (postfunc) + (*postfunc) (rl->str); newdiff = results_differ(test, rl->str, el->str); if (newdiff && tl) { @@ -2083,7 +2089,10 @@ help(void) } int -regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc) +regression_main(int argc, char *argv[], + init_function ifunc, + test_start_function startfunc, + postprocess_result_function postfunc) { static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, @@ -2554,12 +2563,12 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc for (sl = schedulelist; sl != NULL; sl = sl->next) { - run_schedule(sl->str, tfunc); + run_schedule(sl->str, startfunc, postfunc); } for (sl = extra_tests; sl != NULL; sl = sl->next) { - run_single_test(sl->str, tfunc); + run_single_test(sl->str, startfunc, postfunc); } /* diff --git a/src/test/regress/pg_regress.h b/src/test/regress/pg_regress.h index d04f7721aa8a1..c6d015c8402a2 100644 --- a/src/test/regress/pg_regress.h +++ b/src/test/regress/pg_regress.h @@ -27,12 +27,23 @@ typedef struct _stringlist struct _stringlist *next; } _stringlist; -typedef PID_TYPE(*test_function) (const char *, - _stringlist **, - _stringlist **, - _stringlist **); +/* + * Callback function signatures for test programs that use regression_main() + */ + +/* Initialize at program start */ typedef void (*init_function) (int argc, char **argv); +/* Launch one test case */ +typedef PID_TYPE(*test_start_function) (const char *testname, + _stringlist **resultfiles, + _stringlist **expectfiles, + _stringlist **tags); + +/* Postprocess one result file (optional) */ +typedef void (*postprocess_result_function) (const char *filename); + + extern char *bindir; extern char *libdir; extern char *datadir; @@ -48,7 +59,10 @@ extern const char *basic_diff_opts; extern const char *pretty_diff_opts; int regression_main(int argc, char *argv[], - init_function ifunc, test_function tfunc); + init_function ifunc, + test_start_function startfunc, + postprocess_result_function postfunc); + void add_stringlist_item(_stringlist **listhead, const char *str); PID_TYPE spawn_process(const char *cmdline); void replace_string(struct StringInfoData *string, diff --git a/src/test/regress/pg_regress_main.c b/src/test/regress/pg_regress_main.c index a218bae247c00..8dc4941c240cd 100644 --- a/src/test/regress/pg_regress_main.c +++ b/src/test/regress/pg_regress_main.c @@ -119,5 +119,8 @@ psql_init(int argc, char **argv) int main(int argc, char *argv[]) { - return regression_main(argc, argv, psql_init, psql_start_test); + return regression_main(argc, argv, + psql_init, + psql_start_test, + NULL /* no postfunc needed */ ); } From 52a10224e3cc1d706ba9800695f97cb163b747d5 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 11 Jan 2021 14:03:39 -0500 Subject: [PATCH 069/240] Uniformly identify the target host in libpq connection failure reports. Prefix "could not connect to host-or-socket-path:" to all connection failure cases that occur after the socket() call, and remove the ad-hoc server identity data that was appended to a few of these messages. This should produce much more intelligible error reports in multiple-target-host situations, especially for error cases that are off the beaten track to any degree (because none of those provided any server identity info). As an example of the change, formerly a connection attempt with a bad port number such as "psql -p 12345 -h localhost,/tmp" might produce psql: error: could not connect to server: Connection refused Is the server running on host "localhost" (::1) and accepting TCP/IP connections on port 12345? could not connect to server: Connection refused Is the server running on host "localhost" (127.0.0.1) and accepting TCP/IP connections on port 12345? could not connect to server: No such file or directory Is the server running locally and accepting connections on Unix domain socket "/tmp/.s.PGSQL.12345"? Now it looks like psql: error: could not connect to host "localhost" (::1), port 12345: Connection refused Is the server running on that host and accepting TCP/IP connections? could not connect to host "localhost" (127.0.0.1), port 12345: Connection refused Is the server running on that host and accepting TCP/IP connections? could not connect to socket "/tmp/.s.PGSQL.12345": No such file or directory Is the server running locally and accepting connections on that socket? This requires adjusting a couple of regression tests to allow for variation in the contents of a connection failure message. Discussion: https://postgr.es/m/BN6PR05MB3492948E4FD76C156E747E8BC9160@BN6PR05MB3492.namprd05.prod.outlook.com --- src/bin/pg_dump/t/002_pg_dump.pl | 2 +- .../ecpg/test/expected/connect-test5.stderr | 4 +- src/interfaces/libpq/fe-connect.c | 121 +++++++++--------- 3 files changed, 62 insertions(+), 65 deletions(-) diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl index 11dc98ee0a5ee..2b501166b80f5 100644 --- a/src/bin/pg_dump/t/002_pg_dump.pl +++ b/src/bin/pg_dump/t/002_pg_dump.pl @@ -3460,7 +3460,7 @@ command_fails_like( [ 'pg_dump', '-p', "$port", 'qqq' ], - qr/\Qpg_dump: error: connection to database "qqq" failed: FATAL: database "qqq" does not exist\E/, + qr/pg_dump: error: connection to database "qqq" failed: could not connect to .*: FATAL: database "qqq" does not exist/, 'connecting to a non-existent database'); ######################################### diff --git a/src/interfaces/ecpg/test/expected/connect-test5.stderr b/src/interfaces/ecpg/test/expected/connect-test5.stderr index a54df175fbf0d..4dbf2c0fc4626 100644 --- a/src/interfaces/ecpg/test/expected/connect-test5.stderr +++ b/src/interfaces/ecpg/test/expected/connect-test5.stderr @@ -36,7 +36,7 @@ [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ECPGconnect: opening database on port for user regress_ecpg_user2 [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ECPGconnect: could not open database: FATAL: database "regress_ecpg_user2" does not exist +[NO_PID]: ECPGconnect: could not open database: could not connect: FATAL: database "regress_ecpg_user2" does not exist [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ecpg_finish: connection main closed @@ -73,7 +73,7 @@ [NO_PID]: sqlca: code: -220, state: 08003 [NO_PID]: ECPGconnect: opening database on port for user regress_ecpg_user2 [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ECPGconnect: could not open database: FATAL: database "regress_ecpg_user2" does not exist +[NO_PID]: ECPGconnect: could not open database: could not connect: FATAL: database "regress_ecpg_user2" does not exist [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ecpg_finish: connection main closed diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 61a1fa6a14aad..a4a8b3ad7a54f 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -1669,15 +1669,17 @@ getHostaddr(PGconn *conn, char *host_addr, int host_addr_len) } /* ---------- - * connectFailureMessage - - * create a friendly error message on connection failure. + * emitCouldNotConnect - + * Speculatively append "could not connect to ...: " to conn->errorMessage + * once we've identified the current connection target address. This ensures + * that any subsequent error message will be properly attributed to the + * server we couldn't connect to. conn->raddr must be valid, and the result + * of getHostaddr() must be supplied. * ---------- */ static void -connectFailureMessage(PGconn *conn, int errorno) +emitCouldNotConnect(PGconn *conn, const char *host_addr) { - char sebuf[PG_STRERROR_R_BUFLEN]; - #ifdef HAVE_UNIX_SOCKETS if (IS_AF_UNIX(conn->raddr.addr.ss_family)) { @@ -1688,25 +1690,15 @@ connectFailureMessage(PGconn *conn, int errorno) service, sizeof(service), NI_NUMERICSERV); appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not connect to server: %s\n" - "\tIs the server running locally and accepting\n" - "\tconnections on Unix domain socket \"%s\"?\n"), - SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)), + libpq_gettext("could not connect to socket \"%s\": "), service); } else #endif /* HAVE_UNIX_SOCKETS */ { - char host_addr[NI_MAXHOST]; const char *displayed_host; const char *displayed_port; - /* - * Optionally display the network address with the hostname. This is - * useful to distinguish between IPv4 and IPv6 connections. - */ - getHostaddr(conn, host_addr, NI_MAXHOST); - /* To which host and port were we actually connecting? */ if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS) displayed_host = conn->connhost[conn->whichhost].hostaddr; @@ -1722,26 +1714,46 @@ connectFailureMessage(PGconn *conn, int errorno) * looked-up IP address. */ if (conn->connhost[conn->whichhost].type != CHT_HOST_ADDRESS && - strlen(host_addr) > 0 && + host_addr[0] && strcmp(displayed_host, host_addr) != 0) appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not connect to server: %s\n" - "\tIs the server running on host \"%s\" (%s) and accepting\n" - "\tTCP/IP connections on port %s?\n"), - SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)), + libpq_gettext("could not connect to host \"%s\" (%s), port %s: "), displayed_host, host_addr, displayed_port); else appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not connect to server: %s\n" - "\tIs the server running on host \"%s\" and accepting\n" - "\tTCP/IP connections on port %s?\n"), - SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)), + libpq_gettext("could not connect to host \"%s\", port %s: "), displayed_host, displayed_port); } } +/* ---------- + * connectFailureMessage - + * create a friendly error message on connection failure, + * using the given errno value. Use this for error cases that + * imply that there's no server there. + * ---------- + */ +static void +connectFailureMessage(PGconn *conn, int errorno) +{ + char sebuf[PG_STRERROR_R_BUFLEN]; + + appendPQExpBuffer(&conn->errorMessage, + "%s\n", + SOCK_STRERROR(errorno, sebuf, sizeof(sebuf))); + +#ifdef HAVE_UNIX_SOCKETS + if (IS_AF_UNIX(conn->raddr.addr.ss_family)) + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("\tIs the server running locally and accepting connections on that socket?\n")); + else +#endif + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("\tIs the server running on that host and accepting TCP/IP connections?\n")); +} + /* * Should we use keepalives? Returns 1 if yes, 0 if no, and -1 if * conn->keepalives is set to a value which is not parseable as an @@ -2476,30 +2488,30 @@ PQconnectPoll(PGconn *conn) goto keep_going; } - /* Remember current address for possible error msg */ + /* Remember current address for possible use later */ memcpy(&conn->raddr.addr, addr_cur->ai_addr, addr_cur->ai_addrlen); conn->raddr.salen = addr_cur->ai_addrlen; - /* set connip */ + /* + * Set connip, too. Note we purposely ignore strdup + * failure; not a big problem if it fails. + */ if (conn->connip != NULL) { free(conn->connip); conn->connip = NULL; } - getHostaddr(conn, host_addr, NI_MAXHOST); - if (strlen(host_addr) > 0) + if (host_addr[0]) conn->connip = strdup(host_addr); - /* - * purposely ignore strdup failure; not a big problem if - * it fails anyway. - */ - + /* Try to create the socket */ conn->sock = socket(addr_cur->ai_family, SOCK_STREAM, 0); if (conn->sock == PGINVALID_SOCKET) { + int errorno = SOCK_ERRNO; + /* * Silently ignore socket() failure if we have more * addresses to try; this reduces useless chatter in @@ -2512,12 +2524,20 @@ PQconnectPoll(PGconn *conn) conn->try_next_addr = true; goto keep_going; } + emitCouldNotConnect(conn, host_addr); appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not create socket: %s\n"), - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + SOCK_STRERROR(errorno, sebuf, sizeof(sebuf))); goto error_return; } + /* + * Once we've identified a target address, all errors + * except the preceding socket()-failure case should be + * prefixed with "could not connect to : ". + */ + emitCouldNotConnect(conn, host_addr); + /* * Select socket options: no delay of outgoing data for * TCP sockets, nonblock mode, close-on-exec. Try the @@ -3608,9 +3628,6 @@ PQconnectPoll(PGconn *conn) } case CONNECTION_CHECK_WRITABLE: { - const char *displayed_host; - const char *displayed_port; - conn->status = CONNECTION_OK; if (!PQconsumeInput(conn)) goto error_return; @@ -3634,19 +3651,8 @@ PQconnectPoll(PGconn *conn) PQclear(res); /* Append error report to conn->errorMessage. */ - if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS) - displayed_host = conn->connhost[conn->whichhost].hostaddr; - else - displayed_host = conn->connhost[conn->whichhost].host; - displayed_port = conn->connhost[conn->whichhost].port; - if (displayed_port == NULL || displayed_port[0] == '\0') - displayed_port = DEF_PGPORT_STR; - - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not make a writable " - "connection to server " - "\"%s:%s\"\n"), - displayed_host, displayed_port); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("session is read-only\n")); /* Close connection politely. */ conn->status = CONNECTION_OK; @@ -3679,17 +3685,8 @@ PQconnectPoll(PGconn *conn) PQclear(res); /* Append error report to conn->errorMessage. */ - if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS) - displayed_host = conn->connhost[conn->whichhost].hostaddr; - else - displayed_host = conn->connhost[conn->whichhost].host; - displayed_port = conn->connhost[conn->whichhost].port; - if (displayed_port == NULL || displayed_port[0] == '\0') - displayed_port = DEF_PGPORT_STR; - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("test \"SHOW transaction_read_only\" failed " - "on server \"%s:%s\"\n"), - displayed_host, displayed_port); + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("test \"SHOW transaction_read_only\" failed\n")); /* Close connection politely. */ conn->status = CONNECTION_OK; From c1d589571c497a952d7fbe40d9828655859d746f Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 11 Jan 2021 14:12:31 -0500 Subject: [PATCH 070/240] Try next host after a "cannot connect now" failure. If a server returns ERRCODE_CANNOT_CONNECT_NOW, try the next host, if multiple host names have been provided. This allows dealing gracefully with standby servers that might not be in hot standby mode yet. In the wake of the preceding commit, it might be plausible to retry many more error cases than we do now, but I (tgl) am hesitant to move too aggressively on that --- it's not clear it'd be desirable for cases such as bad-password, for example. But this case seems safe enough. Hubert Zhang, reviewed by Takayuki Tsunakawa Discussion: https://postgr.es/m/BN6PR05MB3492948E4FD76C156E747E8BC9160@BN6PR05MB3492.namprd05.prod.outlook.com --- src/interfaces/libpq/fe-connect.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index a4a8b3ad7a54f..2b78ed8ec3e34 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -3315,6 +3315,20 @@ PQconnectPoll(PGconn *conn) /* OK, we read the message; mark data consumed */ conn->inStart = conn->inCursor; + /* + * If error is "cannot connect now", try the next host if + * any (but we don't want to consider additional addresses + * for this host, nor is there much point in changing SSL + * or GSS mode). This is helpful when dealing with + * standby servers that might not be in hot-standby state. + */ + if (strcmp(conn->last_sqlstate, + ERRCODE_CANNOT_CONNECT_NOW) == 0) + { + conn->try_next_host = true; + goto keep_going; + } + /* Check to see if we should mention pgpassfile */ pgpassfileWarning(conn); From 4edf96846a02693e4416478b3302e5133d2e8e01 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 11 Jan 2021 14:53:42 -0500 Subject: [PATCH 071/240] Rethink SQLSTATE code for ERRCODE_IDLE_SESSION_TIMEOUT. Move it to class 57 (Operator Intervention), which seems like a better choice given that from the client's standpoint it behaves a heck of a lot like, e.g., ERRCODE_ADMIN_SHUTDOWN. In a green field I'd put ERRCODE_IDLE_IN_TRANSACTION_SESSION_TIMEOUT here as well. But that's been around for a few years, so it's probably too late to change its SQLSTATE code. Discussion: https://postgr.es/m/763A0689-F189-459E-946F-F0EC4458980B@hotmail.com --- src/backend/utils/errcodes.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/utils/errcodes.txt b/src/backend/utils/errcodes.txt index 1d5a78e73d6b9..9874a77805934 100644 --- a/src/backend/utils/errcodes.txt +++ b/src/backend/utils/errcodes.txt @@ -109,7 +109,6 @@ Section: Class 08 - Connection Exception 08004 E ERRCODE_SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION sqlserver_rejected_establishment_of_sqlconnection 08007 E ERRCODE_TRANSACTION_RESOLUTION_UNKNOWN transaction_resolution_unknown 08P01 E ERRCODE_PROTOCOL_VIOLATION protocol_violation -08P02 E ERRCODE_IDLE_SESSION_TIMEOUT idle_session_timeout Section: Class 09 - Triggered Action Exception @@ -429,6 +428,7 @@ Section: Class 57 - Operator Intervention 57P02 E ERRCODE_CRASH_SHUTDOWN crash_shutdown 57P03 E ERRCODE_CANNOT_CONNECT_NOW cannot_connect_now 57P04 E ERRCODE_DATABASE_DROPPED database_dropped +57P05 E ERRCODE_IDLE_SESSION_TIMEOUT idle_session_timeout Section: Class 58 - System Error (errors external to PostgreSQL itself) From f315205f3fafd6f6c7c479f480289fcf45700310 Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Tue, 12 Jan 2021 10:55:35 +1300 Subject: [PATCH 072/240] Fix function prototypes in dependency.h. Commit 257836a7 accidentally deleted a couple of redundant-but-conventional "extern" keywords on function prototypes. Put them back. Reported-by: Alvaro Herrera --- src/include/catalog/dependency.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index 6d6c23d8462aa..c8d07f48dea12 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -223,9 +223,9 @@ extern long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId); -long changeDependenciesOf(Oid classId, Oid oldObjectId, +extern long changeDependenciesOf(Oid classId, Oid oldObjectId, Oid newObjectId); -long changeDependenciesOn(Oid refClassId, Oid oldRefObjectId, +extern long changeDependenciesOn(Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId); extern Oid getExtensionOfObject(Oid classId, Oid objectId); From d5ab79d815783fe60062cefc423b54e82fbb92ff Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 11 Jan 2021 19:58:07 -0500 Subject: [PATCH 073/240] Make pg_dump's table of object-type priorities more maintainable. Wedging a new object type into this table has historically required manually renumbering a lot of existing entries. (Although it appears that some people got lazy and re-used the priority level of an existing object type, even if it wasn't particularly related.) We can let the compiler do the counting by inventing an enum type that lists the desired priority levels in order. Now, if you want to add or remove a priority level, that's a one-liner. This patch is not purely cosmetic, because I split apart the priorities of DO_COLLATION and DO_TRANSFORM, as well as those of DO_ACCESS_METHOD and DO_OPERATOR, which look to me to have been merged out of expediency rather than because it was a good idea. Shell types continue to be sorted interchangeably with full types, and opclasses interchangeably with opfamilies. --- src/bin/pg_dump/pg_dump_sort.c | 137 ++++++++++++++++++++++----------- 1 file changed, 93 insertions(+), 44 deletions(-) diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c index f990b86394229..022413812ea56 100644 --- a/src/bin/pg_dump/pg_dump_sort.c +++ b/src/bin/pg_dump/pg_dump_sort.c @@ -39,52 +39,101 @@ * POST_DATA objects must sort after DO_POST_DATA_BOUNDARY, and DATA objects * must sort between them. */ + +/* This enum lists the priority levels in order */ +enum dbObjectTypePriorities +{ + PRIO_NAMESPACE = 1, + PRIO_PROCLANG, + PRIO_COLLATION, + PRIO_TRANSFORM, + PRIO_EXTENSION, + PRIO_TYPE, /* used for DO_TYPE and DO_SHELL_TYPE */ + PRIO_FUNC, + PRIO_AGG, + PRIO_ACCESS_METHOD, + PRIO_OPERATOR, + PRIO_OPFAMILY, /* used for DO_OPFAMILY and DO_OPCLASS */ + PRIO_CAST, + PRIO_CONVERSION, + PRIO_TSPARSER, + PRIO_TSTEMPLATE, + PRIO_TSDICT, + PRIO_TSCONFIG, + PRIO_FDW, + PRIO_FOREIGN_SERVER, + PRIO_TABLE, + PRIO_DUMMY_TYPE, + PRIO_ATTRDEF, + PRIO_BLOB, + PRIO_PRE_DATA_BOUNDARY, /* boundary! */ + PRIO_TABLE_DATA, + PRIO_SEQUENCE_SET, + PRIO_BLOB_DATA, + PRIO_POST_DATA_BOUNDARY, /* boundary! */ + PRIO_CONSTRAINT, + PRIO_INDEX, + PRIO_INDEX_ATTACH, + PRIO_STATSEXT, + PRIO_RULE, + PRIO_TRIGGER, + PRIO_FK_CONSTRAINT, + PRIO_POLICY, + PRIO_PUBLICATION, + PRIO_PUBLICATION_REL, + PRIO_SUBSCRIPTION, + PRIO_DEFAULT_ACL, /* done in ACL pass */ + PRIO_EVENT_TRIGGER, /* must be next to last! */ + PRIO_REFRESH_MATVIEW /* must be last! */ +}; + +/* This table is indexed by enum DumpableObjectType */ static const int dbObjectTypePriority[] = { - 1, /* DO_NAMESPACE */ - 4, /* DO_EXTENSION */ - 5, /* DO_TYPE */ - 5, /* DO_SHELL_TYPE */ - 6, /* DO_FUNC */ - 7, /* DO_AGG */ - 8, /* DO_OPERATOR */ - 8, /* DO_ACCESS_METHOD */ - 9, /* DO_OPCLASS */ - 9, /* DO_OPFAMILY */ - 3, /* DO_COLLATION */ - 11, /* DO_CONVERSION */ - 18, /* DO_TABLE */ - 20, /* DO_ATTRDEF */ - 28, /* DO_INDEX */ - 29, /* DO_INDEX_ATTACH */ - 30, /* DO_STATSEXT */ - 31, /* DO_RULE */ - 32, /* DO_TRIGGER */ - 27, /* DO_CONSTRAINT */ - 33, /* DO_FK_CONSTRAINT */ - 2, /* DO_PROCLANG */ - 10, /* DO_CAST */ - 23, /* DO_TABLE_DATA */ - 24, /* DO_SEQUENCE_SET */ - 19, /* DO_DUMMY_TYPE */ - 12, /* DO_TSPARSER */ - 14, /* DO_TSDICT */ - 13, /* DO_TSTEMPLATE */ - 15, /* DO_TSCONFIG */ - 16, /* DO_FDW */ - 17, /* DO_FOREIGN_SERVER */ - 38, /* DO_DEFAULT_ACL --- done in ACL pass */ - 3, /* DO_TRANSFORM */ - 21, /* DO_BLOB */ - 25, /* DO_BLOB_DATA */ - 22, /* DO_PRE_DATA_BOUNDARY */ - 26, /* DO_POST_DATA_BOUNDARY */ - 39, /* DO_EVENT_TRIGGER --- next to last! */ - 40, /* DO_REFRESH_MATVIEW --- last! */ - 34, /* DO_POLICY */ - 35, /* DO_PUBLICATION */ - 36, /* DO_PUBLICATION_REL */ - 37 /* DO_SUBSCRIPTION */ + PRIO_NAMESPACE, /* DO_NAMESPACE */ + PRIO_EXTENSION, /* DO_EXTENSION */ + PRIO_TYPE, /* DO_TYPE */ + PRIO_TYPE, /* DO_SHELL_TYPE */ + PRIO_FUNC, /* DO_FUNC */ + PRIO_AGG, /* DO_AGG */ + PRIO_OPERATOR, /* DO_OPERATOR */ + PRIO_ACCESS_METHOD, /* DO_ACCESS_METHOD */ + PRIO_OPFAMILY, /* DO_OPCLASS */ + PRIO_OPFAMILY, /* DO_OPFAMILY */ + PRIO_COLLATION, /* DO_COLLATION */ + PRIO_CONVERSION, /* DO_CONVERSION */ + PRIO_TABLE, /* DO_TABLE */ + PRIO_ATTRDEF, /* DO_ATTRDEF */ + PRIO_INDEX, /* DO_INDEX */ + PRIO_INDEX_ATTACH, /* DO_INDEX_ATTACH */ + PRIO_STATSEXT, /* DO_STATSEXT */ + PRIO_RULE, /* DO_RULE */ + PRIO_TRIGGER, /* DO_TRIGGER */ + PRIO_CONSTRAINT, /* DO_CONSTRAINT */ + PRIO_FK_CONSTRAINT, /* DO_FK_CONSTRAINT */ + PRIO_PROCLANG, /* DO_PROCLANG */ + PRIO_CAST, /* DO_CAST */ + PRIO_TABLE_DATA, /* DO_TABLE_DATA */ + PRIO_SEQUENCE_SET, /* DO_SEQUENCE_SET */ + PRIO_DUMMY_TYPE, /* DO_DUMMY_TYPE */ + PRIO_TSPARSER, /* DO_TSPARSER */ + PRIO_TSDICT, /* DO_TSDICT */ + PRIO_TSTEMPLATE, /* DO_TSTEMPLATE */ + PRIO_TSCONFIG, /* DO_TSCONFIG */ + PRIO_FDW, /* DO_FDW */ + PRIO_FOREIGN_SERVER, /* DO_FOREIGN_SERVER */ + PRIO_DEFAULT_ACL, /* DO_DEFAULT_ACL */ + PRIO_TRANSFORM, /* DO_TRANSFORM */ + PRIO_BLOB, /* DO_BLOB */ + PRIO_BLOB_DATA, /* DO_BLOB_DATA */ + PRIO_PRE_DATA_BOUNDARY, /* DO_PRE_DATA_BOUNDARY */ + PRIO_POST_DATA_BOUNDARY, /* DO_POST_DATA_BOUNDARY */ + PRIO_EVENT_TRIGGER, /* DO_EVENT_TRIGGER */ + PRIO_REFRESH_MATVIEW, /* DO_REFRESH_MATVIEW */ + PRIO_POLICY, /* DO_POLICY */ + PRIO_PUBLICATION, /* DO_PUBLICATION */ + PRIO_PUBLICATION_REL, /* DO_PUBLICATION_REL */ + PRIO_SUBSCRIPTION /* DO_SUBSCRIPTION */ }; StaticAssertDecl(lengthof(dbObjectTypePriority) == (DO_SUBSCRIPTION + 1), From 9a4c0e36fbd671b5e7426a5a0670bdd7ba2714a0 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 11 Jan 2021 21:09:03 -0500 Subject: [PATCH 074/240] Dump ALTER TABLE ... ATTACH PARTITION as a separate ArchiveEntry. Previously, we emitted the ATTACH PARTITION command as part of the child table's ArchiveEntry. This was a poor choice since it complicates restoring the partition as a standalone table; you have to ignore the error from the ATTACH, which isn't even an option when restoring direct-to-database with pg_restore. (pg_restore will issue the whole ArchiveEntry as one PQexec, so that any error rolls back the table creation as well.) Hence, separate it out as its own ArchiveEntry, as indeed we already did for index ATTACH PARTITION commands. Justin Pryzby Discussion: https://postgr.es/m/20201023052940.GE9241@telsasoft.com --- src/bin/pg_dump/common.c | 39 ++++++++++++++++- src/bin/pg_dump/pg_dump.c | 77 ++++++++++++++++++++++++---------- src/bin/pg_dump/pg_dump.h | 10 ++++- src/bin/pg_dump/pg_dump_sort.c | 7 ++++ 4 files changed, 109 insertions(+), 24 deletions(-) diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c index f80d2d3ce8a3f..255f891432631 100644 --- a/src/bin/pg_dump/common.c +++ b/src/bin/pg_dump/common.c @@ -261,7 +261,9 @@ getSchemaData(Archive *fout, int *numTablesPtr) /* flagInhTables - * Fill in parent link fields of tables for which we need that information, - * and mark parents of target tables as interesting + * mark parents of target tables as interesting, and create + * TableAttachInfo objects for partitioned tables with appropriate + * dependency links. * * Note that only direct ancestors of targets are marked interesting. * This is sufficient; we don't much care whether they inherited their @@ -320,6 +322,40 @@ flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables, for (j = 0; j < numParents; j++) parents[j]->interesting = true; } + + /* Create TableAttachInfo object if needed */ + if (tblinfo[i].dobj.dump && tblinfo[i].ispartition) + { + TableAttachInfo *attachinfo; + + /* With partitions there can only be one parent */ + if (tblinfo[i].numParents != 1) + fatal("invalid number of parents %d for table \"%s\"", + tblinfo[i].numParents, + tblinfo[i].dobj.name); + + attachinfo = (TableAttachInfo *) palloc(sizeof(TableAttachInfo)); + attachinfo->dobj.objType = DO_TABLE_ATTACH; + attachinfo->dobj.catId.tableoid = 0; + attachinfo->dobj.catId.oid = 0; + AssignDumpId(&attachinfo->dobj); + attachinfo->dobj.name = pg_strdup(tblinfo[i].dobj.name); + attachinfo->dobj.namespace = tblinfo[i].dobj.namespace; + attachinfo->parentTbl = tblinfo[i].parents[0]; + attachinfo->partitionTbl = &tblinfo[i]; + + /* + * We must state the DO_TABLE_ATTACH object's dependencies + * explicitly, since it will not match anything in pg_depend. + * + * Give it dependencies on both the partition table and the parent + * table, so that it will not be executed till both of those + * exist. (There's no need to care what order those are created + * in.) + */ + addObjectDependency(&attachinfo->dobj, tblinfo[i].dobj.dumpId); + addObjectDependency(&attachinfo->dobj, tblinfo[i].parents[0]->dobj.dumpId); + } } } @@ -548,6 +584,7 @@ AssignDumpId(DumpableObject *dobj) dobj->name = NULL; /* must be set later */ dobj->namespace = NULL; /* may be set later */ dobj->dump = DUMP_COMPONENT_ALL; /* default assumption */ + dobj->dump_contains = DUMP_COMPONENT_ALL; /* default assumption */ dobj->ext_member = false; /* default assumption */ dobj->depends_on_ext = false; /* default assumption */ dobj->dependencies = NULL; diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 1f70653c02676..f2c88fa6b579e 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -202,6 +202,7 @@ static void dumpTrigger(Archive *fout, TriggerInfo *tginfo); static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo); static void dumpTable(Archive *fout, TableInfo *tbinfo); static void dumpTableSchema(Archive *fout, TableInfo *tbinfo); +static void dumpTableAttach(Archive *fout, TableAttachInfo *tbinfo); static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo); static void dumpSequence(Archive *fout, TableInfo *tbinfo); static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo); @@ -10176,6 +10177,9 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj) case DO_TABLE: dumpTable(fout, (TableInfo *) dobj); break; + case DO_TABLE_ATTACH: + dumpTableAttach(fout, (TableAttachInfo *) dobj); + break; case DO_ATTRDEF: dumpAttrDef(fout, (AttrDefInfo *) dobj); break; @@ -11183,7 +11187,7 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo) if (dopt->binary_upgrade) binary_upgrade_set_type_oids_by_type_oid(fout, q, tyinfo->dobj.catId.oid, - true, /* force array type */ + true, /* force array type */ false); /* force multirange type */ qtypname = pg_strdup(fmtId(tyinfo->dobj.name)); @@ -16133,27 +16137,6 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) } } - /* - * For partitioned tables, emit the ATTACH PARTITION clause. Note - * that we always want to create partitions this way instead of using - * CREATE TABLE .. PARTITION OF, mainly to preserve a possible column - * layout discrepancy with the parent, but also to ensure it gets the - * correct tablespace setting if it differs from the parent's. - */ - if (tbinfo->ispartition) - { - /* With partitions there can only be one parent */ - if (tbinfo->numParents != 1) - fatal("invalid number of parents %d for table \"%s\"", - tbinfo->numParents, tbinfo->dobj.name); - - /* Perform ALTER TABLE on the parent */ - appendPQExpBuffer(q, - "ALTER TABLE ONLY %s ATTACH PARTITION %s %s;\n", - fmtQualifiedDumpable(parents[0]), - qualrelname, tbinfo->partbound); - } - /* * In binary_upgrade mode, arrange to restore the old relfrozenxid and * relminmxid of all vacuumable relations. (While vacuum.c processes @@ -16383,6 +16366,55 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) free(qualrelname); } +/* + * dumpTableAttach + * write to fout the commands to attach a child partition + * + * Child partitions are always made by creating them separately + * and then using ATTACH PARTITION, rather than using + * CREATE TABLE ... PARTITION OF. This is important for preserving + * any possible discrepancy in column layout, to allow assigning the + * correct tablespace if different, and so that it's possible to restore + * a partition without restoring its parent. (You'll get an error from + * the ATTACH PARTITION command, but that can be ignored, or skipped + * using "pg_restore -L" if you prefer.) The last point motivates + * treating ATTACH PARTITION as a completely separate ArchiveEntry + * rather than emitting it within the child partition's ArchiveEntry. + */ +static void +dumpTableAttach(Archive *fout, TableAttachInfo *attachinfo) +{ + DumpOptions *dopt = fout->dopt; + PQExpBuffer q; + + if (dopt->dataOnly) + return; + + if (!(attachinfo->partitionTbl->dobj.dump & DUMP_COMPONENT_DEFINITION)) + return; + + q = createPQExpBuffer(); + + /* Perform ALTER TABLE on the parent */ + appendPQExpBuffer(q, + "ALTER TABLE ONLY %s ", + fmtQualifiedDumpable(attachinfo->parentTbl)); + appendPQExpBuffer(q, + "ATTACH PARTITION %s %s;\n", + fmtQualifiedDumpable(attachinfo->partitionTbl), + attachinfo->partitionTbl->partbound); + + ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId, + ARCHIVE_OPTS(.tag = attachinfo->dobj.name, + .namespace = attachinfo->dobj.namespace->dobj.name, + .owner = attachinfo->partitionTbl->rolname, + .description = "TABLE ATTACH", + .section = SECTION_PRE_DATA, + .createStmt = q->data)); + + destroyPQExpBuffer(q); +} + /* * dumpAttrDef --- dump an attribute's default-value declaration */ @@ -18344,6 +18376,7 @@ addBoundaryDependencies(DumpableObject **dobjs, int numObjs, case DO_COLLATION: case DO_CONVERSION: case DO_TABLE: + case DO_TABLE_ATTACH: case DO_ATTRDEF: case DO_PROCLANG: case DO_CAST: diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index b3ce4eefe2fae..731d0fe7ba849 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -50,6 +50,7 @@ typedef enum DO_COLLATION, DO_CONVERSION, DO_TABLE, + DO_TABLE_ATTACH, DO_ATTRDEF, DO_INDEX, DO_INDEX_ATTACH, @@ -338,6 +339,13 @@ typedef struct _tableInfo struct _triggerInfo *triggers; /* array of TriggerInfo structs */ } TableInfo; +typedef struct _tableAttachInfo +{ + DumpableObject dobj; + TableInfo *parentTbl; /* link to partitioned table */ + TableInfo *partitionTbl; /* link to partition */ +} TableAttachInfo; + typedef struct _attrDefInfo { DumpableObject dobj; /* note: dobj.name is name of table */ @@ -367,7 +375,7 @@ typedef struct _indxInfo int indnattrs; /* total number of index attributes */ Oid *indkeys; /* In spite of the name 'indkeys' this field * contains both key and nonkey attributes */ - char *inddependcollnames; /* FQ names of depended-on collations */ + char *inddependcollnames; /* FQ names of depended-on collations */ char *inddependcollversions; /* versions of the above */ bool indisclustered; bool indisreplident; diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c index 022413812ea56..46461fb6a1868 100644 --- a/src/bin/pg_dump/pg_dump_sort.c +++ b/src/bin/pg_dump/pg_dump_sort.c @@ -63,6 +63,7 @@ enum dbObjectTypePriorities PRIO_FDW, PRIO_FOREIGN_SERVER, PRIO_TABLE, + PRIO_TABLE_ATTACH, PRIO_DUMMY_TYPE, PRIO_ATTRDEF, PRIO_BLOB, @@ -103,6 +104,7 @@ static const int dbObjectTypePriority[] = PRIO_COLLATION, /* DO_COLLATION */ PRIO_CONVERSION, /* DO_CONVERSION */ PRIO_TABLE, /* DO_TABLE */ + PRIO_TABLE_ATTACH, /* DO_TABLE_ATTACH */ PRIO_ATTRDEF, /* DO_ATTRDEF */ PRIO_INDEX, /* DO_INDEX */ PRIO_INDEX_ATTACH, /* DO_INDEX_ATTACH */ @@ -1324,6 +1326,11 @@ describeDumpableObject(DumpableObject *obj, char *buf, int bufsize) "TABLE %s (ID %d OID %u)", obj->name, obj->dumpId, obj->catId.oid); return; + case DO_TABLE_ATTACH: + snprintf(buf, bufsize, + "TABLE ATTACH %s (ID %d)", + obj->name, obj->dumpId); + return; case DO_ATTRDEF: snprintf(buf, bufsize, "ATTRDEF %s.%s (ID %d OID %u)", From d6ad34f3410f101f9909c0918a49d6ce86fa216c Mon Sep 17 00:00:00 2001 From: Amit Kapila Date: Tue, 12 Jan 2021 07:45:40 +0530 Subject: [PATCH 075/240] Optimize DropRelFileNodeBuffers() for recovery. The recovery path of DropRelFileNodeBuffers() is optimized so that scanning of the whole buffer pool can be avoided when the number of blocks to be truncated in a relation is below a certain threshold. For such cases, we find the buffers by doing lookups in BufMapping table. This improves the performance by more than 100 times in many cases when several small tables (tested with 1000 relations) are truncated and where the server is configured with a large value of shared buffers (greater than equal to 100GB). This optimization helps cases (a) when vacuum or autovacuum truncated off any of the empty pages at the end of a relation, or (b) when the relation is truncated in the same transaction in which it was created. This commit introduces a new API smgrnblocks_cached which returns a cached value for the number of blocks in a relation fork. This helps us to determine the exact size of relation which is required to apply this optimization. The exact size is required to ensure that we don't leave any buffer for the relation being dropped as otherwise the background writer or checkpointer can lead to a PANIC error while flushing buffers corresponding to files that don't exist. Author: Kirk Jamison based on ideas by Amit Kapila Reviewed-by: Kyotaro Horiguchi, Takayuki Tsunakawa, and Amit Kapila Tested-By: Haiying Tang Discussion: https://postgr.es/m/OSBPR01MB3207DCA7EC725FDD661B3EDAEF660@OSBPR01MB3207.jpnprd01.prod.outlook.com --- src/backend/storage/buffer/bufmgr.c | 136 ++++++++++++++++++++++++++-- src/backend/storage/smgr/smgr.c | 30 ++++-- src/include/storage/bufmgr.h | 2 +- src/include/storage/smgr.h | 1 + 4 files changed, 154 insertions(+), 15 deletions(-) diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 71b5852224fcc..c192c2e35b5c3 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -70,6 +70,14 @@ #define RELS_BSEARCH_THRESHOLD 20 +/* + * This is the size (in the number of blocks) above which we scan the + * entire buffer pool to remove the buffers for all the pages of relation + * being dropped. For the relations with size below this threshold, we find + * the buffers by doing lookups in BufMapping table. + */ +#define BUF_DROP_FULL_SCAN_THRESHOLD (uint32) (NBuffers / 32) + typedef struct PrivateRefCountEntry { Buffer buffer; @@ -473,6 +481,10 @@ static BufferDesc *BufferAlloc(SMgrRelation smgr, BufferAccessStrategy strategy, bool *foundPtr); static void FlushBuffer(BufferDesc *buf, SMgrRelation reln); +static void FindAndDropRelFileNodeBuffers(RelFileNode rnode, + ForkNumber forkNum, + BlockNumber nForkBlock, + BlockNumber firstDelBlock); static void AtProcExit_Buffers(int code, Datum arg); static void CheckForBufferLeaks(void); static int rnode_comparator(const void *p1, const void *p2); @@ -2965,19 +2977,19 @@ BufferGetLSNAtomic(Buffer buffer) * later. It is also the responsibility of higher-level code to ensure * that no other process could be trying to load more pages of the * relation into buffers. - * - * XXX currently it sequentially searches the buffer pool, should be - * changed to more clever ways of searching. However, this routine - * is used only in code paths that aren't very performance-critical, - * and we shouldn't slow down the hot paths to make it faster ... * -------------------------------------------------------------------- */ void -DropRelFileNodeBuffers(RelFileNodeBackend rnode, ForkNumber *forkNum, +DropRelFileNodeBuffers(SMgrRelation smgr_reln, ForkNumber *forkNum, int nforks, BlockNumber *firstDelBlock) { int i; int j; + RelFileNodeBackend rnode; + BlockNumber nForkBlock[MAX_FORKNUM]; + BlockNumber nBlocksToInvalidate = 0; + + rnode = smgr_reln->smgr_rnode; /* If it's a local relation, it's localbuf.c's problem. */ if (RelFileNodeBackendIsTemp(rnode)) @@ -2991,6 +3003,56 @@ DropRelFileNodeBuffers(RelFileNodeBackend rnode, ForkNumber *forkNum, return; } + /* + * To remove all the pages of the specified relation forks from the buffer + * pool, we need to scan the entire buffer pool but we can optimize it by + * finding the buffers from BufMapping table provided we know the exact + * size of each fork of the relation. The exact size is required to ensure + * that we don't leave any buffer for the relation being dropped as + * otherwise the background writer or checkpointer can lead to a PANIC + * error while flushing buffers corresponding to files that don't exist. + * + * To know the exact size, we rely on the size cached for each fork by us + * during recovery which limits the optimization to recovery and on + * standbys but we can easily extend it once we have shared cache for + * relation size. + * + * In recovery, we cache the value returned by the first lseek(SEEK_END) + * and the future writes keeps the cached value up-to-date. See + * smgrextend. It is possible that the value of the first lseek is smaller + * than the actual number of existing blocks in the file due to buggy + * Linux kernels that might not have accounted for the recent write. But + * that should be fine because there must not be any buffers after that + * file size. + */ + for (i = 0; i < nforks; i++) + { + /* Get the number of blocks for a relation's fork */ + nForkBlock[i] = smgrnblocks_cached(smgr_reln, forkNum[i]); + + if (nForkBlock[i] == InvalidBlockNumber) + { + nBlocksToInvalidate = InvalidBlockNumber; + break; + } + + /* calculate the number of blocks to be invalidated */ + nBlocksToInvalidate += (nForkBlock[i] - firstDelBlock[i]); + } + + /* + * We apply the optimization iff the total number of blocks to invalidate + * is below the BUF_DROP_FULL_SCAN_THRESHOLD. + */ + if (BlockNumberIsValid(nBlocksToInvalidate) && + nBlocksToInvalidate < BUF_DROP_FULL_SCAN_THRESHOLD) + { + for (j = 0; j < nforks; j++) + FindAndDropRelFileNodeBuffers(rnode.node, forkNum[j], + nForkBlock[j], firstDelBlock[j]); + return; + } + for (i = 0; i < NBuffers; i++) { BufferDesc *bufHdr = GetBufferDescriptor(i); @@ -3133,6 +3195,65 @@ DropRelFileNodesAllBuffers(RelFileNodeBackend *rnodes, int nnodes) pfree(nodes); } +/* --------------------------------------------------------------------- + * FindAndDropRelFileNodeBuffers + * + * This function performs look up in BufMapping table and removes from the + * buffer pool all the pages of the specified relation fork that has block + * number >= firstDelBlock. (In particular, with firstDelBlock = 0, all + * pages are removed.) + * -------------------------------------------------------------------- + */ +static void +FindAndDropRelFileNodeBuffers(RelFileNode rnode, ForkNumber forkNum, + BlockNumber nForkBlock, + BlockNumber firstDelBlock) +{ + BlockNumber curBlock; + + for (curBlock = firstDelBlock; curBlock < nForkBlock; curBlock++) + { + uint32 bufHash; /* hash value for tag */ + BufferTag bufTag; /* identity of requested block */ + LWLock *bufPartitionLock; /* buffer partition lock for it */ + int buf_id; + BufferDesc *bufHdr; + uint32 buf_state; + + /* create a tag so we can lookup the buffer */ + INIT_BUFFERTAG(bufTag, rnode, forkNum, curBlock); + + /* determine its hash code and partition lock ID */ + bufHash = BufTableHashCode(&bufTag); + bufPartitionLock = BufMappingPartitionLock(bufHash); + + /* Check that it is in the buffer pool. If not, do nothing. */ + LWLockAcquire(bufPartitionLock, LW_SHARED); + buf_id = BufTableLookup(&bufTag, bufHash); + LWLockRelease(bufPartitionLock); + + if (buf_id < 0) + continue; + + bufHdr = GetBufferDescriptor(buf_id); + + /* + * We need to lock the buffer header and recheck if the buffer is + * still associated with the same block because the buffer could be + * evicted by some other backend loading blocks for a different + * relation after we release lock on the BufMapping table. + */ + buf_state = LockBufHdr(bufHdr); + + if (RelFileNodeEquals(bufHdr->tag.rnode, rnode) && + bufHdr->tag.forkNum == forkNum && + bufHdr->tag.blockNum >= firstDelBlock) + InvalidateBuffer(bufHdr); /* releases spinlock */ + else + UnlockBufHdr(bufHdr, buf_state); + } +} + /* --------------------------------------------------------------------- * DropDatabaseBuffers * @@ -3245,8 +3366,7 @@ PrintPinnedBufs(void) * XXX currently it sequentially searches the buffer pool, should be * changed to more clever ways of searching. This routine is not * used in any performance-critical code paths, so it's not worth - * adding additional overhead to normal paths to make it go faster; - * but see also DropRelFileNodeBuffers. + * adding additional overhead to normal paths to make it go faster. * -------------------------------------------------------------------- */ void diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c index 0f31ff38221f6..af603c3db3b3b 100644 --- a/src/backend/storage/smgr/smgr.c +++ b/src/backend/storage/smgr/smgr.c @@ -549,6 +549,28 @@ smgrnblocks(SMgrRelation reln, ForkNumber forknum) { BlockNumber result; + /* Check and return if we get the cached value for the number of blocks. */ + result = smgrnblocks_cached(reln, forknum); + if (result != InvalidBlockNumber) + return result; + + result = smgrsw[reln->smgr_which].smgr_nblocks(reln, forknum); + + reln->smgr_cached_nblocks[forknum] = result; + + return result; +} + +/* + * smgrnblocks_cached() -- Get the cached number of blocks in the supplied + * relation. + * + * Returns an InvalidBlockNumber when not in recovery and when the relation + * fork size is not cached. + */ +BlockNumber +smgrnblocks_cached(SMgrRelation reln, ForkNumber forknum) +{ /* * For now, we only use cached values in recovery due to lack of a shared * invalidation mechanism for changes in file size. @@ -556,11 +578,7 @@ smgrnblocks(SMgrRelation reln, ForkNumber forknum) if (InRecovery && reln->smgr_cached_nblocks[forknum] != InvalidBlockNumber) return reln->smgr_cached_nblocks[forknum]; - result = smgrsw[reln->smgr_which].smgr_nblocks(reln, forknum); - - reln->smgr_cached_nblocks[forknum] = result; - - return result; + return InvalidBlockNumber; } /* @@ -582,7 +600,7 @@ smgrtruncate(SMgrRelation reln, ForkNumber *forknum, int nforks, BlockNumber *nb * Get rid of any buffers for the about-to-be-deleted blocks. bufmgr will * just drop them without bothering to write the contents. */ - DropRelFileNodeBuffers(reln->smgr_rnode, forknum, nforks, nblocks); + DropRelFileNodeBuffers(reln, forknum, nforks, nblocks); /* * Send a shared-inval message to force other backends to close any smgr diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h index ff6cd0fc54e36..0c484f3addb92 100644 --- a/src/include/storage/bufmgr.h +++ b/src/include/storage/bufmgr.h @@ -203,7 +203,7 @@ extern void FlushOneBuffer(Buffer buffer); extern void FlushRelationBuffers(Relation rel); extern void FlushRelationsAllBuffers(struct SMgrRelationData **smgrs, int nrels); extern void FlushDatabaseBuffers(Oid dbid); -extern void DropRelFileNodeBuffers(RelFileNodeBackend rnode, ForkNumber *forkNum, +extern void DropRelFileNodeBuffers(struct SMgrRelationData *smgr_reln, ForkNumber *forkNum, int nforks, BlockNumber *firstDelBlock); extern void DropRelFileNodesAllBuffers(RelFileNodeBackend *rnodes, int nnodes); extern void DropDatabaseBuffers(Oid dbid); diff --git a/src/include/storage/smgr.h b/src/include/storage/smgr.h index ebf4a199dcb4d..a6fbf7b6a6c8a 100644 --- a/src/include/storage/smgr.h +++ b/src/include/storage/smgr.h @@ -99,6 +99,7 @@ extern void smgrwrite(SMgrRelation reln, ForkNumber forknum, extern void smgrwriteback(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, BlockNumber nblocks); extern BlockNumber smgrnblocks(SMgrRelation reln, ForkNumber forknum); +extern BlockNumber smgrnblocks_cached(SMgrRelation reln, ForkNumber forknum); extern void smgrtruncate(SMgrRelation reln, ForkNumber *forknum, int nforks, BlockNumber *nblocks); extern void smgrimmedsync(SMgrRelation reln, ForkNumber forknum); From 044aa9e70e552d9adb4f6429a1b0e96dde946a92 Mon Sep 17 00:00:00 2001 From: Amit Kapila Date: Tue, 12 Jan 2021 08:19:39 +0530 Subject: [PATCH 076/240] Fix relation descriptor leak. We missed closing the relation descriptor while sending changes via the root of partitioned relations during logical replication. Author: Amit Langote and Mark Zhao Reviewed-by: Amit Kapila and Ashutosh Bapat Backpatch-through: 13, where it was introduced Discussion: https://postgr.es/m/tencent_41FEA657C206F19AB4F406BE9252A0F69C06@qq.com Discussion: https://postgr.es/m/tencent_6E296D2F7D70AFC90D83353B69187C3AA507@qq.com --- src/backend/replication/pgoutput/pgoutput.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c index 81dbed33d511c..2f01137b426cd 100644 --- a/src/backend/replication/pgoutput/pgoutput.c +++ b/src/backend/replication/pgoutput/pgoutput.c @@ -502,6 +502,7 @@ pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, MemoryContext old; RelationSyncEntry *relentry; TransactionId xid = InvalidTransactionId; + Relation ancestor = NULL; if (!is_publishable_relation(relation)) return; @@ -552,7 +553,8 @@ pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, if (relentry->publish_as_relid != RelationGetRelid(relation)) { Assert(relation->rd_rel->relispartition); - relation = RelationIdGetRelation(relentry->publish_as_relid); + ancestor = RelationIdGetRelation(relentry->publish_as_relid); + relation = ancestor; /* Convert tuple if needed. */ if (relentry->map) tuple = execute_attr_map_tuple(tuple, relentry->map); @@ -574,7 +576,8 @@ pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, if (relentry->publish_as_relid != RelationGetRelid(relation)) { Assert(relation->rd_rel->relispartition); - relation = RelationIdGetRelation(relentry->publish_as_relid); + ancestor = RelationIdGetRelation(relentry->publish_as_relid); + relation = ancestor; /* Convert tuples if needed. */ if (relentry->map) { @@ -598,7 +601,8 @@ pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, if (relentry->publish_as_relid != RelationGetRelid(relation)) { Assert(relation->rd_rel->relispartition); - relation = RelationIdGetRelation(relentry->publish_as_relid); + ancestor = RelationIdGetRelation(relentry->publish_as_relid); + relation = ancestor; /* Convert tuple if needed. */ if (relentry->map) oldtuple = execute_attr_map_tuple(oldtuple, relentry->map); @@ -616,6 +620,12 @@ pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, Assert(false); } + if (RelationIsValid(ancestor)) + { + RelationClose(ancestor); + ancestor = NULL; + } + /* Cleanup */ MemoryContextSwitchTo(old); MemoryContextReset(data->context); From a3e51a36b77ab073df88860cc21b2a6094d699d4 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Tue, 12 Jan 2021 11:48:45 -0300 Subject: [PATCH 077/240] Fix thinko in comment This comment has been wrong since its introduction in commit 2c03216d8311. Author: Masahiko Sawada Discussion: https://postgr.es/m/CAD21AoAzz6qipFJBbGEaHmyWxvvNDp8httbwLR9tUQWaTjUs2Q@mail.gmail.com --- src/backend/access/transam/xlogreader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c index 0e8c74f2bb67b..bb95e0e527f09 100644 --- a/src/backend/access/transam/xlogreader.c +++ b/src/backend/access/transam/xlogreader.c @@ -1545,7 +1545,7 @@ XLogRecGetBlockData(XLogReaderState *record, uint8 block_id, Size *len) /* * Restore a full-page image from a backup block attached to an XLOG record. * - * Returns the buffer number containing the page. + * Returns true if a full-page image is restored. */ bool RestoreBlockImage(XLogReaderState *record, uint8 block_id, char *page) From cc865c0f319fde22540625e02863f42e9853b3e4 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 12 Jan 2021 12:52:14 -0500 Subject: [PATCH 078/240] Doc: fix description of privileges needed for ALTER PUBLICATION. Adding a table to a publication requires ownership of the table (in addition to ownership of the publication). This was mentioned nowhere. --- doc/src/sgml/ref/alter_publication.sgml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/src/sgml/ref/alter_publication.sgml b/doc/src/sgml/ref/alter_publication.sgml index c2946dfe0f8cf..faa114b2c681f 100644 --- a/doc/src/sgml/ref/alter_publication.sgml +++ b/doc/src/sgml/ref/alter_publication.sgml @@ -62,11 +62,12 @@ ALTER PUBLICATION name RENAME TO You must own the publication to use ALTER PUBLICATION. + Adding a table to a publication additionally requires owning that table. To alter the owner, you must also be a direct or indirect member of the new owning role. The new owner must have CREATE privilege on the database. Also, the new owner of a FOR ALL TABLES publication must be a superuser. However, a superuser can change the - ownership of a publication while circumventing these restrictions. + ownership of a publication regardless of these restrictions. From 9eabfe300a22ad3d776dc293265e15379790bd9a Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 12 Jan 2021 13:37:38 -0500 Subject: [PATCH 079/240] pg_dump: label INDEX ATTACH ArchiveEntries with an owner. Although a partitioned index's attachment to its parent doesn't have separate ownership, the ArchiveEntry for it needs to be marked with an owner anyway, to ensure that the ALTER command is run by the appropriate role when restoring with --use-set-session-authorization. Without this, the ALTER will be run by the role that started the restore session, which will usually work but it's formally the wrong thing. Back-patch to v11 where this type of ArchiveEntry was added. In HEAD, add equivalent commentary to the just-added TABLE ATTACH case, which I'd made do the right thing already. Discussion: https://postgr.es/m/1094034.1610418498@sss.pgh.pa.us --- src/bin/pg_dump/pg_dump.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index f2c88fa6b579e..3bcbd4bdc3f60 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -16404,6 +16404,13 @@ dumpTableAttach(Archive *fout, TableAttachInfo *attachinfo) fmtQualifiedDumpable(attachinfo->partitionTbl), attachinfo->partitionTbl->partbound); + /* + * There is no point in creating a drop query as the drop is done by table + * drop. (If you think to change this, see also _printTocEntry().) + * Although this object doesn't really have ownership as such, set the + * owner field anyway to ensure that the command is run by the correct + * role at restore time. + */ ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId, ARCHIVE_OPTS(.tag = attachinfo->dobj.name, .namespace = attachinfo->dobj.namespace->dobj.name, @@ -16685,9 +16692,17 @@ dumpIndexAttach(Archive *fout, IndexAttachInfo *attachinfo) appendPQExpBuffer(q, "ATTACH PARTITION %s;\n", fmtQualifiedDumpable(attachinfo->partitionIdx)); + /* + * There is no point in creating a drop query as the drop is done by + * index drop. (If you think to change this, see also + * _printTocEntry().) Although this object doesn't really have + * ownership as such, set the owner field anyway to ensure that the + * command is run by the correct role at restore time. + */ ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId, ARCHIVE_OPTS(.tag = attachinfo->dobj.name, .namespace = attachinfo->dobj.namespace->dobj.name, + .owner = attachinfo->parentIdx->indextable->rolname, .description = "INDEX ATTACH", .section = SECTION_POST_DATA, .createStmt = q->data)); From c6c4b37395b22f7e649234453a0aafe74d61b7e6 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Tue, 12 Jan 2021 17:04:49 -0300 Subject: [PATCH 080/240] Invent struct ReindexIndexInfo This struct is used by ReindexRelationConcurrently to keep track of the relations to process. This saves having to obtain some data repeatedly, and has future uses as well. Reviewed-by: Dmitry Dolgov <9erthalion6@gmail.com> Reviewed-by: Hamid Akhtar Reviewed-by: Masahiko Sawada Discussion: https://postgr.es/m/20201130195439.GA24598@alvherre.pgsql --- src/backend/commands/indexcmds.c | 126 ++++++++++++++++--------------- src/tools/pgindent/typedefs.list | 1 + 2 files changed, 66 insertions(+), 61 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 992f4813b4946..8c9c39a467533 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -3061,6 +3061,12 @@ ReindexMultipleInternal(List *relids, int options) static bool ReindexRelationConcurrently(Oid relationOid, int options) { + typedef struct ReindexIndexInfo + { + Oid indexId; + Oid tableId; + Oid amId; + } ReindexIndexInfo; List *heapRelationIds = NIL; List *indexIds = NIL; List *newIndexIds = NIL; @@ -3170,10 +3176,16 @@ ReindexRelationConcurrently(Oid relationOid, int options) get_rel_name(cellOid)))); else { + ReindexIndexInfo *idx; + /* Save the list of relation OIDs in private context */ oldcontext = MemoryContextSwitchTo(private_context); - indexIds = lappend_oid(indexIds, cellOid); + idx = palloc(sizeof(ReindexIndexInfo)); + idx->indexId = cellOid; + /* other fields set later */ + + indexIds = lappend(indexIds, idx); MemoryContextSwitchTo(oldcontext); } @@ -3210,13 +3222,18 @@ ReindexRelationConcurrently(Oid relationOid, int options) get_rel_name(cellOid)))); else { + ReindexIndexInfo *idx; + /* * Save the list of relation OIDs in private * context */ oldcontext = MemoryContextSwitchTo(private_context); - indexIds = lappend_oid(indexIds, cellOid); + idx = palloc(sizeof(ReindexIndexInfo)); + idx->indexId = cellOid; + indexIds = lappend(indexIds, idx); + /* other fields set later */ MemoryContextSwitchTo(oldcontext); } @@ -3235,6 +3252,7 @@ ReindexRelationConcurrently(Oid relationOid, int options) Oid heapId = IndexGetRelation(relationOid, (options & REINDEXOPT_MISSING_OK) != 0); Relation heapRelation; + ReindexIndexInfo *idx; /* if relation is missing, leave */ if (!OidIsValid(heapId)) @@ -3285,7 +3303,10 @@ ReindexRelationConcurrently(Oid relationOid, int options) * Save the list of relation OIDs in private context. Note * that invalid indexes are allowed here. */ - indexIds = lappend_oid(indexIds, relationOid); + idx = palloc(sizeof(ReindexIndexInfo)); + idx->indexId = relationOid; + indexIds = lappend(indexIds, idx); + /* other fields set later */ MemoryContextSwitchTo(oldcontext); break; @@ -3344,31 +3365,36 @@ ReindexRelationConcurrently(Oid relationOid, int options) foreach(lc, indexIds) { char *concurrentName; - Oid indexId = lfirst_oid(lc); + ReindexIndexInfo *idx = lfirst(lc); + ReindexIndexInfo *newidx; Oid newIndexId; Relation indexRel; Relation heapRel; Relation newIndexRel; LockRelId *lockrelid; - indexRel = index_open(indexId, ShareUpdateExclusiveLock); + indexRel = index_open(idx->indexId, ShareUpdateExclusiveLock); heapRel = table_open(indexRel->rd_index->indrelid, ShareUpdateExclusiveLock); + idx->tableId = RelationGetRelid(heapRel); + idx->amId = indexRel->rd_rel->relam; + /* This function shouldn't be called for temporary relations. */ if (indexRel->rd_rel->relpersistence == RELPERSISTENCE_TEMP) elog(ERROR, "cannot reindex a temporary table concurrently"); pgstat_progress_start_command(PROGRESS_COMMAND_CREATE_INDEX, - RelationGetRelid(heapRel)); + idx->tableId); + progress_vals[0] = PROGRESS_CREATEIDX_COMMAND_REINDEX_CONCURRENTLY; progress_vals[1] = 0; /* initializing */ - progress_vals[2] = indexId; - progress_vals[3] = indexRel->rd_rel->relam; + progress_vals[2] = idx->indexId; + progress_vals[3] = idx->amId; pgstat_progress_update_multi_param(4, progress_index, progress_vals); /* Choose a temporary relation name for the new index */ - concurrentName = ChooseRelationName(get_rel_name(indexId), + concurrentName = ChooseRelationName(get_rel_name(idx->indexId), NULL, "ccnew", get_rel_namespace(indexRel->rd_index->indrelid), @@ -3376,7 +3402,7 @@ ReindexRelationConcurrently(Oid relationOid, int options) /* Create new index definition based on given index */ newIndexId = index_concurrently_create_copy(heapRel, - indexId, + idx->indexId, concurrentName); /* @@ -3390,7 +3416,12 @@ ReindexRelationConcurrently(Oid relationOid, int options) */ oldcontext = MemoryContextSwitchTo(private_context); - newIndexIds = lappend_oid(newIndexIds, newIndexId); + newidx = palloc(sizeof(ReindexIndexInfo)); + newidx->indexId = newIndexId; + newidx->tableId = idx->tableId; + newidx->amId = idx->amId; + + newIndexIds = lappend(newIndexIds, newidx); /* * Save lockrelid to protect each relation from drop then close @@ -3471,10 +3502,7 @@ ReindexRelationConcurrently(Oid relationOid, int options) foreach(lc, newIndexIds) { - Relation newIndexRel; - Oid newIndexId = lfirst_oid(lc); - Oid heapId; - Oid indexam; + ReindexIndexInfo *newidx = lfirst(lc); /* Start new transaction for this index's concurrent build */ StartTransactionCommand(); @@ -3489,28 +3517,19 @@ ReindexRelationConcurrently(Oid relationOid, int options) /* Set ActiveSnapshot since functions in the indexes may need it */ PushActiveSnapshot(GetTransactionSnapshot()); - /* - * Index relation has been closed by previous commit, so reopen it to - * get its information. - */ - newIndexRel = index_open(newIndexId, ShareUpdateExclusiveLock); - heapId = newIndexRel->rd_index->indrelid; - indexam = newIndexRel->rd_rel->relam; - index_close(newIndexRel, NoLock); - /* * Update progress for the index to build, with the correct parent * table involved. */ - pgstat_progress_start_command(PROGRESS_COMMAND_CREATE_INDEX, heapId); + pgstat_progress_start_command(PROGRESS_COMMAND_CREATE_INDEX, newidx->tableId); progress_vals[0] = PROGRESS_CREATEIDX_COMMAND_REINDEX_CONCURRENTLY; progress_vals[1] = PROGRESS_CREATEIDX_PHASE_BUILD; - progress_vals[2] = newIndexId; - progress_vals[3] = indexam; + progress_vals[2] = newidx->indexId; + progress_vals[3] = newidx->amId; pgstat_progress_update_multi_param(4, progress_index, progress_vals); /* Perform concurrent build of new index */ - index_concurrently_build(heapId, newIndexId); + index_concurrently_build(newidx->tableId, newidx->indexId); PopActiveSnapshot(); CommitTransactionCommand(); @@ -3532,12 +3551,9 @@ ReindexRelationConcurrently(Oid relationOid, int options) foreach(lc, newIndexIds) { - Oid newIndexId = lfirst_oid(lc); - Oid heapId; + ReindexIndexInfo *newidx = lfirst(lc); TransactionId limitXmin; Snapshot snapshot; - Relation newIndexRel; - Oid indexam; StartTransactionCommand(); @@ -3555,27 +3571,19 @@ ReindexRelationConcurrently(Oid relationOid, int options) snapshot = RegisterSnapshot(GetTransactionSnapshot()); PushActiveSnapshot(snapshot); - /* - * Index relation has been closed by previous commit, so reopen it to - * get its information. - */ - newIndexRel = index_open(newIndexId, ShareUpdateExclusiveLock); - heapId = newIndexRel->rd_index->indrelid; - indexam = newIndexRel->rd_rel->relam; - index_close(newIndexRel, NoLock); - /* * Update progress for the index to build, with the correct parent * table involved. */ - pgstat_progress_start_command(PROGRESS_COMMAND_CREATE_INDEX, heapId); + pgstat_progress_start_command(PROGRESS_COMMAND_CREATE_INDEX, + newidx->tableId); progress_vals[0] = PROGRESS_CREATEIDX_COMMAND_REINDEX_CONCURRENTLY; progress_vals[1] = PROGRESS_CREATEIDX_PHASE_VALIDATE_IDXSCAN; - progress_vals[2] = newIndexId; - progress_vals[3] = indexam; + progress_vals[2] = newidx->indexId; + progress_vals[3] = newidx->amId; pgstat_progress_update_multi_param(4, progress_index, progress_vals); - validate_index(heapId, newIndexId, snapshot); + validate_index(newidx->tableId, newidx->indexId, snapshot); /* * We can now do away with our active snapshot, we still need to save @@ -3622,10 +3630,9 @@ ReindexRelationConcurrently(Oid relationOid, int options) forboth(lc, indexIds, lc2, newIndexIds) { + ReindexIndexInfo *oldidx = lfirst(lc); + ReindexIndexInfo *newidx = lfirst(lc2); char *oldName; - Oid oldIndexId = lfirst_oid(lc); - Oid newIndexId = lfirst_oid(lc2); - Oid heapId; /* * Check for user-requested abort. This is inside a transaction so as @@ -3634,27 +3641,25 @@ ReindexRelationConcurrently(Oid relationOid, int options) */ CHECK_FOR_INTERRUPTS(); - heapId = IndexGetRelation(oldIndexId, false); - /* Choose a relation name for old index */ - oldName = ChooseRelationName(get_rel_name(oldIndexId), + oldName = ChooseRelationName(get_rel_name(oldidx->indexId), NULL, "ccold", - get_rel_namespace(heapId), + get_rel_namespace(oldidx->tableId), false); /* * Swap old index with the new one. This also marks the new one as * valid and the old one as not valid. */ - index_concurrently_swap(newIndexId, oldIndexId, oldName); + index_concurrently_swap(newidx->indexId, oldidx->indexId, oldName); /* * Invalidate the relcache for the table, so that after this commit * all sessions will refresh any cached plans that might reference the * index. */ - CacheInvalidateRelcacheByRelid(heapId); + CacheInvalidateRelcacheByRelid(oldidx->tableId); /* * CCI here so that subsequent iterations see the oldName in the @@ -3684,8 +3689,7 @@ ReindexRelationConcurrently(Oid relationOid, int options) foreach(lc, indexIds) { - Oid oldIndexId = lfirst_oid(lc); - Oid heapId; + ReindexIndexInfo *oldidx = lfirst(lc); /* * Check for user-requested abort. This is inside a transaction so as @@ -3694,8 +3698,7 @@ ReindexRelationConcurrently(Oid relationOid, int options) */ CHECK_FOR_INTERRUPTS(); - heapId = IndexGetRelation(oldIndexId, false); - index_concurrently_set_dead(heapId, oldIndexId); + index_concurrently_set_dead(oldidx->tableId, oldidx->indexId); } /* Commit this transaction to make the updates visible. */ @@ -3719,11 +3722,11 @@ ReindexRelationConcurrently(Oid relationOid, int options) foreach(lc, indexIds) { - Oid oldIndexId = lfirst_oid(lc); + ReindexIndexInfo *idx = lfirst(lc); ObjectAddress object; object.classId = RelationRelationId; - object.objectId = oldIndexId; + object.objectId = idx->indexId; object.objectSubId = 0; add_exact_object_address(&object, objects); @@ -3766,7 +3769,8 @@ ReindexRelationConcurrently(Oid relationOid, int options) { foreach(lc, newIndexIds) { - Oid indOid = lfirst_oid(lc); + ReindexIndexInfo *idx = lfirst(lc); + Oid indOid = idx->indexId; ereport(INFO, (errmsg("index \"%s.%s\" was reindexed", diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index f3957bad6c290..fb57b8393f177 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -2061,6 +2061,7 @@ Regis RegisNode RegisteredBgWorker ReindexErrorInfo +ReindexIndexInfo ReindexObjectType ReindexStmt ReindexType From fce7d0e6efbef304e81846c75eddf73099628d10 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Wed, 13 Jan 2021 10:32:21 +0900 Subject: [PATCH 081/240] Fix routine name in comment of catcache.c Author: Bharath Rupireddy Discussion: https://postgr.es/m/CALj2ACUDXLAkf_XxQO9tAUtnTNGi3Lmd8fANd+vBJbcHn1HoWA@mail.gmail.com --- src/backend/utils/cache/catcache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c index ba95755867029..fa2b49c676e6b 100644 --- a/src/backend/utils/cache/catcache.c +++ b/src/backend/utils/cache/catcache.c @@ -1128,7 +1128,7 @@ IndexScanOK(CatCache *cache, ScanKey cur_skey) } /* - * SearchCatCacheInternal + * SearchCatCache * * This call searches a system cache for a tuple, opening the relation * if necessary (on the first access to a particular cache). From bea449c635c0e68e21610593594c1e5d52842cdd Mon Sep 17 00:00:00 2001 From: Amit Kapila Date: Wed, 13 Jan 2021 07:46:11 +0530 Subject: [PATCH 082/240] Optimize DropRelFileNodesAllBuffers() for recovery. Similar to commit d6ad34f341, this patch optimizes DropRelFileNodesAllBuffers() by avoiding the complete buffer pool scan and instead find the buffers to be invalidated by doing lookups in the BufMapping table. This optimization helps operations where the relation files need to be removed like Truncate, Drop, Abort of Create Table, etc. Author: Kirk Jamison Reviewed-by: Kyotaro Horiguchi, Takayuki Tsunakawa, and Amit Kapila Tested-By: Haiying Tang Discussion: https://postgr.es/m/OSBPR01MB3207DCA7EC725FDD661B3EDAEF660@OSBPR01MB3207.jpnprd01.prod.outlook.com --- src/backend/storage/buffer/bufmgr.c | 86 ++++++++++++++++++++++++++--- src/backend/storage/smgr/smgr.c | 12 ++-- src/include/storage/bufmgr.h | 2 +- 3 files changed, 84 insertions(+), 16 deletions(-) diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index c192c2e35b5c3..c46b8abad12e4 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -3104,28 +3104,33 @@ DropRelFileNodeBuffers(SMgrRelation smgr_reln, ForkNumber *forkNum, * -------------------------------------------------------------------- */ void -DropRelFileNodesAllBuffers(RelFileNodeBackend *rnodes, int nnodes) +DropRelFileNodesAllBuffers(SMgrRelation *smgr_reln, int nnodes) { - int i, - n = 0; + int i; + int j; + int n = 0; + SMgrRelation *rels; + BlockNumber (*block)[MAX_FORKNUM + 1]; + BlockNumber nBlocksToInvalidate = 0; RelFileNode *nodes; + bool cached = true; bool use_bsearch; if (nnodes == 0) return; - nodes = palloc(sizeof(RelFileNode) * nnodes); /* non-local relations */ + rels = palloc(sizeof(SMgrRelation) * nnodes); /* non-local relations */ /* If it's a local relation, it's localbuf.c's problem. */ for (i = 0; i < nnodes; i++) { - if (RelFileNodeBackendIsTemp(rnodes[i])) + if (RelFileNodeBackendIsTemp(smgr_reln[i]->smgr_rnode)) { - if (rnodes[i].backend == MyBackendId) - DropRelFileNodeAllLocalBuffers(rnodes[i].node); + if (smgr_reln[i]->smgr_rnode.backend == MyBackendId) + DropRelFileNodeAllLocalBuffers(smgr_reln[i]->smgr_rnode.node); } else - nodes[n++] = rnodes[i].node; + rels[n++] = smgr_reln[i]; } /* @@ -3134,10 +3139,72 @@ DropRelFileNodesAllBuffers(RelFileNodeBackend *rnodes, int nnodes) */ if (n == 0) { - pfree(nodes); + pfree(rels); return; } + /* + * This is used to remember the number of blocks for all the relations + * forks. + */ + block = (BlockNumber (*)[MAX_FORKNUM + 1]) + palloc(sizeof(BlockNumber) * n * (MAX_FORKNUM + 1)); + + /* + * We can avoid scanning the entire buffer pool if we know the exact size + * of each of the given relation forks. See DropRelFileNodeBuffers. + */ + for (i = 0; i < n && cached; i++) + { + for (j = 0; j <= MAX_FORKNUM; j++) + { + /* Get the number of blocks for a relation's fork. */ + block[i][j] = smgrnblocks_cached(rels[i], j); + + /* We need to only consider the relation forks that exists. */ + if (block[i][j] == InvalidBlockNumber) + { + if (!smgrexists(rels[i], j)) + continue; + cached = false; + break; + } + + /* calculate the total number of blocks to be invalidated */ + nBlocksToInvalidate += block[i][j]; + } + } + + /* + * We apply the optimization iff the total number of blocks to invalidate + * is below the BUF_DROP_FULL_SCAN_THRESHOLD. + */ + if (cached && nBlocksToInvalidate < BUF_DROP_FULL_SCAN_THRESHOLD) + { + for (i = 0; i < n; i++) + { + for (j = 0; j <= MAX_FORKNUM; j++) + { + /* ignore relation forks that doesn't exist */ + if (!BlockNumberIsValid(block[i][j])) + continue; + + /* drop all the buffers for a particular relation fork */ + FindAndDropRelFileNodeBuffers(rels[i]->smgr_rnode.node, + j, block[i][j], 0); + } + } + + pfree(block); + pfree(rels); + return; + } + + pfree(block); + nodes = palloc(sizeof(RelFileNode) * n); /* non-local relations */ + for (i = 0; i < n; i++) + nodes[i] = rels[i]->smgr_rnode.node; + /* * For low number of relations to drop just use a simple walk through, to * save the bsearch overhead. The threshold to use is rather a guess than @@ -3193,6 +3260,7 @@ DropRelFileNodesAllBuffers(RelFileNodeBackend *rnodes, int nnodes) } pfree(nodes); + pfree(rels); } /* --------------------------------------------------------------------- diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c index af603c3db3b3b..4dc24649df982 100644 --- a/src/backend/storage/smgr/smgr.c +++ b/src/backend/storage/smgr/smgr.c @@ -390,6 +390,12 @@ smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo) if (nrels == 0) return; + /* + * Get rid of any remaining buffers for the relations. bufmgr will just + * drop them without bothering to write the contents. + */ + DropRelFileNodesAllBuffers(rels, nrels); + /* * create an array which contains all relations to be dropped, and close * each relation's forks at the smgr level while at it @@ -407,12 +413,6 @@ smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo) smgrsw[which].smgr_close(rels[i], forknum); } - /* - * Get rid of any remaining buffers for the relations. bufmgr will just - * drop them without bothering to write the contents. - */ - DropRelFileNodesAllBuffers(rnodes, nrels); - /* * It'd be nice to tell the stats collector to forget them immediately, * too. But we can't because we don't know the OIDs. diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h index 0c484f3addb92..fb00fda6a7f21 100644 --- a/src/include/storage/bufmgr.h +++ b/src/include/storage/bufmgr.h @@ -205,7 +205,7 @@ extern void FlushRelationsAllBuffers(struct SMgrRelationData **smgrs, int nrels) extern void FlushDatabaseBuffers(Oid dbid); extern void DropRelFileNodeBuffers(struct SMgrRelationData *smgr_reln, ForkNumber *forkNum, int nforks, BlockNumber *firstDelBlock); -extern void DropRelFileNodesAllBuffers(RelFileNodeBackend *rnodes, int nnodes); +extern void DropRelFileNodesAllBuffers(struct SMgrRelationData **smgr_reln, int nnodes); extern void DropDatabaseBuffers(Oid dbid); #define RelationGetNumberOfBlocks(reln) \ From ee1b38f65948cb09ecf3c39b58bd88aabc950e7c Mon Sep 17 00:00:00 2001 From: Amit Kapila Date: Wed, 13 Jan 2021 08:19:50 +0530 Subject: [PATCH 083/240] Fix memory leak in SnapBuildSerialize. The memory for the snapshot was leaked while serializing it to disk during logical decoding. This memory will be freed only once walsender stops streaming the changes. This can lead to a huge memory increase when master logs Standby Snapshot too frequently say when the user is trying to create many replication slots. Reported-by: funnyxj.fxj@alibaba-inc.com Diagnosed-by: funnyxj.fxj@alibaba-inc.com Author: Amit Kapila Backpatch-through: 9.5 Discussion: https://postgr.es/m/033ab54c-6393-42ee-8ec9-2b399b5d8cde.funnyxj.fxj@alibaba-inc.com --- src/backend/replication/logical/snapbuild.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c index 15b07a54c1172..71d510e305e14 100644 --- a/src/backend/replication/logical/snapbuild.c +++ b/src/backend/replication/logical/snapbuild.c @@ -1488,7 +1488,7 @@ static void SnapBuildSerialize(SnapBuild *builder, XLogRecPtr lsn) { Size needed_length; - SnapBuildOnDisk *ondisk; + SnapBuildOnDisk *ondisk = NULL; char *ondisk_c; int fd; char tmppath[MAXPGPATH]; @@ -1687,6 +1687,9 @@ SnapBuildSerialize(SnapBuild *builder, XLogRecPtr lsn) out: ReorderBufferSetRestartPoint(builder->reorder, builder->last_serialized_snapshot); + /* be tidy */ + if (ondisk) + pfree(ondisk); } /* From df10ac625c1672edf839ff59cfcac9dcc097515c Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Wed, 13 Jan 2021 19:11:09 +1300 Subject: [PATCH 084/240] Don't use elog() in src/port/pwrite.c. Nothing broke because of this oversight yet, but it would fail to link if we tried to use pg_pwrite() in frontend code on a system that lacks pwrite(). Use an assertion instead. Also pgindent while here. Discussion: https://postgr.es/m/CA%2BhUKGL57RvoQsS35TVPnQoPYqbtBixsdRhynB8NpcUKpHTTtg%40mail.gmail.com --- src/port/pwrite.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/port/pwrite.c b/src/port/pwrite.c index e029f44bc0ce0..a98343ec05b70 100644 --- a/src/port/pwrite.c +++ b/src/port/pwrite.c @@ -70,8 +70,8 @@ pg_pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) return -1; return writev(fd, iov, iovcnt); #else - ssize_t sum = 0; - ssize_t part; + ssize_t sum = 0; + ssize_t part; for (int i = 0; i < iovcnt; ++i) { @@ -137,14 +137,14 @@ pg_pwritev_with_retry(int fd, const struct iovec *iov, int iovcnt, off_t offset) /* Are they all done? */ if (iovcnt == 0) { - if (part > 0) - elog(ERROR, "unexpectedly wrote more than requested"); + /* We don't expect the kernel to write more than requested. */ + Assert(part == 0); break; } /* - * Move whatever's left to the front of our mutable copy and adjust the - * leading iovec. + * Move whatever's left to the front of our mutable copy and adjust + * the leading iovec. */ Assert(iovcnt > 0); memmove(iov_copy, iov, sizeof(*iov) * iovcnt); From 756ab29124d7850d4392e2227b67b69b61576cd6 Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Wed, 13 Jan 2021 10:33:33 +0200 Subject: [PATCH 085/240] Add functions to 'pageinspect' to inspect GiST indexes. Author: Andrey Borodin and me Discussion: https://www.postgresql.org/message-id/3E4F9093-A1B5-4DF8-A292-0B48692E3954%40yandex-team.ru --- contrib/pageinspect/Makefile | 6 +- contrib/pageinspect/expected/gist.out | 87 ++++++ contrib/pageinspect/gistfuncs.c | 287 ++++++++++++++++++ contrib/pageinspect/pageinspect--1.8--1.9.sql | 41 +++ contrib/pageinspect/pageinspect.control | 2 +- contrib/pageinspect/sql/gist.sql | 18 ++ doc/src/sgml/pageinspect.sgml | 89 ++++++ 7 files changed, 527 insertions(+), 3 deletions(-) create mode 100644 contrib/pageinspect/expected/gist.out create mode 100644 contrib/pageinspect/gistfuncs.c create mode 100644 contrib/pageinspect/pageinspect--1.8--1.9.sql create mode 100644 contrib/pageinspect/sql/gist.sql diff --git a/contrib/pageinspect/Makefile b/contrib/pageinspect/Makefile index d9d8177116b03..4539f0aef79ad 100644 --- a/contrib/pageinspect/Makefile +++ b/contrib/pageinspect/Makefile @@ -7,19 +7,21 @@ OBJS = \ btreefuncs.o \ fsmfuncs.o \ ginfuncs.o \ + gistfuncs.o \ hashfuncs.o \ heapfuncs.o \ rawpage.o EXTENSION = pageinspect -DATA = pageinspect--1.7--1.8.sql pageinspect--1.6--1.7.sql \ +DATA = pageinspect--1.8--1.9.sql \ + pageinspect--1.7--1.8.sql pageinspect--1.6--1.7.sql \ pageinspect--1.5.sql pageinspect--1.5--1.6.sql \ pageinspect--1.4--1.5.sql pageinspect--1.3--1.4.sql \ pageinspect--1.2--1.3.sql pageinspect--1.1--1.2.sql \ pageinspect--1.0--1.1.sql PGFILEDESC = "pageinspect - functions to inspect contents of database pages" -REGRESS = page btree brin gin hash checksum +REGRESS = page btree brin gin gist hash checksum ifdef USE_PGXS PG_CONFIG = pg_config diff --git a/contrib/pageinspect/expected/gist.out b/contrib/pageinspect/expected/gist.out new file mode 100644 index 0000000000000..89294b5a17d72 --- /dev/null +++ b/contrib/pageinspect/expected/gist.out @@ -0,0 +1,87 @@ +CREATE TABLE test_gist AS SELECT point(i,i) p, i::text t FROM + generate_series(1,1000) i; +CREATE INDEX test_gist_idx ON test_gist USING gist (p); +-- Page 0 is the root, the rest are leaf pages +SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 0)); + lsn | nsn | rightlink | flags +-----+-----+------------+------- + 0/1 | 0/0 | 4294967295 | {} +(1 row) + +SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 1)); + lsn | nsn | rightlink | flags +-----+-----+------------+-------- + 0/1 | 0/0 | 4294967295 | {leaf} +(1 row) + +SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 2)); + lsn | nsn | rightlink | flags +-----+-----+-----------+-------- + 0/1 | 0/0 | 1 | {leaf} +(1 row) + +SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 0), 'test_gist_idx'); + itemoffset | ctid | itemlen | keys +------------+-----------+---------+------------------- + 1 | (1,65535) | 40 | (p)=((166,166)) + 2 | (2,65535) | 40 | (p)=((332,332)) + 3 | (3,65535) | 40 | (p)=((498,498)) + 4 | (4,65535) | 40 | (p)=((664,664)) + 5 | (5,65535) | 40 | (p)=((830,830)) + 6 | (6,65535) | 40 | (p)=((996,996)) + 7 | (7,65535) | 40 | (p)=((1000,1000)) +(7 rows) + +SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 1), 'test_gist_idx') LIMIT 5; + itemoffset | ctid | itemlen | keys +------------+-------+---------+------------- + 1 | (0,1) | 40 | (p)=((1,1)) + 2 | (0,2) | 40 | (p)=((2,2)) + 3 | (0,3) | 40 | (p)=((3,3)) + 4 | (0,4) | 40 | (p)=((4,4)) + 5 | (0,5) | 40 | (p)=((5,5)) +(5 rows) + +SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 2), 'test_gist_idx') LIMIT 5; + itemoffset | ctid | itemlen | keys +------------+--------+---------+----------------- + 1 | (1,10) | 40 | (p)=((167,167)) + 2 | (1,11) | 40 | (p)=((168,168)) + 3 | (1,12) | 40 | (p)=((169,169)) + 4 | (1,13) | 40 | (p)=((170,170)) + 5 | (1,14) | 40 | (p)=((171,171)) +(5 rows) + +SELECT * FROM gist_page_items_bytea(get_raw_page('test_gist_idx', 0)); + itemoffset | ctid | itemlen | key_data +------------+-----------+---------+------------------------------------------------------------------------------------ + 1 | (1,65535) | 40 | \x00000100ffff28000000000000c064400000000000c06440000000000000f03f000000000000f03f + 2 | (2,65535) | 40 | \x00000200ffff28000000000000c074400000000000c074400000000000e064400000000000e06440 + 3 | (3,65535) | 40 | \x00000300ffff28000000000000207f400000000000207f400000000000d074400000000000d07440 + 4 | (4,65535) | 40 | \x00000400ffff28000000000000c084400000000000c084400000000000307f400000000000307f40 + 5 | (5,65535) | 40 | \x00000500ffff28000000000000f089400000000000f089400000000000c884400000000000c88440 + 6 | (6,65535) | 40 | \x00000600ffff28000000000000208f400000000000208f400000000000f889400000000000f88940 + 7 | (7,65535) | 40 | \x00000700ffff28000000000000408f400000000000408f400000000000288f400000000000288f40 +(7 rows) + +SELECT * FROM gist_page_items_bytea(get_raw_page('test_gist_idx', 1)) LIMIT 5; + itemoffset | ctid | itemlen | key_data +------------+-------+---------+------------------------------------------------------------------------------------ + 1 | (0,1) | 40 | \x0000000001002800000000000000f03f000000000000f03f000000000000f03f000000000000f03f + 2 | (0,2) | 40 | \x00000000020028000000000000000040000000000000004000000000000000400000000000000040 + 3 | (0,3) | 40 | \x00000000030028000000000000000840000000000000084000000000000008400000000000000840 + 4 | (0,4) | 40 | \x00000000040028000000000000001040000000000000104000000000000010400000000000001040 + 5 | (0,5) | 40 | \x00000000050028000000000000001440000000000000144000000000000014400000000000001440 +(5 rows) + +SELECT * FROM gist_page_items_bytea(get_raw_page('test_gist_idx', 2)) LIMIT 5; + itemoffset | ctid | itemlen | key_data +------------+--------+---------+------------------------------------------------------------------------------------ + 1 | (1,10) | 40 | \x000001000a0028000000000000e064400000000000e064400000000000e064400000000000e06440 + 2 | (1,11) | 40 | \x000001000b0028000000000000006540000000000000654000000000000065400000000000006540 + 3 | (1,12) | 40 | \x000001000c0028000000000000206540000000000020654000000000002065400000000000206540 + 4 | (1,13) | 40 | \x000001000d0028000000000000406540000000000040654000000000004065400000000000406540 + 5 | (1,14) | 40 | \x000001000e0028000000000000606540000000000060654000000000006065400000000000606540 +(5 rows) + +DROP TABLE test_gist; diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c new file mode 100644 index 0000000000000..146b2e91b6011 --- /dev/null +++ b/contrib/pageinspect/gistfuncs.c @@ -0,0 +1,287 @@ +/* + * gistfuncs.c + * Functions to investigate the content of GiST indexes + * + * Copyright (c) 2014-2020, PostgreSQL Global Development Group + * + * IDENTIFICATION + * contrib/pageinspect/gistfuncs.c + */ +#include "postgres.h" + +#include "access/gist.h" +#include "access/gist_private.h" +#include "access/htup.h" +#include "access/relation.h" +#include "catalog/namespace.h" +#include "funcapi.h" +#include "miscadmin.h" +#include "pageinspect.h" +#include "storage/itemptr.h" +#include "utils/array.h" +#include "utils/builtins.h" +#include "utils/rel.h" +#include "utils/pg_lsn.h" +#include "utils/varlena.h" + +PG_FUNCTION_INFO_V1(gist_page_opaque_info); +PG_FUNCTION_INFO_V1(gist_page_items); +PG_FUNCTION_INFO_V1(gist_page_items_bytea); + +#define ItemPointerGetDatum(X) PointerGetDatum(X) + + +Datum +gist_page_opaque_info(PG_FUNCTION_ARGS) +{ + bytea *raw_page = PG_GETARG_BYTEA_P(0); + TupleDesc tupdesc; + Page page; + GISTPageOpaque opaq; + HeapTuple resultTuple; + Datum values[4]; + bool nulls[4]; + Datum flags[16]; + int nflags = 0; + uint16 flagbits; + + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to use raw page functions"))); + + page = get_page_from_raw(raw_page); + + opaq = (GISTPageOpaque) PageGetSpecialPointer(page); + + /* Build a tuple descriptor for our result type */ + if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + elog(ERROR, "return type must be a row type"); + + /* Convert the flags bitmask to an array of human-readable names */ + flagbits = opaq->flags; + if (flagbits & F_LEAF) + flags[nflags++] = CStringGetTextDatum("leaf"); + if (flagbits & F_DELETED) + flags[nflags++] = CStringGetTextDatum("deleted"); + if (flagbits & F_TUPLES_DELETED) + flags[nflags++] = CStringGetTextDatum("tuples_deleted"); + if (flagbits & F_FOLLOW_RIGHT) + flags[nflags++] = CStringGetTextDatum("follow_right"); + if (flagbits & F_HAS_GARBAGE) + flags[nflags++] = CStringGetTextDatum("has_garbage"); + flagbits &= ~(F_LEAF | F_DELETED | F_TUPLES_DELETED | F_FOLLOW_RIGHT | F_HAS_GARBAGE); + if (flagbits) + { + /* any flags we don't recognize are printed in hex */ + flags[nflags++] = DirectFunctionCall1(to_hex32, Int32GetDatum(flagbits)); + } + + memset(nulls, 0, sizeof(nulls)); + + values[0] = LSNGetDatum(PageGetLSN(page)); + values[1] = LSNGetDatum(GistPageGetNSN(page)); + values[2] = Int64GetDatum(opaq->rightlink); + values[3] = PointerGetDatum(construct_array(flags, nflags, + TEXTOID, + -1, false, TYPALIGN_INT)); + + /* Build and return the result tuple. */ + resultTuple = heap_form_tuple(tupdesc, values, nulls); + + return HeapTupleGetDatum(resultTuple); +} + +typedef struct gist_page_items_state +{ + Page page; + TupleDesc tupd; + OffsetNumber offset; + Relation rel; +} gist_page_items_state; + +Datum +gist_page_items_bytea(PG_FUNCTION_ARGS) +{ + bytea *raw_page = PG_GETARG_BYTEA_P(0); + FuncCallContext *fctx; + gist_page_items_state *inter_call_data; + + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to use raw page functions"))); + + if (SRF_IS_FIRSTCALL()) + { + TupleDesc tupdesc; + MemoryContext mctx; + Page page; + + fctx = SRF_FIRSTCALL_INIT(); + mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx); + + page = get_page_from_raw(raw_page); + + inter_call_data = palloc(sizeof(gist_page_items_state)); + + /* Build a tuple descriptor for our result type */ + if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + elog(ERROR, "return type must be a row type"); + + if (GistPageIsDeleted(page)) + elog(NOTICE, "page is deleted"); + + inter_call_data->page = page; + inter_call_data->tupd = tupdesc; + inter_call_data->offset = FirstOffsetNumber; + + fctx->max_calls = PageGetMaxOffsetNumber(page); + fctx->user_fctx = inter_call_data; + + MemoryContextSwitchTo(mctx); + } + + fctx = SRF_PERCALL_SETUP(); + inter_call_data = fctx->user_fctx; + + if (fctx->call_cntr < fctx->max_calls) + { + Page page = inter_call_data->page; + OffsetNumber offset = inter_call_data->offset; + HeapTuple resultTuple; + Datum result; + Datum values[4]; + bool nulls[4]; + ItemId id; + IndexTuple itup; + bytea *tuple_bytea; + int tuple_len; + + id = PageGetItemId(page, offset); + + if (!ItemIdIsValid(id)) + elog(ERROR, "invalid ItemId"); + + itup = (IndexTuple) PageGetItem(page, id); + tuple_len = IndexTupleSize(itup); + + memset(nulls, 0, sizeof(nulls)); + + values[0] = DatumGetInt16(offset); + values[1] = ItemPointerGetDatum(&itup->t_tid); + values[2] = Int32GetDatum((int) IndexTupleSize(itup)); + + tuple_bytea = (bytea *) palloc(tuple_len + VARHDRSZ); + SET_VARSIZE(tuple_bytea, tuple_len + VARHDRSZ); + memcpy(VARDATA(tuple_bytea), itup, tuple_len); + values[3] = PointerGetDatum(tuple_bytea); + + /* Build and return the result tuple. */ + resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls); + result = HeapTupleGetDatum(resultTuple); + + inter_call_data->offset++; + SRF_RETURN_NEXT(fctx, result); + } + + SRF_RETURN_DONE(fctx); +} + +Datum +gist_page_items(PG_FUNCTION_ARGS) +{ + bytea *raw_page = PG_GETARG_BYTEA_P(0); + Oid indexRelid = PG_GETARG_OID(1); + FuncCallContext *fctx; + gist_page_items_state *inter_call_data; + + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to use raw page functions"))); + + if (SRF_IS_FIRSTCALL()) + { + Relation indexRel; + TupleDesc tupdesc; + MemoryContext mctx; + Page page; + + fctx = SRF_FIRSTCALL_INIT(); + mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx); + + page = get_page_from_raw(raw_page); + + inter_call_data = palloc(sizeof(gist_page_items_state)); + + /* Open the relation */ + indexRel = index_open(indexRelid, AccessShareLock); + + /* Build a tuple descriptor for our result type */ + if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + elog(ERROR, "return type must be a row type"); + + if (GistPageIsDeleted(page)) + elog(NOTICE, "page is deleted"); + + inter_call_data->page = page; + inter_call_data->tupd = tupdesc; + inter_call_data->offset = FirstOffsetNumber; + inter_call_data->rel = indexRel; + + fctx->max_calls = PageGetMaxOffsetNumber(page); + fctx->user_fctx = inter_call_data; + + MemoryContextSwitchTo(mctx); + } + + fctx = SRF_PERCALL_SETUP(); + inter_call_data = fctx->user_fctx; + + if (fctx->call_cntr < fctx->max_calls) + { + Page page = inter_call_data->page; + OffsetNumber offset = inter_call_data->offset; + HeapTuple resultTuple; + Datum result; + Datum values[4]; + bool nulls[4]; + ItemId id; + IndexTuple itup; + Datum itup_values[INDEX_MAX_KEYS]; + bool itup_isnull[INDEX_MAX_KEYS]; + char *key_desc; + + id = PageGetItemId(page, offset); + + if (!ItemIdIsValid(id)) + elog(ERROR, "invalid ItemId"); + + itup = (IndexTuple) PageGetItem(page, id); + + index_deform_tuple(itup, RelationGetDescr(inter_call_data->rel), + itup_values, itup_isnull); + + key_desc = BuildIndexValueDescription(inter_call_data->rel, itup_values, + itup_isnull); + + memset(nulls, 0, sizeof(nulls)); + + values[0] = DatumGetInt16(offset); + values[1] = ItemPointerGetDatum(&itup->t_tid); + values[2] = Int32GetDatum((int) IndexTupleSize(itup)); + values[3] = CStringGetTextDatum(key_desc); + + /* Build and return the result tuple. */ + resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls); + result = HeapTupleGetDatum(resultTuple); + + inter_call_data->offset++; + SRF_RETURN_NEXT(fctx, result); + } + + relation_close(inter_call_data->rel, AccessShareLock); + + SRF_RETURN_DONE(fctx); +} diff --git a/contrib/pageinspect/pageinspect--1.8--1.9.sql b/contrib/pageinspect/pageinspect--1.8--1.9.sql new file mode 100644 index 0000000000000..9dc342fabc269 --- /dev/null +++ b/contrib/pageinspect/pageinspect--1.8--1.9.sql @@ -0,0 +1,41 @@ +/* contrib/pageinspect/pageinspect--1.8--1.9.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION pageinspect UPDATE TO '1.9'" to load this file. \quit + +-- +-- gist_page_opaque_info() +-- +CREATE FUNCTION gist_page_opaque_info(IN page bytea, + OUT lsn pg_lsn, + OUT nsn pg_lsn, + OUT rightlink bigint, + OUT flags text[]) +AS 'MODULE_PATHNAME', 'gist_page_opaque_info' +LANGUAGE C STRICT PARALLEL SAFE; + + +-- +-- gist_page_items_bytea() +-- +CREATE FUNCTION gist_page_items_bytea(IN page bytea, + OUT itemoffset smallint, + OUT ctid tid, + OUT itemlen smallint, + OUT key_data bytea) +RETURNS SETOF record +AS 'MODULE_PATHNAME', 'gist_page_items_bytea' +LANGUAGE C STRICT PARALLEL SAFE; + +-- +-- gist_page_items() +-- +CREATE FUNCTION gist_page_items(IN page bytea, + IN index_oid regclass, + OUT itemoffset smallint, + OUT ctid tid, + OUT itemlen smallint, + OUT keys text) +RETURNS SETOF record +AS 'MODULE_PATHNAME', 'gist_page_items' +LANGUAGE C STRICT PARALLEL SAFE; diff --git a/contrib/pageinspect/pageinspect.control b/contrib/pageinspect/pageinspect.control index f8cdf526c6515..bd716769a174c 100644 --- a/contrib/pageinspect/pageinspect.control +++ b/contrib/pageinspect/pageinspect.control @@ -1,5 +1,5 @@ # pageinspect extension comment = 'inspect the contents of database pages at a low level' -default_version = '1.8' +default_version = '1.9' module_pathname = '$libdir/pageinspect' relocatable = true diff --git a/contrib/pageinspect/sql/gist.sql b/contrib/pageinspect/sql/gist.sql new file mode 100644 index 0000000000000..b38da4cb033a9 --- /dev/null +++ b/contrib/pageinspect/sql/gist.sql @@ -0,0 +1,18 @@ +CREATE TABLE test_gist AS SELECT point(i,i) p, i::text t FROM + generate_series(1,1000) i; +CREATE INDEX test_gist_idx ON test_gist USING gist (p); + +-- Page 0 is the root, the rest are leaf pages +SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 0)); +SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 1)); +SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 2)); + +SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 0), 'test_gist_idx'); +SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 1), 'test_gist_idx') LIMIT 5; +SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 2), 'test_gist_idx') LIMIT 5; + +SELECT * FROM gist_page_items_bytea(get_raw_page('test_gist_idx', 0)); +SELECT * FROM gist_page_items_bytea(get_raw_page('test_gist_idx', 1)) LIMIT 5; +SELECT * FROM gist_page_items_bytea(get_raw_page('test_gist_idx', 2)) LIMIT 5; + +DROP TABLE test_gist; diff --git a/doc/src/sgml/pageinspect.sgml b/doc/src/sgml/pageinspect.sgml index 687c3606baf55..35858e1557604 100644 --- a/doc/src/sgml/pageinspect.sgml +++ b/doc/src/sgml/pageinspect.sgml @@ -671,6 +671,95 @@ test=# SELECT first_tid, nbytes, tids[0:5] AS some_tids + + GiST Functions + + + + + gist_page_opaque_info(page bytea) returns record + + gist_page_opaque_info + + + + + + gist_page_opaque_info returns information about + a GiST index opaque area, like the NSN, rightlink and + page type. + For example: + +test=# SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 2)); + lsn | nsn | rightlink | flags +-----+-----+-----------+-------- + 0/1 | 0/0 | 1 | {leaf} +(1 row) + + + + + + + + gist_page_items(page bytea, index oid) returns setof record + + gist_page_items + + + + + + gist_page_items returns information about + the data stored in a page of GiST index. For example: + +test=# SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 0), 'test_gist_idx'); + itemoffset | ctid | itemlen | keys +------------+-----------+---------+------------------- + 1 | (1,65535) | 40 | (p)=((166,166)) + 2 | (2,65535) | 40 | (p)=((332,332)) + 3 | (3,65535) | 40 | (p)=((498,498)) + 4 | (4,65535) | 40 | (p)=((664,664)) + 5 | (5,65535) | 40 | (p)=((830,830)) + 6 | (6,65535) | 40 | (p)=((996,996)) + 7 | (7,65535) | 40 | (p)=((1000,1000)) +(7 rows) + + + + + + + + gist_page_items_bytea(page bytea) returns setof record + + gist_page_items_bytea + + + + + + Same as gist_page_items, but returns the key data as a raw + bytea blob. For example: + +test=# SELECT * FROM gist_page_items_bytea(get_raw_page('test_gist_idx', 0)); + itemoffset | ctid | itemlen | key_data +------------+-----------+---------+------------------------------------------------------------------------------------ + 1 | (1,65535) | 40 | \x00000100ffff28000000000000c064400000000000c06440000000000000f03f000000000000f03f + 2 | (2,65535) | 40 | \x00000200ffff28000000000000c074400000000000c074400000000000e064400000000000e06440 + 3 | (3,65535) | 40 | \x00000300ffff28000000000000207f400000000000207f400000000000d074400000000000d07440 + 4 | (4,65535) | 40 | \x00000400ffff28000000000000c084400000000000c084400000000000307f400000000000307f40 + 5 | (5,65535) | 40 | \x00000500ffff28000000000000f089400000000000f089400000000000c884400000000000c88440 + 6 | (6,65535) | 40 | \x00000600ffff28000000000000208f400000000000208f400000000000f889400000000000f88940 + 7 | (7,65535) | 40 | \x00000700ffff28000000000000408f400000000000408f400000000000288f400000000000288f40 +(7 rows) + + + + + + + Hash Functions From e6eeb8d799c703eb829612ddcb4fd5ba82d3e880 Mon Sep 17 00:00:00 2001 From: Magnus Hagander Date: Wed, 13 Jan 2021 11:07:37 +0100 Subject: [PATCH 086/240] Remove incorrect markup Seems 737d69ffc3c made a copy/paste or automation error resulting in two extra right-parenthesis. Reported-By: Michael Vastola Backpatch-through: 13 Discussion: https://postgr.es/m/161051035421.12224.1741822783166533529@wrigleys.postgresql.org --- doc/src/sgml/func.sgml | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 02a37658ad9a2..fd0370a1b438b 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -3262,7 +3262,6 @@ repeat('Pg', 4) PgPgPgPg right ( string text, n integer ) - ) text @@ -3284,7 +3283,6 @@ repeat('Pg', 4) PgPgPgPg rpad ( string text, length integer , fill text ) - ) text From 6ecaaf810b8b9e3132f00549e630400f38a7ca37 Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Wed, 13 Jan 2021 12:32:54 +0200 Subject: [PATCH 087/240] Fix portability issues in the new gist pageinspect test. 1. The raw bytea representation of the point-type keys used in the test depends on endianess. Remove the raw key_data column from the test. 2. The items stored on non-leftmost gist page depends on how many items git on the other pages. This showed up as a failure on 32-bit i386 systems. To fix, only test the gist_page_items() function on the leftmost leaf page. Per Andrey Borodin and the buildfarm. Discussion: https://www.postgresql.org/message-id/9FCEC1DC-86FB-4A57-88EF-DD13663B36AF%40yandex-team.ru --- contrib/pageinspect/expected/gist.out | 52 +++++++-------------------- contrib/pageinspect/sql/gist.sql | 7 ++-- 2 files changed, 15 insertions(+), 44 deletions(-) diff --git a/contrib/pageinspect/expected/gist.out b/contrib/pageinspect/expected/gist.out index 89294b5a17d72..508f5adb550b5 100644 --- a/contrib/pageinspect/expected/gist.out +++ b/contrib/pageinspect/expected/gist.out @@ -42,46 +42,18 @@ SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 1), 'test_gist_idx') 5 | (0,5) | 40 | (p)=((5,5)) (5 rows) -SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 2), 'test_gist_idx') LIMIT 5; - itemoffset | ctid | itemlen | keys -------------+--------+---------+----------------- - 1 | (1,10) | 40 | (p)=((167,167)) - 2 | (1,11) | 40 | (p)=((168,168)) - 3 | (1,12) | 40 | (p)=((169,169)) - 4 | (1,13) | 40 | (p)=((170,170)) - 5 | (1,14) | 40 | (p)=((171,171)) -(5 rows) - -SELECT * FROM gist_page_items_bytea(get_raw_page('test_gist_idx', 0)); - itemoffset | ctid | itemlen | key_data -------------+-----------+---------+------------------------------------------------------------------------------------ - 1 | (1,65535) | 40 | \x00000100ffff28000000000000c064400000000000c06440000000000000f03f000000000000f03f - 2 | (2,65535) | 40 | \x00000200ffff28000000000000c074400000000000c074400000000000e064400000000000e06440 - 3 | (3,65535) | 40 | \x00000300ffff28000000000000207f400000000000207f400000000000d074400000000000d07440 - 4 | (4,65535) | 40 | \x00000400ffff28000000000000c084400000000000c084400000000000307f400000000000307f40 - 5 | (5,65535) | 40 | \x00000500ffff28000000000000f089400000000000f089400000000000c884400000000000c88440 - 6 | (6,65535) | 40 | \x00000600ffff28000000000000208f400000000000208f400000000000f889400000000000f88940 - 7 | (7,65535) | 40 | \x00000700ffff28000000000000408f400000000000408f400000000000288f400000000000288f40 +-- gist_page_items_bytea prints the raw key data as a bytea. The output of that is +-- platform-dependent (endianess), so omit the actual key data from the output. +SELECT itemoffset, ctid, itemlen FROM gist_page_items_bytea(get_raw_page('test_gist_idx', 0)); + itemoffset | ctid | itemlen +------------+-----------+--------- + 1 | (1,65535) | 40 + 2 | (2,65535) | 40 + 3 | (3,65535) | 40 + 4 | (4,65535) | 40 + 5 | (5,65535) | 40 + 6 | (6,65535) | 40 + 7 | (7,65535) | 40 (7 rows) -SELECT * FROM gist_page_items_bytea(get_raw_page('test_gist_idx', 1)) LIMIT 5; - itemoffset | ctid | itemlen | key_data -------------+-------+---------+------------------------------------------------------------------------------------ - 1 | (0,1) | 40 | \x0000000001002800000000000000f03f000000000000f03f000000000000f03f000000000000f03f - 2 | (0,2) | 40 | \x00000000020028000000000000000040000000000000004000000000000000400000000000000040 - 3 | (0,3) | 40 | \x00000000030028000000000000000840000000000000084000000000000008400000000000000840 - 4 | (0,4) | 40 | \x00000000040028000000000000001040000000000000104000000000000010400000000000001040 - 5 | (0,5) | 40 | \x00000000050028000000000000001440000000000000144000000000000014400000000000001440 -(5 rows) - -SELECT * FROM gist_page_items_bytea(get_raw_page('test_gist_idx', 2)) LIMIT 5; - itemoffset | ctid | itemlen | key_data -------------+--------+---------+------------------------------------------------------------------------------------ - 1 | (1,10) | 40 | \x000001000a0028000000000000e064400000000000e064400000000000e064400000000000e06440 - 2 | (1,11) | 40 | \x000001000b0028000000000000006540000000000000654000000000000065400000000000006540 - 3 | (1,12) | 40 | \x000001000c0028000000000000206540000000000020654000000000002065400000000000206540 - 4 | (1,13) | 40 | \x000001000d0028000000000000406540000000000040654000000000004065400000000000406540 - 5 | (1,14) | 40 | \x000001000e0028000000000000606540000000000060654000000000006065400000000000606540 -(5 rows) - DROP TABLE test_gist; diff --git a/contrib/pageinspect/sql/gist.sql b/contrib/pageinspect/sql/gist.sql index b38da4cb033a9..e6f6e42a5ef54 100644 --- a/contrib/pageinspect/sql/gist.sql +++ b/contrib/pageinspect/sql/gist.sql @@ -9,10 +9,9 @@ SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 2)); SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 0), 'test_gist_idx'); SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 1), 'test_gist_idx') LIMIT 5; -SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 2), 'test_gist_idx') LIMIT 5; -SELECT * FROM gist_page_items_bytea(get_raw_page('test_gist_idx', 0)); -SELECT * FROM gist_page_items_bytea(get_raw_page('test_gist_idx', 1)) LIMIT 5; -SELECT * FROM gist_page_items_bytea(get_raw_page('test_gist_idx', 2)) LIMIT 5; +-- gist_page_items_bytea prints the raw key data as a bytea. The output of that is +-- platform-dependent (endianess), so omit the actual key data from the output. +SELECT itemoffset, ctid, itemlen FROM gist_page_items_bytea(get_raw_page('test_gist_idx', 0)); DROP TABLE test_gist; From 39b03690b529935a3c33024ee68f08e2d347cf4f Mon Sep 17 00:00:00 2001 From: Fujii Masao Date: Wed, 13 Jan 2021 22:59:17 +0900 Subject: [PATCH 088/240] Log long wait time on recovery conflict when it's resolved. This is a follow-up of the work done in commit 0650ff2303. This commit extends log_recovery_conflict_waits so that a log message is produced also when recovery conflict has already been resolved after deadlock_timeout passes, i.e., when the startup process finishes waiting for recovery conflict after deadlock_timeout. This is useful in investigating how long recovery conflicts prevented the recovery from applying WAL. Author: Fujii Masao Reviewed-by: Kyotaro Horiguchi, Bertrand Drouvot Discussion: https://postgr.es/m/9a60178c-a853-1440-2cdc-c3af916cff59@amazon.com --- doc/src/sgml/config.sgml | 2 +- src/backend/storage/buffer/bufmgr.c | 12 +++++++- src/backend/storage/ipc/standby.c | 47 ++++++++++++++++++++++------- src/backend/storage/lmgr/proc.c | 12 +++++++- src/include/storage/standby.h | 3 +- 5 files changed, 61 insertions(+), 15 deletions(-) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 7c0a673a8dd42..82864bbb247f5 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -6961,7 +6961,7 @@ log_line_prefix = '%m [%p] %q%u@%d/%a ' Controls whether a log message is produced when the startup process - is waiting longer than deadlock_timeout + waits longer than deadlock_timeout for recovery conflicts. This is useful in determining if recovery conflicts prevent the recovery from applying WAL. diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index c46b8abad12e4..561c212092f76 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -4034,6 +4034,16 @@ LockBufferForCleanup(Buffer buffer) /* Successfully acquired exclusive lock with pincount 1 */ UnlockBufHdr(bufHdr, buf_state); + /* + * Emit the log message if recovery conflict on buffer pin was + * resolved but the startup process waited longer than + * deadlock_timeout for it. + */ + if (logged_recovery_conflict) + LogRecoveryConflict(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN, + waitStart, GetCurrentTimestamp(), + NULL, false); + /* Report change to non-waiting status */ if (new_status) { @@ -4088,7 +4098,7 @@ LockBufferForCleanup(Buffer buffer) DeadlockTimeout)) { LogRecoveryConflict(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN, - waitStart, now, NULL); + waitStart, now, NULL, true); logged_recovery_conflict = true; } } diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c index d4b0f65ba20ba..39a30c00f7a36 100644 --- a/src/backend/storage/ipc/standby.c +++ b/src/backend/storage/ipc/standby.c @@ -226,11 +226,14 @@ WaitExceedsMaxStandbyDelay(uint32 wait_event_info) * wait_start is the timestamp when the caller started to wait. * now is the timestamp when this function has been called. * wait_list is the list of virtual transaction ids assigned to - * conflicting processes. + * conflicting processes. still_waiting indicates whether + * the startup process is still waiting for the recovery conflict + * to be resolved or not. */ void LogRecoveryConflict(ProcSignalReason reason, TimestampTz wait_start, - TimestampTz now, VirtualTransactionId *wait_list) + TimestampTz now, VirtualTransactionId *wait_list, + bool still_waiting) { long secs; int usecs; @@ -238,6 +241,12 @@ LogRecoveryConflict(ProcSignalReason reason, TimestampTz wait_start, StringInfoData buf; int nprocs = 0; + /* + * There must be no conflicting processes when the recovery conflict has + * already been resolved. + */ + Assert(still_waiting || wait_list == NULL); + TimestampDifference(wait_start, now, &secs, &usecs); msecs = secs * 1000 + usecs / 1000; usecs = usecs % 1000; @@ -275,12 +284,21 @@ LogRecoveryConflict(ProcSignalReason reason, TimestampTz wait_start, * conflicting backends in a detail message. Note that if all the backends * in the list are not active, no detail message is logged. */ - ereport(LOG, - errmsg("recovery still waiting after %ld.%03d ms: %s", - msecs, usecs, _(get_recovery_conflict_desc(reason))), - nprocs > 0 ? errdetail_log_plural("Conflicting process: %s.", - "Conflicting processes: %s.", - nprocs, buf.data) : 0); + if (still_waiting) + { + ereport(LOG, + errmsg("recovery still waiting after %ld.%03d ms: %s", + msecs, usecs, _(get_recovery_conflict_desc(reason))), + nprocs > 0 ? errdetail_log_plural("Conflicting process: %s.", + "Conflicting processes: %s.", + nprocs, buf.data) : 0); + } + else + { + ereport(LOG, + errmsg("recovery finished waiting after %ld.%03d ms: %s", + msecs, usecs, _(get_recovery_conflict_desc(reason)))); + } if (nprocs > 0) pfree(buf.data); @@ -375,13 +393,12 @@ ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, /* * Emit the log message if the startup process is waiting - * longer than deadlock_timeout for recovery conflict on - * buffer pin. + * longer than deadlock_timeout for recovery conflict. */ if (maybe_log_conflict && TimestampDifferenceExceeds(waitStart, now, DeadlockTimeout)) { - LogRecoveryConflict(reason, waitStart, now, waitlist); + LogRecoveryConflict(reason, waitStart, now, waitlist, true); logged_recovery_conflict = true; } } @@ -391,6 +408,14 @@ ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, waitlist++; } + /* + * Emit the log message if recovery conflict was resolved but the startup + * process waited longer than deadlock_timeout for it. + */ + if (logged_recovery_conflict) + LogRecoveryConflict(reason, waitStart, GetCurrentTimestamp(), + NULL, false); + /* Reset ps display if we changed it */ if (new_status) { diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index db0cfaa360031..c87ffc654919a 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -1322,7 +1322,8 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable) * longer than deadlock_timeout. */ LogRecoveryConflict(PROCSIG_RECOVERY_CONFLICT_LOCK, - standbyWaitStart, now, cnt > 0 ? vxids : NULL); + standbyWaitStart, now, + cnt > 0 ? vxids : NULL, true); logged_recovery_conflict = true; } } @@ -1607,6 +1608,15 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable) disable_timeout(DEADLOCK_TIMEOUT, false); } + /* + * Emit the log message if recovery conflict on lock was resolved but the + * startup process waited longer than deadlock_timeout for it. + */ + if (InHotStandby && logged_recovery_conflict) + LogRecoveryConflict(PROCSIG_RECOVERY_CONFLICT_LOCK, + standbyWaitStart, GetCurrentTimestamp(), + NULL, false); + /* * Re-acquire the lock table's partition lock. We have to do this to hold * off cancel/die interrupts before we can mess with lockAwaited (else we diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h index a0f3e0bdf09e1..2b1f340b82b8c 100644 --- a/src/include/storage/standby.h +++ b/src/include/storage/standby.h @@ -40,7 +40,8 @@ extern void StandbyDeadLockHandler(void); extern void StandbyTimeoutHandler(void); extern void StandbyLockTimeoutHandler(void); extern void LogRecoveryConflict(ProcSignalReason reason, TimestampTz wait_start, - TimestampTz cur_ts, VirtualTransactionId *wait_list); + TimestampTz cur_ts, VirtualTransactionId *wait_list, + bool still_waiting); /* * Standby Rmgr (RM_STANDBY_ID) From 9dc718bdf2b1a574481a45624d42b674332e2903 Mon Sep 17 00:00:00 2001 From: Peter Geoghegan Date: Wed, 13 Jan 2021 08:11:00 -0800 Subject: [PATCH 089/240] Pass down "logically unchanged index" hint. Add an executor aminsert() hint mechanism that informs index AMs that the incoming index tuple (the tuple that accompanies the hint) is not being inserted by execution of an SQL statement that logically modifies any of the index's key columns. The hint is received by indexes when an UPDATE takes place that does not apply an optimization like heapam's HOT (though only for indexes where all key columns are logically unchanged). Any index tuple that receives the hint on insert is expected to be a duplicate of at least one existing older version that is needed for the same logical row. Related versions will typically be stored on the same index page, at least within index AMs that apply the hint. Recognizing the difference between MVCC version churn duplicates and true logical row duplicates at the index AM level can help with cleanup of garbage index tuples. Cleanup can intelligently target tuples that are likely to be garbage, without wasting too many cycles on less promising tuples/pages (index pages with little or no version churn). This is infrastructure for an upcoming commit that will teach nbtree to perform bottom-up index deletion. No index AM actually applies the hint just yet. Author: Peter Geoghegan Reviewed-By: Victor Yegorov Discussion: https://postgr.es/m/CAH2-Wz=CEKFa74EScx_hFVshCOn6AA5T-ajFASTdzipdkLTNQQ@mail.gmail.com --- contrib/bloom/blinsert.c | 1 + contrib/bloom/bloom.h | 1 + doc/src/sgml/indexam.sgml | 15 ++ src/backend/access/brin/brin.c | 1 + src/backend/access/common/toast_internals.c | 2 +- src/backend/access/gin/gininsert.c | 1 + src/backend/access/gist/gist.c | 1 + src/backend/access/hash/hash.c | 1 + src/backend/access/heap/heapam_handler.c | 1 + src/backend/access/index/indexam.c | 4 +- src/backend/access/nbtree/nbtree.c | 1 + src/backend/access/spgist/spginsert.c | 1 + src/backend/catalog/indexing.c | 1 + src/backend/commands/constraint.c | 2 +- src/backend/commands/copyfrom.c | 5 +- src/backend/commands/trigger.c | 6 +- src/backend/executor/execIndexing.c | 160 +++++++++++++++++- src/backend/executor/execMain.c | 8 +- src/backend/executor/execReplication.c | 8 +- src/backend/executor/nodeModifyTable.c | 6 +- src/backend/replication/logical/worker.c | 3 +- src/include/access/amapi.h | 1 + src/include/access/brin_internal.h | 1 + src/include/access/genam.h | 1 + src/include/access/gin_private.h | 1 + src/include/access/gist_private.h | 1 + src/include/access/hash.h | 1 + src/include/access/nbtree.h | 1 + src/include/access/spgist.h | 1 + src/include/executor/executor.h | 1 + .../modules/dummy_index_am/dummy_index_am.c | 1 + 31 files changed, 214 insertions(+), 25 deletions(-) diff --git a/contrib/bloom/blinsert.c b/contrib/bloom/blinsert.c index 32b5d62e1f34c..d37ceef753ab0 100644 --- a/contrib/bloom/blinsert.c +++ b/contrib/bloom/blinsert.c @@ -198,6 +198,7 @@ bool blinsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, + bool indexUnchanged, IndexInfo *indexInfo) { BloomState blstate; diff --git a/contrib/bloom/bloom.h b/contrib/bloom/bloom.h index 436bd43209245..a22a6dfa40400 100644 --- a/contrib/bloom/bloom.h +++ b/contrib/bloom/bloom.h @@ -192,6 +192,7 @@ extern bool blvalidate(Oid opclassoid); extern bool blinsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, + bool indexUnchanged, struct IndexInfo *indexInfo); extern IndexScanDesc blbeginscan(Relation r, int nkeys, int norderbys); extern int64 blgetbitmap(IndexScanDesc scan, TIDBitmap *tbm); diff --git a/doc/src/sgml/indexam.sgml b/doc/src/sgml/indexam.sgml index f00268d5b51f2..ec5741df6d164 100644 --- a/doc/src/sgml/indexam.sgml +++ b/doc/src/sgml/indexam.sgml @@ -293,6 +293,7 @@ aminsert (Relation indexRelation, ItemPointer heap_tid, Relation heapRelation, IndexUniqueCheck checkUnique, + bool indexUnchanged, IndexInfo *indexInfo); Insert a new tuple into an existing index. The values and @@ -308,6 +309,20 @@ aminsert (Relation indexRelation, look into the heap to verify tuple liveness). + + The indexUnchanged boolean value gives a hint + about the nature of the tuple to be indexed. When it is true, + the tuple is a duplicate of some existing tuple in the index. The + new tuple is a logically unchanged successor MVCC tuple version. This + happens when an UPDATE takes place that does not + modify any columns covered by the index, but nevertheless requires a + new version in the index. The index AM may use this hint to decide + to apply bottom-up index deletion in parts of the index where many + versions of the same logical row accumulate. Note that updating a + non-key column does not affect the value of + indexUnchanged. + + The function's Boolean result value is significant only when checkUnique is UNIQUE_CHECK_PARTIAL. diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 58fe109d2d9c5..27ba596c6e47d 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -151,6 +151,7 @@ bool brininsert(Relation idxRel, Datum *values, bool *nulls, ItemPointer heaptid, Relation heapRel, IndexUniqueCheck checkUnique, + bool indexUnchanged, IndexInfo *indexInfo) { BlockNumber pagesPerRange; diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c index 70a9f771884fb..9b9da0f41bcd7 100644 --- a/src/backend/access/common/toast_internals.c +++ b/src/backend/access/common/toast_internals.c @@ -328,7 +328,7 @@ toast_save_datum(Relation rel, Datum value, toastrel, toastidxs[i]->rd_index->indisunique ? UNIQUE_CHECK_YES : UNIQUE_CHECK_NO, - NULL); + false, NULL); } /* diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c index 29546ce0ae48d..0e8672c9e90cc 100644 --- a/src/backend/access/gin/gininsert.c +++ b/src/backend/access/gin/gininsert.c @@ -488,6 +488,7 @@ bool gininsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, + bool indexUnchanged, IndexInfo *indexInfo) { GinState *ginstate = (GinState *) indexInfo->ii_AmCache; diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index e4b251a58fb57..992936cfa8eac 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -156,6 +156,7 @@ bool gistinsert(Relation r, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, + bool indexUnchanged, IndexInfo *indexInfo) { GISTSTATE *giststate = (GISTSTATE *) indexInfo->ii_AmCache; diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c index 263ae23ab0ad9..0752fb38a9248 100644 --- a/src/backend/access/hash/hash.c +++ b/src/backend/access/hash/hash.c @@ -247,6 +247,7 @@ bool hashinsert(Relation rel, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, + bool indexUnchanged, IndexInfo *indexInfo) { Datum index_values[1]; diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c index 10ddde4ecf949..ac4a3be458739 100644 --- a/src/backend/access/heap/heapam_handler.c +++ b/src/backend/access/heap/heapam_handler.c @@ -1956,6 +1956,7 @@ heapam_index_validate_scan(Relation heapRelation, heapRelation, indexInfo->ii_Unique ? UNIQUE_CHECK_YES : UNIQUE_CHECK_NO, + false, indexInfo); state->tups_inserted += 1; diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c index c2b98e8a727d1..3d2dbed708309 100644 --- a/src/backend/access/index/indexam.c +++ b/src/backend/access/index/indexam.c @@ -179,6 +179,7 @@ index_insert(Relation indexRelation, ItemPointer heap_t_ctid, Relation heapRelation, IndexUniqueCheck checkUnique, + bool indexUnchanged, IndexInfo *indexInfo) { RELATION_CHECKS; @@ -191,7 +192,8 @@ index_insert(Relation indexRelation, return indexRelation->rd_indam->aminsert(indexRelation, values, isnull, heap_t_ctid, heapRelation, - checkUnique, indexInfo); + checkUnique, indexUnchanged, + indexInfo); } /* diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index ba79a7f3e9e2c..c50c4e8434ba6 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -199,6 +199,7 @@ bool btinsert(Relation rel, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, + bool indexUnchanged, IndexInfo *indexInfo) { bool result; diff --git a/src/backend/access/spgist/spginsert.c b/src/backend/access/spgist/spginsert.c index 2e1d8a33d1f7d..0ca621450e647 100644 --- a/src/backend/access/spgist/spginsert.c +++ b/src/backend/access/spgist/spginsert.c @@ -207,6 +207,7 @@ bool spginsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, + bool indexUnchanged, IndexInfo *indexInfo) { SpGistState spgstate; diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c index 8701653eb6162..284ceaa6b9c00 100644 --- a/src/backend/catalog/indexing.c +++ b/src/backend/catalog/indexing.c @@ -162,6 +162,7 @@ CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple) heapRelation, index->rd_index->indisunique ? UNIQUE_CHECK_YES : UNIQUE_CHECK_NO, + false, indexInfo); } diff --git a/src/backend/commands/constraint.c b/src/backend/commands/constraint.c index c2394d2232e6d..d0063164a7e4e 100644 --- a/src/backend/commands/constraint.c +++ b/src/backend/commands/constraint.c @@ -175,7 +175,7 @@ unique_key_recheck(PG_FUNCTION_ARGS) */ index_insert(indexRel, values, isnull, &checktid, trigdata->tg_relation, UNIQUE_CHECK_EXISTING, - indexInfo); + false, indexInfo); } else { diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c index 08b6f782c7358..c39cc736ed2bc 100644 --- a/src/backend/commands/copyfrom.c +++ b/src/backend/commands/copyfrom.c @@ -342,8 +342,8 @@ CopyMultiInsertBufferFlush(CopyMultiInsertInfo *miinfo, cstate->cur_lineno = buffer->linenos[i]; recheckIndexes = ExecInsertIndexTuples(resultRelInfo, - buffer->slots[i], estate, false, NULL, - NIL); + buffer->slots[i], estate, false, false, + NULL, NIL); ExecARInsertTriggers(estate, resultRelInfo, slots[i], recheckIndexes, cstate->transition_capture); @@ -1087,6 +1087,7 @@ CopyFrom(CopyFromState cstate) myslot, estate, false, + false, NULL, NIL); } diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 12229364f1e92..3e7086c5e5295 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -71,10 +71,8 @@ int SessionReplicationRole = SESSION_REPLICATION_ROLE_ORIGIN; static int MyTriggerDepth = 0; /* - * Note that similar macros also exist in executor/execMain.c. There does not - * appear to be any good header to put them into, given the structures that - * they use, so we let them be duplicated. Be sure to update all if one needs - * to be changed, however. + * The authoritative version of this macro is in executor/execMain.c. Be sure + * to keep everything in sync. */ #define GetAllUpdatedColumns(relinfo, estate) \ (bms_union(exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->updatedCols, \ diff --git a/src/backend/executor/execIndexing.c b/src/backend/executor/execIndexing.c index 2aafcc8f2298b..1f0fe145ce8eb 100644 --- a/src/backend/executor/execIndexing.c +++ b/src/backend/executor/execIndexing.c @@ -124,6 +124,15 @@ typedef enum CEOUC_LIVELOCK_PREVENTING_WAIT } CEOUC_WAIT_MODE; +/* + * The authoritative version of these macro are in executor/execMain.c. Be + * sure to keep everything in sync. + */ +#define GetUpdatedColumns(relinfo, estate) \ + (exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->updatedCols) +#define GetExtraUpdatedColumns(relinfo, estate) \ + (exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->extraUpdatedCols) + static bool check_exclusion_or_unique_constraint(Relation heap, Relation index, IndexInfo *indexInfo, ItemPointer tupleid, @@ -136,6 +145,11 @@ static bool check_exclusion_or_unique_constraint(Relation heap, Relation index, static bool index_recheck_constraint(Relation index, Oid *constr_procs, Datum *existing_values, bool *existing_isnull, Datum *new_values); +static bool index_unchanged_by_update(ResultRelInfo *resultRelInfo, + EState *estate, IndexInfo *indexInfo, + Relation indexRelation); +static bool index_expression_changed_walker(Node *node, + Bitmapset *allUpdatedCols); /* ---------------------------------------------------------------- * ExecOpenIndices @@ -254,6 +268,16 @@ ExecCloseIndices(ResultRelInfo *resultRelInfo) * into all the relations indexing the result relation * when a heap tuple is inserted into the result relation. * + * When 'update' is true, executor is performing an UPDATE + * that could not use an optimization like heapam's HOT (in + * more general terms a call to table_tuple_update() took + * place and set 'update_indexes' to true). Receiving this + * hint makes us consider if we should pass down the + * 'indexUnchanged' hint in turn. That's something that we + * figure out for each index_insert() call iff 'update' is + * true. (When 'update' is false we already know not to pass + * the hint to any index.) + * * Unique and exclusion constraints are enforced at the same * time. This returns a list of index OIDs for any unique or * exclusion constraints that are deferred and that had @@ -263,16 +287,13 @@ ExecCloseIndices(ResultRelInfo *resultRelInfo) * * If 'arbiterIndexes' is nonempty, noDupErr applies only to * those indexes. NIL means noDupErr applies to all indexes. - * - * CAUTION: this must not be called for a HOT update. - * We can't defend against that here for lack of info. - * Should we change the API to make it safer? * ---------------------------------------------------------------- */ List * ExecInsertIndexTuples(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, + bool update, bool noDupErr, bool *specConflict, List *arbiterIndexes) @@ -319,6 +340,7 @@ ExecInsertIndexTuples(ResultRelInfo *resultRelInfo, IndexInfo *indexInfo; bool applyNoDupErr; IndexUniqueCheck checkUnique; + bool indexUnchanged; bool satisfiesConstraint; if (indexRelation == NULL) @@ -389,6 +411,16 @@ ExecInsertIndexTuples(ResultRelInfo *resultRelInfo, else checkUnique = UNIQUE_CHECK_PARTIAL; + /* + * There's definitely going to be an index_insert() call for this + * index. If we're being called as part of an UPDATE statement, + * consider if the 'indexUnchanged' = true hint should be passed. + */ + indexUnchanged = update && index_unchanged_by_update(resultRelInfo, + estate, + indexInfo, + indexRelation); + satisfiesConstraint = index_insert(indexRelation, /* index relation */ values, /* array of index Datums */ @@ -396,6 +428,7 @@ ExecInsertIndexTuples(ResultRelInfo *resultRelInfo, tupleid, /* tid of heap tuple */ heapRelation, /* heap relation */ checkUnique, /* type of uniqueness check to do */ + indexUnchanged, /* UPDATE without logical change? */ indexInfo); /* index AM may need this */ /* @@ -899,3 +932,122 @@ index_recheck_constraint(Relation index, Oid *constr_procs, return true; } + +/* + * Check if ExecInsertIndexTuples() should pass indexUnchanged hint. + * + * When the executor performs an UPDATE that requires a new round of index + * tuples, determine if we should pass 'indexUnchanged' = true hint for one + * single index. + */ +static bool +index_unchanged_by_update(ResultRelInfo *resultRelInfo, EState *estate, + IndexInfo *indexInfo, Relation indexRelation) +{ + Bitmapset *updatedCols = GetUpdatedColumns(resultRelInfo, estate); + Bitmapset *extraUpdatedCols = GetExtraUpdatedColumns(resultRelInfo, estate); + Bitmapset *allUpdatedCols; + bool hasexpression = false; + List *idxExprs; + + /* + * Check for indexed attribute overlap with updated columns. + * + * Only do this for key columns. A change to a non-key column within an + * INCLUDE index should not be counted here. Non-key column values are + * opaque payload state to the index AM, a little like an extra table TID. + */ + for (int attr = 0; attr < indexInfo->ii_NumIndexKeyAttrs; attr++) + { + int keycol = indexInfo->ii_IndexAttrNumbers[attr]; + + if (keycol <= 0) + { + /* + * Skip expressions for now, but remember to deal with them later + * on + */ + hasexpression = true; + continue; + } + + if (bms_is_member(keycol - FirstLowInvalidHeapAttributeNumber, + updatedCols) || + bms_is_member(keycol - FirstLowInvalidHeapAttributeNumber, + extraUpdatedCols)) + { + /* Changed key column -- don't hint for this index */ + return false; + } + } + + /* + * When we get this far and index has no expressions, return true so that + * index_insert() call will go on to pass 'indexUnchanged' = true hint. + * + * The _absence_ of an indexed key attribute that overlaps with updated + * attributes (in addition to the total absence of indexed expressions) + * shows that the index as a whole is logically unchanged by UPDATE. + */ + if (!hasexpression) + return true; + + /* + * Need to pass only one bms to expression_tree_walker helper function. + * Avoid allocating memory in common case where there are no extra cols. + */ + if (!extraUpdatedCols) + allUpdatedCols = updatedCols; + else + allUpdatedCols = bms_union(updatedCols, extraUpdatedCols); + + /* + * We have to work slightly harder in the event of indexed expressions, + * but the principle is the same as before: try to find columns (Vars, + * actually) that overlap with known-updated columns. + * + * If we find any matching Vars, don't pass hint for index. Otherwise + * pass hint. + */ + idxExprs = RelationGetIndexExpressions(indexRelation); + hasexpression = index_expression_changed_walker((Node *) idxExprs, + allUpdatedCols); + list_free(idxExprs); + if (extraUpdatedCols) + bms_free(allUpdatedCols); + + if (hasexpression) + return false; + + return true; +} + +/* + * Indexed expression helper for index_unchanged_by_update(). + * + * Returns true when Var that appears within allUpdatedCols located. + */ +static bool +index_expression_changed_walker(Node *node, Bitmapset *allUpdatedCols) +{ + if (node == NULL) + return false; + + if (IsA(node, Var)) + { + Var *var = (Var *) node; + + if (bms_is_member(var->varattno - FirstLowInvalidHeapAttributeNumber, + allUpdatedCols)) + { + /* Var was updated -- indicates that we should not hint */ + return true; + } + + /* Still haven't found a reason to not pass the hint */ + return false; + } + + return expression_tree_walker(node, index_expression_changed_walker, + (void *) allUpdatedCols); +} diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index b4e25df601bd2..f4dd47acc76ac 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -101,10 +101,10 @@ static char *ExecBuildSlotValueDescription(Oid reloid, static void EvalPlanQualStart(EPQState *epqstate, Plan *planTree); /* - * Note that GetAllUpdatedColumns() also exists in commands/trigger.c. There does - * not appear to be any good header to put it into, given the structures that - * it uses, so we let them be duplicated. Be sure to update both if one needs - * to be changed, however. + * Note that variants of these macros exists in commands/trigger.c and in + * execIndexing.c. There does not appear to be any good header to put it + * into, given the structures that it uses, so we let them be duplicated. Be + * sure to keep everything in sync. */ #define GetInsertedColumns(relinfo, estate) \ (exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->insertedCols) diff --git a/src/backend/executor/execReplication.c b/src/backend/executor/execReplication.c index 12f6e5c6778fa..1e285e0349f46 100644 --- a/src/backend/executor/execReplication.c +++ b/src/backend/executor/execReplication.c @@ -444,8 +444,8 @@ ExecSimpleRelationInsert(ResultRelInfo *resultRelInfo, if (resultRelInfo->ri_NumIndices > 0) recheckIndexes = ExecInsertIndexTuples(resultRelInfo, - slot, estate, false, NULL, - NIL); + slot, estate, false, false, + NULL, NIL); /* AFTER ROW INSERT Triggers */ ExecARInsertTriggers(estate, resultRelInfo, slot, @@ -512,8 +512,8 @@ ExecSimpleRelationUpdate(ResultRelInfo *resultRelInfo, if (resultRelInfo->ri_NumIndices > 0 && update_indexes) recheckIndexes = ExecInsertIndexTuples(resultRelInfo, - slot, estate, false, NULL, - NIL); + slot, estate, true, false, + NULL, NIL); /* AFTER ROW UPDATE Triggers */ ExecARUpdateTriggers(estate, resultRelInfo, diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index d7b8f6559196f..921e6954194ea 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -599,7 +599,7 @@ ExecInsert(ModifyTableState *mtstate, /* insert index entries for tuple */ recheckIndexes = ExecInsertIndexTuples(resultRelInfo, - slot, estate, true, + slot, estate, false, true, &specConflict, arbiterIndexes); @@ -640,7 +640,7 @@ ExecInsert(ModifyTableState *mtstate, if (resultRelInfo->ri_NumIndices > 0) recheckIndexes = ExecInsertIndexTuples(resultRelInfo, slot, estate, false, - NULL, NIL); + false, NULL, NIL); } } @@ -1511,7 +1511,7 @@ lreplace:; /* insert index entries for tuple if necessary */ if (resultRelInfo->ri_NumIndices > 0 && update_indexes) recheckIndexes = ExecInsertIndexTuples(resultRelInfo, - slot, estate, false, + slot, estate, true, false, NULL, NIL); } diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c index 1b1d70ed68aa5..f2b2549a51584 100644 --- a/src/backend/replication/logical/worker.c +++ b/src/backend/replication/logical/worker.c @@ -1309,7 +1309,8 @@ apply_handle_update(StringInfo s) InitResultRelInfo(resultRelInfo, rel->localrel, 1, NULL, 0); /* - * Populate updatedCols so that per-column triggers can fire. This could + * Populate updatedCols so that per-column triggers can fire, and so + * executor can correctly pass down indexUnchanged hint. This could * include more columns than were actually changed on the publisher * because the logical replication protocol doesn't contain that * information. But it would for example exclude columns that only exist diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h index de758cab0bde4..d357ebb559804 100644 --- a/src/include/access/amapi.h +++ b/src/include/access/amapi.h @@ -110,6 +110,7 @@ typedef bool (*aminsert_function) (Relation indexRelation, ItemPointer heap_tid, Relation heapRelation, IndexUniqueCheck checkUnique, + bool indexUnchanged, struct IndexInfo *indexInfo); /* bulk delete */ diff --git a/src/include/access/brin_internal.h b/src/include/access/brin_internal.h index 85c612e4902c5..78c89a6961736 100644 --- a/src/include/access/brin_internal.h +++ b/src/include/access/brin_internal.h @@ -91,6 +91,7 @@ extern void brinbuildempty(Relation index); extern bool brininsert(Relation idxRel, Datum *values, bool *nulls, ItemPointer heaptid, Relation heapRel, IndexUniqueCheck checkUnique, + bool indexUnchanged, struct IndexInfo *indexInfo); extern IndexScanDesc brinbeginscan(Relation r, int nkeys, int norderbys); extern int64 bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm); diff --git a/src/include/access/genam.h b/src/include/access/genam.h index aa8ff360daac4..0eab1508d3753 100644 --- a/src/include/access/genam.h +++ b/src/include/access/genam.h @@ -143,6 +143,7 @@ extern bool index_insert(Relation indexRelation, ItemPointer heap_t_ctid, Relation heapRelation, IndexUniqueCheck checkUnique, + bool indexUnchanged, struct IndexInfo *indexInfo); extern IndexScanDesc index_beginscan(Relation heapRelation, diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h index a7a71ae1b4c49..670a40b4bee8d 100644 --- a/src/include/access/gin_private.h +++ b/src/include/access/gin_private.h @@ -116,6 +116,7 @@ extern void ginbuildempty(Relation index); extern bool gininsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, + bool indexUnchanged, struct IndexInfo *indexInfo); extern void ginEntryInsert(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index e899e817496b4..553d364e2d1e3 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -403,6 +403,7 @@ extern void gistbuildempty(Relation index); extern bool gistinsert(Relation r, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, + bool indexUnchanged, struct IndexInfo *indexInfo); extern MemoryContext createTempGistContext(void); extern GISTSTATE *initGISTstate(Relation index); diff --git a/src/include/access/hash.h b/src/include/access/hash.h index 22a99e70837da..1cce865be2b04 100644 --- a/src/include/access/hash.h +++ b/src/include/access/hash.h @@ -364,6 +364,7 @@ extern void hashbuildempty(Relation index); extern bool hashinsert(Relation rel, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, + bool indexUnchanged, struct IndexInfo *indexInfo); extern bool hashgettuple(IndexScanDesc scan, ScanDirection dir); extern int64 hashgetbitmap(IndexScanDesc scan, TIDBitmap *tbm); diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h index b793dab9fa66c..7f8489aac2a00 100644 --- a/src/include/access/nbtree.h +++ b/src/include/access/nbtree.h @@ -996,6 +996,7 @@ extern void btbuildempty(Relation index); extern bool btinsert(Relation rel, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, + bool indexUnchanged, struct IndexInfo *indexInfo); extern IndexScanDesc btbeginscan(Relation rel, int nkeys, int norderbys); extern Size btestimateparallelscan(void); diff --git a/src/include/access/spgist.h b/src/include/access/spgist.h index 38a5902202bfe..2eb2f421a8714 100644 --- a/src/include/access/spgist.h +++ b/src/include/access/spgist.h @@ -199,6 +199,7 @@ extern void spgbuildempty(Relation index); extern bool spginsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, + bool indexUnchanged, struct IndexInfo *indexInfo); /* spgscan.c */ diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 53f431e1ed79f..758c3ca0974a0 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -581,6 +581,7 @@ extern void ExecOpenIndices(ResultRelInfo *resultRelInfo, bool speculative); extern void ExecCloseIndices(ResultRelInfo *resultRelInfo); extern List *ExecInsertIndexTuples(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, + bool update, bool noDupErr, bool *specConflict, List *arbiterIndexes); extern bool ExecCheckIndexConstraints(ResultRelInfo *resultRelInfo, diff --git a/src/test/modules/dummy_index_am/dummy_index_am.c b/src/test/modules/dummy_index_am/dummy_index_am.c index ac35023fb5c0e..5365b0639ec33 100644 --- a/src/test/modules/dummy_index_am/dummy_index_am.c +++ b/src/test/modules/dummy_index_am/dummy_index_am.c @@ -168,6 +168,7 @@ static bool diinsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, + bool indexUnchanged, IndexInfo *indexInfo) { /* nothing to do */ From d168b666823b6e0bcf60ed19ce24fb5fb91b8ccf Mon Sep 17 00:00:00 2001 From: Peter Geoghegan Date: Wed, 13 Jan 2021 09:21:32 -0800 Subject: [PATCH 090/240] Enhance nbtree index tuple deletion. Teach nbtree and heapam to cooperate in order to eagerly remove duplicate tuples representing dead MVCC versions. This is "bottom-up deletion". Each bottom-up deletion pass is triggered lazily in response to a flood of versions on an nbtree leaf page. This usually involves a "logically unchanged index" hint (these are produced by the executor mechanism added by commit 9dc718bd). The immediate goal of bottom-up index deletion is to avoid "unnecessary" page splits caused entirely by version duplicates. It naturally has an even more useful effect, though: it acts as a backstop against accumulating an excessive number of index tuple versions for any given _logical row_. Bottom-up index deletion complements what we might now call "top-down index deletion": index vacuuming performed by VACUUM. Bottom-up index deletion responds to the immediate local needs of queries, while leaving it up to autovacuum to perform infrequent clean sweeps of the index. The overall effect is to avoid certain pathological performance issues related to "version churn" from UPDATEs. The previous tableam interface used by index AMs to perform tuple deletion (the table_compute_xid_horizon_for_tuples() function) has been replaced with a new interface that supports certain new requirements. Many (perhaps all) of the capabilities added to nbtree by this commit could also be extended to other index AMs. That is left as work for a later commit. Extend deletion of LP_DEAD-marked index tuples in nbtree by adding logic to consider extra index tuples (that are not LP_DEAD-marked) for deletion in passing. This increases the number of index tuples deleted significantly in many cases. The LP_DEAD deletion process (which is now called "simple deletion" to clearly distinguish it from bottom-up deletion) won't usually need to visit any extra table blocks to check these extra tuples. We have to visit the same table blocks anyway to generate a latestRemovedXid value (at least in the common case where the index deletion operation's WAL record needs such a value). Testing has shown that the "extra tuples" simple deletion enhancement increases the number of index tuples deleted with almost any workload that has LP_DEAD bits set in leaf pages. That is, it almost never fails to delete at least a few extra index tuples. It helps most of all in cases that happen to naturally have a lot of delete-safe tuples. It's not uncommon for an individual deletion operation to end up deleting an order of magnitude more index tuples compared to the old naive approach (e.g., custom instrumentation of the patch shows that this happens fairly often when the regression tests are run). Add a further enhancement that augments simple deletion and bottom-up deletion in indexes that make use of deduplication: Teach nbtree's _bt_delitems_delete() function to support granular TID deletion in posting list tuples. It is now possible to delete individual TIDs from posting list tuples provided the TIDs have a tableam block number of a table block that gets visited as part of the deletion process (visiting the table block can be triggered directly or indirectly). Setting the LP_DEAD bit of a posting list tuple is still an all-or-nothing thing, but that matters much less now that deletion only needs to start out with the right _general_ idea about which index tuples are deletable. Bump XLOG_PAGE_MAGIC because xl_btree_delete changed. No bump in BTREE_VERSION, since there are no changes to the on-disk representation of nbtree indexes. Indexes built on PostgreSQL 12 or PostgreSQL 13 will automatically benefit from bottom-up index deletion (i.e. no reindexing required) following a pg_upgrade. The enhancement to simple deletion is available with all B-Tree indexes following a pg_upgrade, no matter what PostgreSQL version the user upgrades from. Author: Peter Geoghegan Reviewed-By: Heikki Linnakangas Reviewed-By: Victor Yegorov Discussion: https://postgr.es/m/CAH2-Wzm+maE3apHB8NOtmM=p-DO65j2V5GzAWCOEEuy3JZgb2g@mail.gmail.com --- doc/src/sgml/btree.sgml | 152 +++++- doc/src/sgml/ref/create_index.sgml | 36 +- src/backend/access/heap/heapam.c | 638 ++++++++++++++++++++--- src/backend/access/heap/heapam_handler.c | 2 +- src/backend/access/index/genam.c | 46 +- src/backend/access/nbtree/README | 140 +++-- src/backend/access/nbtree/nbtdedup.c | 293 ++++++++++- src/backend/access/nbtree/nbtinsert.c | 395 +++++++++++--- src/backend/access/nbtree/nbtpage.c | 494 +++++++++++++----- src/backend/access/nbtree/nbtree.c | 10 +- src/backend/access/nbtree/nbtsort.c | 1 - src/backend/access/nbtree/nbtxlog.c | 94 ++-- src/backend/access/rmgrdesc/nbtdesc.c | 4 +- src/backend/access/table/tableamapi.c | 2 +- src/include/access/heapam.h | 5 +- src/include/access/nbtree.h | 19 +- src/include/access/nbtxlog.h | 93 ++-- src/include/access/tableam.h | 128 ++++- src/include/access/xlog_internal.h | 2 +- 19 files changed, 2112 insertions(+), 442 deletions(-) diff --git a/doc/src/sgml/btree.sgml b/doc/src/sgml/btree.sgml index bb395e6a85c15..2b716c6443984 100644 --- a/doc/src/sgml/btree.sgml +++ b/doc/src/sgml/btree.sgml @@ -629,6 +629,109 @@ options(relopts local_relopts *) returns + + Bottom-up index deletion + + B-Tree indexes are not directly aware that under MVCC, there might + be multiple extant versions of the same logical table row; to an + index, each tuple is an independent object that needs its own index + entry. Version churn tuples may sometimes + accumulate and adversely affect query latency and throughput. This + typically occurs with UPDATE-heavy workloads + where most individual updates cannot apply the + HOT optimization. Changing the value of only + one column covered by one index during an UPDATE + always necessitates a new set of index tuples + — one for each and every index on the + table. Note in particular that this includes indexes that were not + logically modified by the UPDATE. + All indexes will need a successor physical index tuple that points + to the latest version in the table. Each new tuple within each + index will generally need to coexist with the original + updated tuple for a short period of time (typically + until shortly after the UPDATE transaction + commits). + + + B-Tree indexes incrementally delete version churn index tuples by + performing bottom-up index deletion passes. + Each deletion pass is triggered in reaction to an anticipated + version churn page split. This only happens with + indexes that are not logically modified by + UPDATE statements, where concentrated build up + of obsolete versions in particular pages would occur otherwise. A + page split will usually be avoided, though it's possible that + certain implementation-level heuristics will fail to identify and + delete even one garbage index tuple (in which case a page split or + deduplication pass resolves the issue of an incoming new tuple not + fitting on a leaf page). The worst case number of versions that + any index scan must traverse (for any single logical row) is an + important contributor to overall system responsiveness and + throughput. A bottom-up index deletion pass targets suspected + garbage tuples in a single leaf page based on + qualitative distinctions involving logical + rows and versions. This contrasts with the top-down + index cleanup performed by autovacuum workers, which is triggered + when certain quantitative table-level + thresholds are exceeded (see ). + + + + Not all deletion operations that are performed within B-Tree + indexes are bottom-up deletion operations. There is a distinct + category of index tuple deletion: simple index tuple + deletion. This is a deferred maintenance operation + that deletes index tuples that are known to be safe to delete + (those whose item identifier's LP_DEAD bit is + already set). Like bottom-up index deletion, simple index + deletion takes place at the point that a page split is anticipated + as a way of avoiding the split. + + + Simple deletion is opportunistic in the sense that it can only + take place when recent index scans set the + LP_DEAD bits of affected items in passing. + Prior to PostgreSQL 14, the only + category of B-Tree deletion was simple deletion. The main + differences between it and bottom-up deletion are that only the + former is opportunistically driven by the activity of passing + index scans, while only the latter specifically targets version + churn from UPDATEs that do not logically modify + indexed columns. + + + + Bottom-up index deletion performs the vast majority of all garbage + index tuple cleanup for particular indexes with certain workloads. + This is expected with any B-Tree index that is subject to + significant version churn from UPDATEs that + rarely or never logically modify the columns that the index covers. + The average and worst case number of versions per logical row can + be kept low purely through targeted incremental deletion passes. + It's quite possible that the on-disk size of certain indexes will + never increase by even one single page/block despite + constant version churn from + UPDATEs. Even then, an exhaustive clean + sweep by a VACUUM operation (typically + run in an autovacuum worker process) will eventually be required as + a part of collective cleanup of the table and + each of its indexes. + + + Unlike VACUUM, bottom-up index deletion does not + provide any strong guarantees about how old the oldest garbage + index tuple may be. No index can be permitted to retain + floating garbage index tuples that became dead prior + to a conservative cutoff point shared by the table and all of its + indexes collectively. This fundamental table-level invariant makes + it safe to recycle table TIDs. This is how it + is possible for distinct logical rows to reuse the same table + TID over time (though this can never happen with + two logical rows whose lifetimes span the same + VACUUM cycle). + + + Deduplication @@ -666,15 +769,17 @@ options(relopts local_relopts *) returns The deduplication process occurs lazily, when a new item is - inserted that cannot fit on an existing leaf page. This prevents - (or at least delays) leaf page splits. Unlike GIN posting list - tuples, B-Tree posting list tuples do not need to expand every time - a new duplicate is inserted; they are merely an alternative - physical representation of the original logical contents of the - leaf page. This design prioritizes consistent performance with - mixed read-write workloads. Most client applications will at least - see a moderate performance benefit from using deduplication. - Deduplication is enabled by default. + inserted that cannot fit on an existing leaf page, though only when + index tuple deletion could not free sufficient space for the new + item (typically deletion is briefly considered and then skipped + over). Unlike GIN posting list tuples, B-Tree posting list tuples + do not need to expand every time a new duplicate is inserted; they + are merely an alternative physical representation of the original + logical contents of the leaf page. This design prioritizes + consistent performance with mixed read-write workloads. Most + client applications will at least see a moderate performance + benefit from using deduplication. Deduplication is enabled by + default. CREATE INDEX and REINDEX @@ -702,25 +807,16 @@ options(relopts local_relopts *) returns deduplication isn't usually helpful. - B-Tree indexes are not directly aware that under MVCC, there might - be multiple extant versions of the same logical table row; to an - index, each tuple is an independent object that needs its own index - entry. Version duplicates may sometimes accumulate - and adversely affect query latency and throughput. This typically - occurs with UPDATE-heavy workloads where most - individual updates cannot apply the HOT - optimization (often because at least one indexed column gets - modified, necessitating a new set of index tuple versions — - one new tuple for each and every index). In - effect, B-Tree deduplication ameliorates index bloat caused by - version churn. Note that even the tuples from a unique index are - not necessarily physically unique when stored - on disk due to version churn. The deduplication optimization is - selectively applied within unique indexes. It targets those pages - that appear to have version duplicates. The high level goal is to - give VACUUM more time to run before an - unnecessary page split caused by version churn can - take place. + It is sometimes possible for unique indexes (as well as unique + constraints) to use deduplication. This allows leaf pages to + temporarily absorb extra version churn duplicates. + Deduplication in unique indexes augments bottom-up index deletion, + especially in cases where a long-running transactions holds a + snapshot that blocks garbage collection. The goal is to buy time + for the bottom-up index deletion strategy to become effective + again. Delaying page splits until a single long-running + transaction naturally goes away can allow a bottom-up deletion pass + to succeed where an earlier deletion pass failed. diff --git a/doc/src/sgml/ref/create_index.sgml b/doc/src/sgml/ref/create_index.sgml index 2054d5d9436c1..6fff02d824302 100644 --- a/doc/src/sgml/ref/create_index.sgml +++ b/doc/src/sgml/ref/create_index.sgml @@ -386,17 +386,39 @@ CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] The fillfactor for an index is a percentage that determines how full the index method will try to pack index pages. For B-trees, leaf pages - are filled to this percentage during initial index build, and also + are filled to this percentage during initial index builds, and also when extending the index at the right (adding new largest key values). If pages subsequently become completely full, they will be split, leading to - gradual degradation in the index's efficiency. B-trees use a default + fragmentation of the on-disk index structure. B-trees use a default fillfactor of 90, but any integer value from 10 to 100 can be selected. - If the table is static then fillfactor 100 is best to minimize the - index's physical size, but for heavily updated tables a smaller - fillfactor is better to minimize the need for page splits. The - other index methods use fillfactor in different but roughly analogous - ways; the default fillfactor varies between methods. + + + B-tree indexes on tables where many inserts and/or updates are + anticipated can benefit from lower fillfactor settings at + CREATE INDEX time (following bulk loading into the + table). Values in the range of 50 - 90 can usefully smooth + out the rate of page splits during the + early life of the B-tree index (lowering fillfactor like this may even + lower the absolute number of page splits, though this effect is highly + workload dependent). The B-tree bottom-up index deletion technique + described in is dependent on having + some extra space on pages to store extra + tuple versions, and so can be affected by fillfactor (though the effect + is usually not significant). + + + In other specific cases it might be useful to increase fillfactor to + 100 at CREATE INDEX time as a way of maximizing + space utilization. You should only consider this when you are + completely sure that the table is static (i.e. that it will never be + affected by either inserts or updates). A fillfactor setting of 100 + otherwise risks harming performance: even a few + updates or inserts will cause a sudden flood of page splits. + + + The other index methods use fillfactor in different but roughly + analogous ways; the default fillfactor varies between methods. diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 53e997cd5536e..5b9cfb26cf76f 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -55,6 +55,7 @@ #include "miscadmin.h" #include "pgstat.h" #include "port/atomics.h" +#include "port/pg_bitutils.h" #include "storage/bufmgr.h" #include "storage/freespace.h" #include "storage/lmgr.h" @@ -102,6 +103,8 @@ static void MultiXactIdWait(MultiXactId multi, MultiXactStatus status, uint16 in int *remaining); static bool ConditionalMultiXactIdWait(MultiXactId multi, MultiXactStatus status, uint16 infomask, Relation rel, int *remaining); +static void index_delete_sort(TM_IndexDeleteOp *delstate); +static int bottomup_sort_and_shrink(TM_IndexDeleteOp *delstate); static XLogRecPtr log_heap_new_cid(Relation relation, HeapTuple tup); static HeapTuple ExtractReplicaIdentity(Relation rel, HeapTuple tup, bool key_changed, bool *copy); @@ -166,18 +169,33 @@ static const struct #ifdef USE_PREFETCH /* - * heap_compute_xid_horizon_for_tuples and xid_horizon_prefetch_buffer use - * this structure to coordinate prefetching activity. + * heap_index_delete_tuples and index_delete_prefetch_buffer use this + * structure to coordinate prefetching activity */ typedef struct { BlockNumber cur_hblkno; int next_item; - int nitems; - ItemPointerData *tids; -} XidHorizonPrefetchState; + int ndeltids; + TM_IndexDelete *deltids; +} IndexDeletePrefetchState; #endif +/* heap_index_delete_tuples bottom-up index deletion costing constants */ +#define BOTTOMUP_MAX_NBLOCKS 6 +#define BOTTOMUP_TOLERANCE_NBLOCKS 3 + +/* + * heap_index_delete_tuples uses this when determining which heap blocks it + * must visit to help its bottom-up index deletion caller + */ +typedef struct IndexDeleteCounts +{ + int16 npromisingtids; /* Number of "promising" TIDs in group */ + int16 ntids; /* Number of TIDs in group */ + int16 ifirsttid; /* Offset to group's first deltid */ +} IndexDeleteCounts; + /* * This table maps tuple lock strength values for each particular * MultiXactStatus value. @@ -6936,28 +6954,31 @@ HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple, #ifdef USE_PREFETCH /* - * Helper function for heap_compute_xid_horizon_for_tuples. Issue prefetch - * requests for the number of buffers indicated by prefetch_count. The - * prefetch_state keeps track of all the buffers that we can prefetch and - * which ones have already been prefetched; each call to this function picks - * up where the previous call left off. + * Helper function for heap_index_delete_tuples. Issues prefetch requests for + * prefetch_count buffers. The prefetch_state keeps track of all the buffers + * we can prefetch, and which have already been prefetched; each call to this + * function picks up where the previous call left off. + * + * Note: we expect the deltids array to be sorted in an order that groups TIDs + * by heap block, with all TIDs for each block appearing together in exactly + * one group. */ static void -xid_horizon_prefetch_buffer(Relation rel, - XidHorizonPrefetchState *prefetch_state, - int prefetch_count) +index_delete_prefetch_buffer(Relation rel, + IndexDeletePrefetchState *prefetch_state, + int prefetch_count) { BlockNumber cur_hblkno = prefetch_state->cur_hblkno; int count = 0; int i; - int nitems = prefetch_state->nitems; - ItemPointerData *tids = prefetch_state->tids; + int ndeltids = prefetch_state->ndeltids; + TM_IndexDelete *deltids = prefetch_state->deltids; for (i = prefetch_state->next_item; - i < nitems && count < prefetch_count; + i < ndeltids && count < prefetch_count; i++) { - ItemPointer htid = &tids[i]; + ItemPointer htid = &deltids[i].tid; if (cur_hblkno == InvalidBlockNumber || ItemPointerGetBlockNumber(htid) != cur_hblkno) @@ -6978,24 +6999,20 @@ xid_horizon_prefetch_buffer(Relation rel, #endif /* - * Get the latestRemovedXid from the heap pages pointed at by the index - * tuples being deleted. + * heapam implementation of tableam's index_delete_tuples interface. * - * We used to do this during recovery rather than on the primary, but that - * approach now appears inferior. It meant that the primary could generate - * a lot of work for the standby without any back-pressure to slow down the - * primary, and it required the standby to have reached consistency, whereas - * we want to have correct information available even before that point. + * This helper function is called by index AMs during index tuple deletion. + * See tableam header comments for an explanation of the interface implemented + * here and a general theory of operation. Note that each call here is either + * a simple index deletion call, or a bottom-up index deletion call. * * It's possible for this to generate a fair amount of I/O, since we may be * deleting hundreds of tuples from a single index block. To amortize that * cost to some degree, this uses prefetching and combines repeat accesses to - * the same block. + * the same heap block. */ TransactionId -heap_compute_xid_horizon_for_tuples(Relation rel, - ItemPointerData *tids, - int nitems) +heap_index_delete_tuples(Relation rel, TM_IndexDeleteOp *delstate) { /* Initial assumption is that earlier pruning took care of conflict */ TransactionId latestRemovedXid = InvalidTransactionId; @@ -7005,28 +7022,44 @@ heap_compute_xid_horizon_for_tuples(Relation rel, OffsetNumber maxoff = InvalidOffsetNumber; TransactionId priorXmax; #ifdef USE_PREFETCH - XidHorizonPrefetchState prefetch_state; + IndexDeletePrefetchState prefetch_state; int prefetch_distance; #endif + SnapshotData SnapshotNonVacuumable; + int finalndeltids = 0, + nblocksaccessed = 0; + + /* State that's only used in bottom-up index deletion case */ + int nblocksfavorable = 0; + int curtargetfreespace = delstate->bottomupfreespace, + lastfreespace = 0, + actualfreespace = 0; + bool bottomup_final_block = false; + + InitNonVacuumableSnapshot(SnapshotNonVacuumable, GlobalVisTestFor(rel)); + + /* Sort caller's deltids array by TID for further processing */ + index_delete_sort(delstate); /* - * Sort to avoid repeated lookups for the same page, and to make it more - * likely to access items in an efficient order. In particular, this - * ensures that if there are multiple pointers to the same page, they all - * get processed looking up and locking the page just once. + * Bottom-up case: resort deltids array in an order attuned to where the + * greatest number of promising TIDs are to be found, and determine how + * many blocks from the start of sorted array should be considered + * favorable. This will also shrink the deltids array in order to + * eliminate completely unfavorable blocks up front. */ - qsort((void *) tids, nitems, sizeof(ItemPointerData), - (int (*) (const void *, const void *)) ItemPointerCompare); + if (delstate->bottomup) + nblocksfavorable = bottomup_sort_and_shrink(delstate); #ifdef USE_PREFETCH /* Initialize prefetch state. */ prefetch_state.cur_hblkno = InvalidBlockNumber; prefetch_state.next_item = 0; - prefetch_state.nitems = nitems; - prefetch_state.tids = tids; + prefetch_state.ndeltids = delstate->ndeltids; + prefetch_state.deltids = delstate->deltids; /* - * Compute the prefetch distance that we will attempt to maintain. + * Determine the prefetch distance that we will attempt to maintain. * * Since the caller holds a buffer lock somewhere in rel, we'd better make * sure that isn't a catalog relation before we call code that does @@ -7038,33 +7071,111 @@ heap_compute_xid_horizon_for_tuples(Relation rel, prefetch_distance = get_tablespace_maintenance_io_concurrency(rel->rd_rel->reltablespace); + /* Cap initial prefetch distance for bottom-up deletion caller */ + if (delstate->bottomup) + { + Assert(nblocksfavorable >= 1); + Assert(nblocksfavorable <= BOTTOMUP_MAX_NBLOCKS); + prefetch_distance = Min(prefetch_distance, nblocksfavorable); + } + /* Start prefetching. */ - xid_horizon_prefetch_buffer(rel, &prefetch_state, prefetch_distance); + index_delete_prefetch_buffer(rel, &prefetch_state, prefetch_distance); #endif - /* Iterate over all tids, and check their horizon */ - for (int i = 0; i < nitems; i++) + /* Iterate over deltids, determine which to delete, check their horizon */ + Assert(delstate->ndeltids > 0); + for (int i = 0; i < delstate->ndeltids; i++) { - ItemPointer htid = &tids[i]; + TM_IndexDelete *ideltid = &delstate->deltids[i]; + TM_IndexStatus *istatus = delstate->status + ideltid->id; + ItemPointer htid = &ideltid->tid; OffsetNumber offnum; /* - * Read heap buffer, but avoid refetching if it's the same block as - * required for the last tid. + * Read buffer, and perform required extra steps each time a new block + * is encountered. Avoid refetching if it's the same block as the one + * from the last htid. */ if (blkno == InvalidBlockNumber || ItemPointerGetBlockNumber(htid) != blkno) { - /* release old buffer */ - if (BufferIsValid(buf)) + /* + * Consider giving up early for bottom-up index deletion caller + * first. (Only prefetch next-next block afterwards, when it + * becomes clear that we're at least going to access the next + * block in line.) + * + * Sometimes the first block frees so much space for bottom-up + * caller that the deletion process can end without accessing any + * more blocks. It is usually necessary to access 2 or 3 blocks + * per bottom-up deletion operation, though. + */ + if (delstate->bottomup) { - LockBuffer(buf, BUFFER_LOCK_UNLOCK); - ReleaseBuffer(buf); + /* + * We often allow caller to delete a few additional items + * whose entries we reached after the point that space target + * from caller was satisfied. The cost of accessing the page + * was already paid at that point, so it made sense to finish + * it off. When that happened, we finalize everything here + * (by finishing off the whole bottom-up deletion operation + * without needlessly paying the cost of accessing any more + * blocks). + */ + if (bottomup_final_block) + break; + + /* + * Give up when we didn't enable our caller to free any + * additional space as a result of processing the page that we + * just finished up with. This rule is the main way in which + * we keep the cost of bottom-up deletion under control. + */ + if (nblocksaccessed >= 1 && actualfreespace == lastfreespace) + break; + lastfreespace = actualfreespace; /* for next time */ + + /* + * Deletion operation (which is bottom-up) will definitely + * access the next block in line. Prepare for that now. + * + * Decay target free space so that we don't hang on for too + * long with a marginal case. (Space target is only truly + * helpful when it allows us to recognize that we don't need + * to access more than 1 or 2 blocks to satisfy caller due to + * agreeable workload characteristics.) + * + * We are a bit more patient when we encounter contiguous + * blocks, though: these are treated as favorable blocks. The + * decay process is only applied when the next block in line + * is not a favorable/contiguous block. This is not an + * exception to the general rule; we still insist on finding + * at least one deletable item per block accessed. See + * bottomup_nblocksfavorable() for full details of the theory + * behind favorable blocks and heap block locality in general. + * + * Note: The first block in line is always treated as a + * favorable block, so the earliest possible point that the + * decay can be applied is just before we access the second + * block in line. The Assert() verifies this for us. + */ + Assert(nblocksaccessed > 0 || nblocksfavorable > 0); + if (nblocksfavorable > 0) + nblocksfavorable--; + else + curtargetfreespace /= 2; } - blkno = ItemPointerGetBlockNumber(htid); + /* release old buffer */ + if (BufferIsValid(buf)) + UnlockReleaseBuffer(buf); + blkno = ItemPointerGetBlockNumber(htid); buf = ReadBuffer(rel, blkno); + nblocksaccessed++; + Assert(!delstate->bottomup || + nblocksaccessed <= BOTTOMUP_MAX_NBLOCKS); #ifdef USE_PREFETCH @@ -7072,7 +7183,7 @@ heap_compute_xid_horizon_for_tuples(Relation rel, * To maintain the prefetch distance, prefetch one more page for * each page we read. */ - xid_horizon_prefetch_buffer(rel, &prefetch_state, 1); + index_delete_prefetch_buffer(rel, &prefetch_state, 1); #endif LockBuffer(buf, BUFFER_LOCK_SHARE); @@ -7081,6 +7192,31 @@ heap_compute_xid_horizon_for_tuples(Relation rel, maxoff = PageGetMaxOffsetNumber(page); } + if (istatus->knowndeletable) + Assert(!delstate->bottomup && !istatus->promising); + else + { + ItemPointerData tmp = *htid; + HeapTupleData heapTuple; + + /* Are any tuples from this HOT chain non-vacuumable? */ + if (heap_hot_search_buffer(&tmp, rel, buf, &SnapshotNonVacuumable, + &heapTuple, NULL, true)) + continue; /* can't delete entry */ + + /* Caller will delete, since whole HOT chain is vacuumable */ + istatus->knowndeletable = true; + + /* Maintain index free space info for bottom-up deletion case */ + if (delstate->bottomup) + { + Assert(istatus->freespace > 0); + actualfreespace += istatus->freespace; + if (actualfreespace >= curtargetfreespace) + bottomup_final_block = true; + } + } + /* * Maintain latestRemovedXid value for deletion operation as a whole * by advancing current value using heap tuple headers. This is @@ -7108,17 +7244,18 @@ heap_compute_xid_horizon_for_tuples(Relation rel, } /* - * We'll often encounter LP_DEAD line pointers. No need to do - * anything more with htid when that happens. This is okay - * because the earlier pruning operation that made the line - * pointer LP_DEAD in the first place must have considered the - * tuple header as part of generating its own latestRemovedXid - * value. + * We'll often encounter LP_DEAD line pointers (especially with an + * entry marked knowndeletable by our caller up front). No heap + * tuple headers get examined for an htid that leads us to an + * LP_DEAD item. This is okay because the earlier pruning + * operation that made the line pointer LP_DEAD in the first place + * must have considered the original tuple header as part of + * generating its own latestRemovedXid value. * - * Relying on XLOG_HEAP2_CLEANUP_INFO records like this is the - * same strategy that index vacuuming uses in all cases. Index - * VACUUM WAL records don't even have a latestRemovedXid field of - * their own for this reason. + * Relying on XLOG_HEAP2_CLEAN records like this is the same + * strategy that index vacuuming uses in all cases. Index VACUUM + * WAL records don't even have a latestRemovedXid field of their + * own for this reason. */ if (!ItemIdIsNormal(lp)) break; @@ -7148,15 +7285,388 @@ heap_compute_xid_horizon_for_tuples(Relation rel, offnum = ItemPointerGetOffsetNumber(&htup->t_ctid); priorXmax = HeapTupleHeaderGetUpdateXid(htup); } + + /* Enable further/final shrinking of deltids for caller */ + finalndeltids = i + 1; } - if (BufferIsValid(buf)) + UnlockReleaseBuffer(buf); + + /* + * Shrink deltids array to exclude non-deletable entries at the end. This + * is not just a minor optimization. Final deltids array size might be + * zero for a bottom-up caller. Index AM is explicitly allowed to rely on + * ndeltids being zero in all cases with zero total deletable entries. + */ + Assert(finalndeltids > 0 || delstate->bottomup); + delstate->ndeltids = finalndeltids; + + return latestRemovedXid; +} + +/* + * Specialized inlineable comparison function for index_delete_sort() + */ +static inline int +index_delete_sort_cmp(TM_IndexDelete *deltid1, TM_IndexDelete *deltid2) +{ + ItemPointer tid1 = &deltid1->tid; + ItemPointer tid2 = &deltid2->tid; + + { + BlockNumber blk1 = ItemPointerGetBlockNumber(tid1); + BlockNumber blk2 = ItemPointerGetBlockNumber(tid2); + + if (blk1 != blk2) + return (blk1 < blk2) ? -1 : 1; + } { - LockBuffer(buf, BUFFER_LOCK_UNLOCK); - ReleaseBuffer(buf); + OffsetNumber pos1 = ItemPointerGetOffsetNumber(tid1); + OffsetNumber pos2 = ItemPointerGetOffsetNumber(tid2); + + if (pos1 != pos2) + return (pos1 < pos2) ? -1 : 1; } - return latestRemovedXid; + pg_unreachable(); + + return 0; +} + +/* + * Sort deltids array from delstate by TID. This prepares it for further + * processing by heap_index_delete_tuples(). + * + * This operation becomes a noticeable consumer of CPU cycles with some + * workloads, so we go to the trouble of specialization/micro optimization. + * We use shellsort for this because it's easy to specialize, compiles to + * relatively few instructions, and is adaptive to presorted inputs/subsets + * (which are typical here). + */ +static void +index_delete_sort(TM_IndexDeleteOp *delstate) +{ + TM_IndexDelete *deltids = delstate->deltids; + int ndeltids = delstate->ndeltids; + int low = 0; + + /* + * Shellsort gap sequence (taken from Sedgewick-Incerpi paper). + * + * This implementation is fast with array sizes up to ~4500. This covers + * all supported BLCKSZ values. + */ + const int gaps[9] = {1968, 861, 336, 112, 48, 21, 7, 3, 1}; + + /* Think carefully before changing anything here -- keep swaps cheap */ + StaticAssertStmt(sizeof(TM_IndexDelete) <= 8, + "element size exceeds 8 bytes"); + + for (int g = 0; g < lengthof(gaps); g++) + { + for (int hi = gaps[g], i = low + hi; i < ndeltids; i++) + { + TM_IndexDelete d = deltids[i]; + int j = i; + + while (j >= hi && index_delete_sort_cmp(&deltids[j - hi], &d) >= 0) + { + deltids[j] = deltids[j - hi]; + j -= hi; + } + deltids[j] = d; + } + } +} + +/* + * Returns how many blocks should be considered favorable/contiguous for a + * bottom-up index deletion pass. This is a number of heap blocks that starts + * from and includes the first block in line. + * + * There is always at least one favorable block during bottom-up index + * deletion. In the worst case (i.e. with totally random heap blocks) the + * first block in line (the only favorable block) can be thought of as a + * degenerate array of contiguous blocks that consists of a single block. + * heap_index_delete_tuples() will expect this. + * + * Caller passes blockgroups, a description of the final order that deltids + * will be sorted in for heap_index_delete_tuples() bottom-up index deletion + * processing. Note that deltids need not actually be sorted just yet (caller + * only passes deltids to us so that we can interpret blockgroups). + * + * You might guess that the existence of contiguous blocks cannot matter much, + * since in general the main factor that determines which blocks we visit is + * the number of promising TIDs, which is a fixed hint from the index AM. + * We're not really targeting the general case, though -- the actual goal is + * to adapt our behavior to a wide variety of naturally occurring conditions. + * The effects of most of the heuristics we apply are only noticeable in the + * aggregate, over time and across many _related_ bottom-up index deletion + * passes. + * + * Deeming certain blocks favorable allows heapam to recognize and adapt to + * workloads where heap blocks visited during bottom-up index deletion can be + * accessed contiguously, in the sense that each newly visited block is the + * neighbor of the block that bottom-up deletion just finished processing (or + * close enough to it). It will likely be cheaper to access more favorable + * blocks sooner rather than later (e.g. in this pass, not across a series of + * related bottom-up passes). Either way it is probably only a matter of time + * (or a matter of further correlated version churn) before all blocks that + * appear together as a single large batch of favorable blocks get accessed by + * _some_ bottom-up pass. Large batches of favorable blocks tend to either + * appear almost constantly or not even once (it all depends on per-index + * workload characteristics). + * + * Note that the blockgroups sort order applies a power-of-two bucketing + * scheme that creates opportunities for contiguous groups of blocks to get + * batched together, at least with workloads that are naturally amenable to + * being driven by heap block locality. This doesn't just enhance the spatial + * locality of bottom-up heap block processing in the obvious way. It also + * enables temporal locality of access, since sorting by heap block number + * naturally tends to make the bottom-up processing order deterministic. + * + * Consider the following example to get a sense of how temporal locality + * might matter: There is a heap relation with several indexes, each of which + * is low to medium cardinality. It is subject to constant non-HOT updates. + * The updates are skewed (in one part of the primary key, perhaps). None of + * the indexes are logically modified by the UPDATE statements (if they were + * then bottom-up index deletion would not be triggered in the first place). + * Naturally, each new round of index tuples (for each heap tuple that gets a + * heap_update() call) will have the same heap TID in each and every index. + * Since these indexes are low cardinality and never get logically modified, + * heapam processing during bottom-up deletion passes will access heap blocks + * in approximately sequential order. Temporal locality of access occurs due + * to bottom-up deletion passes behaving very similarly across each of the + * indexes at any given moment. This keeps the number of buffer misses needed + * to visit heap blocks to a minimum. + */ +static int +bottomup_nblocksfavorable(IndexDeleteCounts *blockgroups, int nblockgroups, + TM_IndexDelete *deltids) +{ + int64 lastblock = -1; + int nblocksfavorable = 0; + + Assert(nblockgroups >= 1); + Assert(nblockgroups <= BOTTOMUP_MAX_NBLOCKS); + + /* + * We tolerate heap blocks that will be accessed only slightly out of + * physical order. Small blips occur when a pair of almost-contiguous + * blocks happen to fall into different buckets (perhaps due only to a + * small difference in npromisingtids that the bucketing scheme didn't + * quite manage to ignore). We effectively ignore these blips by applying + * a small tolerance. The precise tolerance we use is a little arbitrary, + * but it works well enough in practice. + */ + for (int b = 0; b < nblockgroups; b++) + { + IndexDeleteCounts *group = blockgroups + b; + TM_IndexDelete *firstdtid = deltids + group->ifirsttid; + BlockNumber block = ItemPointerGetBlockNumber(&firstdtid->tid); + + if (lastblock != -1 && + ((int64) block < lastblock - BOTTOMUP_TOLERANCE_NBLOCKS || + (int64) block > lastblock + BOTTOMUP_TOLERANCE_NBLOCKS)) + break; + + nblocksfavorable++; + lastblock = block; + } + + /* Always indicate that there is at least 1 favorable block */ + Assert(nblocksfavorable >= 1); + + return nblocksfavorable; +} + +/* + * qsort comparison function for bottomup_sort_and_shrink() + */ +static int +bottomup_sort_and_shrink_cmp(const void *arg1, const void *arg2) +{ + const IndexDeleteCounts *group1 = (const IndexDeleteCounts *) arg1; + const IndexDeleteCounts *group2 = (const IndexDeleteCounts *) arg2; + + /* + * Most significant field is npromisingtids (which we invert the order of + * so as to sort in desc order). + * + * Caller should have already normalized npromisingtids fields into + * power-of-two values (buckets). + */ + if (group1->npromisingtids > group2->npromisingtids) + return -1; + if (group1->npromisingtids < group2->npromisingtids) + return 1; + + /* + * Tiebreak: desc ntids sort order. + * + * We cannot expect power-of-two values for ntids fields. We should + * behave as if they were already rounded up for us instead. + */ + if (group1->ntids != group2->ntids) + { + uint32 ntids1 = pg_nextpower2_32((uint32) group1->ntids); + uint32 ntids2 = pg_nextpower2_32((uint32) group2->ntids); + + if (ntids1 > ntids2) + return -1; + if (ntids1 < ntids2) + return 1; + } + + /* + * Tiebreak: asc offset-into-deltids-for-block (offset to first TID for + * block in deltids array) order. + * + * This is equivalent to sorting in ascending heap block number order + * (among otherwise equal subsets of the array). This approach allows us + * to avoid accessing the out-of-line TID. (We rely on the assumption + * that the deltids array was sorted in ascending heap TID order when + * these offsets to the first TID from each heap block group were formed.) + */ + if (group1->ifirsttid > group2->ifirsttid) + return 1; + if (group1->ifirsttid < group2->ifirsttid) + return -1; + + pg_unreachable(); + + return 0; +} + +/* + * heap_index_delete_tuples() helper function for bottom-up deletion callers. + * + * Sorts deltids array in the order needed for useful processing by bottom-up + * deletion. The array should already be sorted in TID order when we're + * called. The sort process groups heap TIDs from deltids into heap block + * groupings. Earlier/more-promising groups/blocks are usually those that are + * known to have the most "promising" TIDs. + * + * Sets new size of deltids array (ndeltids) in state. deltids will only have + * TIDs from the BOTTOMUP_MAX_NBLOCKS most promising heap blocks when we + * return. This often means that deltids will be shrunk to a small fraction + * of its original size (we eliminate many heap blocks from consideration for + * caller up front). + * + * Returns the number of "favorable" blocks. See bottomup_nblocksfavorable() + * for a definition and full details. + */ +static int +bottomup_sort_and_shrink(TM_IndexDeleteOp *delstate) +{ + IndexDeleteCounts *blockgroups; + TM_IndexDelete *reordereddeltids; + BlockNumber curblock = InvalidBlockNumber; + int nblockgroups = 0; + int ncopied = 0; + int nblocksfavorable = 0; + + Assert(delstate->bottomup); + Assert(delstate->ndeltids > 0); + + /* Calculate per-heap-block count of TIDs */ + blockgroups = palloc(sizeof(IndexDeleteCounts) * delstate->ndeltids); + for (int i = 0; i < delstate->ndeltids; i++) + { + TM_IndexDelete *ideltid = &delstate->deltids[i]; + TM_IndexStatus *istatus = delstate->status + ideltid->id; + ItemPointer htid = &ideltid->tid; + bool promising = istatus->promising; + + if (curblock != ItemPointerGetBlockNumber(htid)) + { + /* New block group */ + nblockgroups++; + + Assert(curblock < ItemPointerGetBlockNumber(htid) || + !BlockNumberIsValid(curblock)); + + curblock = ItemPointerGetBlockNumber(htid); + blockgroups[nblockgroups - 1].ifirsttid = i; + blockgroups[nblockgroups - 1].ntids = 1; + blockgroups[nblockgroups - 1].npromisingtids = 0; + } + else + { + blockgroups[nblockgroups - 1].ntids++; + } + + if (promising) + blockgroups[nblockgroups - 1].npromisingtids++; + } + + /* + * We're about ready to sort block groups to determine the optimal order + * for visiting heap blocks. But before we do, round the number of + * promising tuples for each block group up to the nearest power-of-two + * (except for block groups where npromisingtids is already 0). + * + * This scheme divides heap blocks/block groups into buckets. Each bucket + * contains blocks that have _approximately_ the same number of promising + * TIDs as each other. The goal is to ignore relatively small differences + * in the total number of promising entries, so that the whole process can + * give a little weight to heapam factors (like heap block locality) + * instead. This isn't a trade-off, really -- we have nothing to lose. + * It would be foolish to interpret small differences in npromisingtids + * values as anything more than noise. + * + * We tiebreak on nhtids when sorting block group subsets that have the + * same npromisingtids, but this has the same issues as npromisingtids, + * and so nhtids is subject to the same power-of-two bucketing scheme. + * The only reason that we don't fix nhtids in the same way here too is + * that we'll need accurate nhtids values after the sort. We handle + * nhtids bucketization dynamically instead (in the sort comparator). + * + * See bottomup_nblocksfavorable() for a full explanation of when and how + * heap locality/favorable blocks can significantly influence when and how + * heap blocks are accessed. + */ + for (int b = 0; b < nblockgroups; b++) + { + IndexDeleteCounts *group = blockgroups + b; + + /* Better off falling back on nhtids with low npromisingtids */ + if (group->npromisingtids <= 4) + group->npromisingtids = 4; + else + group->npromisingtids = + pg_nextpower2_32((uint32) group->npromisingtids); + } + + /* Sort groups and rearrange caller's deltids array */ + qsort(blockgroups, nblockgroups, sizeof(IndexDeleteCounts), + bottomup_sort_and_shrink_cmp); + reordereddeltids = palloc(delstate->ndeltids * sizeof(TM_IndexDelete)); + + nblockgroups = Min(BOTTOMUP_MAX_NBLOCKS, nblockgroups); + /* Determine number of favorable blocks at the start of final deltids */ + nblocksfavorable = bottomup_nblocksfavorable(blockgroups, nblockgroups, + delstate->deltids); + + for (int b = 0; b < nblockgroups; b++) + { + IndexDeleteCounts *group = blockgroups + b; + TM_IndexDelete *firstdtid = delstate->deltids + group->ifirsttid; + + memcpy(reordereddeltids + ncopied, firstdtid, + sizeof(TM_IndexDelete) * group->ntids); + ncopied += group->ntids; + } + + /* Copy final grouped and sorted TIDs back into start of caller's array */ + memcpy(delstate->deltids, reordereddeltids, + sizeof(TM_IndexDelete) * ncopied); + delstate->ndeltids = ncopied; + + pfree(reordereddeltids); + pfree(blockgroups); + + return nblocksfavorable; } /* diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c index ac4a3be458739..4a70e20a14308 100644 --- a/src/backend/access/heap/heapam_handler.c +++ b/src/backend/access/heap/heapam_handler.c @@ -2563,7 +2563,7 @@ static const TableAmRoutine heapam_methods = { .tuple_get_latest_tid = heap_get_latest_tid, .tuple_tid_valid = heapam_tuple_tid_valid, .tuple_satisfies_snapshot = heapam_tuple_satisfies_snapshot, - .compute_xid_horizon_for_tuples = heap_compute_xid_horizon_for_tuples, + .index_delete_tuples = heap_index_delete_tuples, .relation_set_new_filenode = heapam_relation_set_new_filenode, .relation_nontransactional_truncate = heapam_relation_nontransactional_truncate, diff --git a/src/backend/access/index/genam.c b/src/backend/access/index/genam.c index e9877906e56d9..c911c705ba62f 100644 --- a/src/backend/access/index/genam.c +++ b/src/backend/access/index/genam.c @@ -276,11 +276,18 @@ BuildIndexValueDescription(Relation indexRelation, /* * Get the latestRemovedXid from the table entries pointed at by the index - * tuples being deleted. - * - * Note: index access methods that don't consistently use the standard - * IndexTuple + heap TID item pointer representation will need to provide - * their own version of this function. + * tuples being deleted using an AM-generic approach. + * + * This is a table_index_delete_tuples() shim used by index AMs that have + * simple requirements. These callers only need to consult the tableam to get + * a latestRemovedXid value, and only expect to delete tuples that are already + * known deletable. When a latestRemovedXid value isn't needed in index AM's + * deletion WAL record, it is safe for it to skip calling here entirely. + * + * We assume that caller index AM uses the standard IndexTuple representation, + * with table TIDs stored in the t_tid field. We also expect (and assert) + * that the line pointers on page for 'itemnos' offsets are already marked + * LP_DEAD. */ TransactionId index_compute_xid_horizon_for_tuples(Relation irel, @@ -289,12 +296,17 @@ index_compute_xid_horizon_for_tuples(Relation irel, OffsetNumber *itemnos, int nitems) { - ItemPointerData *ttids = - (ItemPointerData *) palloc(sizeof(ItemPointerData) * nitems); + TM_IndexDeleteOp delstate; TransactionId latestRemovedXid = InvalidTransactionId; Page ipage = BufferGetPage(ibuf); IndexTuple itup; + delstate.bottomup = false; + delstate.bottomupfreespace = 0; + delstate.ndeltids = 0; + delstate.deltids = palloc(nitems * sizeof(TM_IndexDelete)); + delstate.status = palloc(nitems * sizeof(TM_IndexStatus)); + /* identify what the index tuples about to be deleted point to */ for (int i = 0; i < nitems; i++) { @@ -303,14 +315,26 @@ index_compute_xid_horizon_for_tuples(Relation irel, iitemid = PageGetItemId(ipage, itemnos[i]); itup = (IndexTuple) PageGetItem(ipage, iitemid); - ItemPointerCopy(&itup->t_tid, &ttids[i]); + Assert(ItemIdIsDead(iitemid)); + + ItemPointerCopy(&itup->t_tid, &delstate.deltids[i].tid); + delstate.deltids[i].id = delstate.ndeltids; + delstate.status[i].idxoffnum = InvalidOffsetNumber; /* unused */ + delstate.status[i].knowndeletable = true; /* LP_DEAD-marked */ + delstate.status[i].promising = false; /* unused */ + delstate.status[i].freespace = 0; /* unused */ + + delstate.ndeltids++; } /* determine the actual xid horizon */ - latestRemovedXid = - table_compute_xid_horizon_for_tuples(hrel, ttids, nitems); + latestRemovedXid = table_index_delete_tuples(hrel, &delstate); + + /* assert tableam agrees that all items are deletable */ + Assert(delstate.ndeltids == nitems); - pfree(ttids); + pfree(delstate.deltids); + pfree(delstate.status); return latestRemovedXid; } diff --git a/src/backend/access/nbtree/README b/src/backend/access/nbtree/README index 27f555177eca3..92205325fbe4a 100644 --- a/src/backend/access/nbtree/README +++ b/src/backend/access/nbtree/README @@ -82,8 +82,8 @@ page.) A backwards scan has one additional bit of complexity: after following the left-link we must account for the possibility that the left sibling page got split before we could read it. So, we have to move right until we find a page whose right-link matches the page we -came from. (Actually, it's even harder than that; see deletion discussion -below.) +came from. (Actually, it's even harder than that; see page deletion +discussion below.) Page read locks are held only for as long as a scan is examining a page. To minimize lock/unlock traffic, an index scan always searches a leaf page @@ -163,16 +163,16 @@ pages (though suffix truncation is also considered). Note we must include the incoming item in this calculation, otherwise it is possible to find that the incoming item doesn't fit on the split page where it needs to go! -The Deletion Algorithm ----------------------- +Deleting index tuples during VACUUM +----------------------------------- Before deleting a leaf item, we get a super-exclusive lock on the target page, so that no other backend has a pin on the page when the deletion starts. This is not necessary for correctness in terms of the btree index operations themselves; as explained above, index scans logically stop "between" pages and so can't lose their place. The reason we do it is to -provide an interlock between non-full VACUUM and indexscans. Since VACUUM -deletes index entries before reclaiming heap tuple line pointers, the +provide an interlock between VACUUM and indexscans. Since VACUUM deletes +index entries before reclaiming heap tuple line pointers, the super-exclusive lock guarantees that VACUUM can't reclaim for re-use a line pointer that an indexscanning process might be about to visit. This guarantee works only for simple indexscans that visit the heap in sync @@ -202,7 +202,8 @@ from the page have been processed. This guarantees that the btbulkdelete call cannot return while any indexscan is still holding a copy of a deleted index tuple if the scan could be confused by that. Note that this requirement does not say that btbulkdelete must visit the pages in any -particular order. (See also on-the-fly deletion, below.) +particular order. (See also simple deletion and bottom-up deletion, +below.) There is no such interlocking for deletion of items in internal pages, since backends keep no lock nor pin on a page they have descended past. @@ -213,8 +214,8 @@ page). Since we hold a lock on the lower page (per L&Y) until we have re-found the parent item that links to it, we can be assured that the parent item does still exist and can't have been deleted. -Page Deletion -------------- +Deleting entire pages during VACUUM +----------------------------------- We consider deleting an entire page from the btree only when it's become completely empty of items. (Merging partly-full pages would allow better @@ -419,8 +420,8 @@ without a backend's cached page also being detected as invalidated, but only when we happen to recycle a block that once again gets recycled as the rightmost leaf page. -On-the-Fly Deletion Of Index Tuples ------------------------------------ +Simple deletion +--------------- If a process visits a heap tuple and finds that it's dead and removable (ie, dead to all open transactions, not only that process), then we can @@ -434,24 +435,27 @@ LP_DEAD bits are often set when checking a unique index for conflicts on insert (this is simpler because it takes place when we hold an exclusive lock on the leaf page). -Once an index tuple has been marked LP_DEAD it can actually be removed +Once an index tuple has been marked LP_DEAD it can actually be deleted from the index immediately; since index scans only stop "between" pages, no scan can lose its place from such a deletion. We separate the steps because we allow LP_DEAD to be set with only a share lock (it's exactly like a hint bit for a heap tuple), but physically removing tuples requires -exclusive lock. In the current code we try to remove LP_DEAD tuples when -we are otherwise faced with having to split a page to do an insertion (and -hence have exclusive lock on it already). Deduplication can also prevent -a page split, but removing LP_DEAD tuples is the preferred approach. -(Note that posting list tuples can only have their LP_DEAD bit set when -every table TID within the posting list is known dead.) - -This leaves the index in a state where it has no entry for a dead tuple -that still exists in the heap. This is not a problem for the current -implementation of VACUUM, but it could be a problem for anything that -explicitly tries to find index entries for dead tuples. (However, the -same situation is created by REINDEX, since it doesn't enter dead -tuples into the index.) +exclusive lock. Also, delaying the deletion often allows us to pick up +extra index tuples that weren't initially safe for index scans to mark +LP_DEAD. We do this with index tuples whose TIDs point to the same table +blocks as an LP_DEAD-marked tuple. They're practically free to check in +passing, and have a pretty good chance of being safe to delete due to +various locality effects. + +We only try to delete LP_DEAD tuples (and nearby tuples) when we are +otherwise faced with having to split a page to do an insertion (and hence +have exclusive lock on it already). Deduplication and bottom-up index +deletion can also prevent a page split, but simple deletion is always our +preferred approach. (Note that posting list tuples can only have their +LP_DEAD bit set when every table TID within the posting list is known +dead. This isn't much of a problem in practice because LP_DEAD bits are +just a starting point for simple deletion -- we still manage to perform +granular deletes of posting list TIDs quite often.) It's sufficient to have an exclusive lock on the index page, not a super-exclusive lock, to do deletion of LP_DEAD items. It might seem @@ -469,6 +473,70 @@ LSN of the page, and only act to set LP_DEAD bits when the LSN has not changed at all. (Avoiding dropping the pin entirely also makes it safe, of course.) +Bottom-Up deletion +------------------ + +We attempt to delete whatever duplicates happen to be present on the page +when the duplicates are suspected to be caused by version churn from +successive UPDATEs. This only happens when we receive an executor hint +indicating that optimizations like heapam's HOT have not worked out for +the index -- the incoming tuple must be a logically unchanged duplicate +which is needed for MVCC purposes, suggesting that that might well be the +dominant source of new index tuples on the leaf page in question. (Also, +bottom-up deletion is triggered within unique indexes in cases with +continual INSERT and DELETE related churn, since that is easy to detect +without any external hint.) + +Simple deletion will already have failed to prevent a page split when a +bottom-up deletion pass takes place (often because no LP_DEAD bits were +ever set on the page). The two mechanisms have closely related +implementations. The same WAL records are used for each operation, and +the same tableam infrastructure is used to determine what TIDs/tuples are +actually safe to delete. The implementations only differ in how they pick +TIDs to consider for deletion, and whether or not the tableam will give up +before accessing all table blocks (bottom-up deletion lives with the +uncertainty of its success by keeping the cost of failure low). Even +still, the two mechanisms are clearly distinct at the conceptual level. + +Bottom-up index deletion is driven entirely by heuristics (whereas simple +deletion is guaranteed to delete at least those index tuples that are +already LP_DEAD marked -- there must be at least one). We have no +certainty that we'll find even one index tuple to delete. That's why we +closely cooperate with the tableam to keep the costs it pays in balance +with the benefits we receive. The interface that we use for this is +described in detail in access/tableam.h. + +Bottom-up index deletion can be thought of as a backstop mechanism against +unnecessary version-driven page splits. It is based in part on an idea +from generational garbage collection: the "generational hypothesis". This +is the empirical observation that "most objects die young". Within +nbtree, new index tuples often quickly appear in the same place, and then +quickly become garbage. There can be intense concentrations of garbage in +relatively few leaf pages with certain workloads (or there could be in +earlier versions of PostgreSQL without bottom-up index deletion, at +least). See doc/src/sgml/btree.sgml for a high-level description of the +design principles behind bottom-up index deletion in nbtree, including +details of how it complements VACUUM. + +We expect to find a reasonably large number of tuples that are safe to +delete within each bottom-up pass. If we don't then we won't need to +consider the question of bottom-up deletion for the same leaf page for +quite a while (usually because the page splits, which resolves the +situation for the time being). We expect to perform regular bottom-up +deletion operations against pages that are at constant risk of unnecessary +page splits caused only by version churn. When the mechanism works well +we'll constantly be "on the verge" of having version-churn-driven page +splits, but never actually have even one. + +Our duplicate heuristics work well despite being fairly simple. +Unnecessary page splits only occur when there are truly pathological +levels of version churn (in theory a small amount of version churn could +make a page split occur earlier than strictly necessary, but that's pretty +harmless). We don't have to understand the underlying workload; we only +have to understand the general nature of the pathology that we target. +Version churn is easy to spot when it is truly pathological. Affected +leaf pages are fairly homogeneous. + WAL Considerations ------------------ @@ -767,9 +835,10 @@ into a single physical tuple with a posting list (a simple array of heap TIDs with the standard item pointer format). Deduplication is always applied lazily, at the point where it would otherwise be necessary to perform a page split. It occurs only when LP_DEAD items have been -removed, as our last line of defense against splitting a leaf page. We -can set the LP_DEAD bit with posting list tuples, though only when all -TIDs are known dead. +removed, as our last line of defense against splitting a leaf page +(bottom-up index deletion may be attempted first, as our second last line +of defense). We can set the LP_DEAD bit with posting list tuples, though +only when all TIDs are known dead. Our lazy approach to deduplication allows the page space accounting used during page splits to have absolutely minimal special case logic for @@ -788,7 +857,10 @@ page space accounting (see later section), so it's not clear how compression could be integrated with nbtree. Besides, posting list compression does not offer a compelling trade-off for nbtree, since in general nbtree is optimized for consistent performance with many -concurrent readers and writers. +concurrent readers and writers. Compression would also make the deletion +of a subset of TIDs from a posting list slow and complicated, which would +be a big problem for workloads that depend heavily on bottom-up index +deletion. A major goal of our lazy approach to deduplication is to limit the performance impact of deduplication with random updates. Even concurrent @@ -826,6 +898,16 @@ delay a split that is probably inevitable anyway. This allows us to avoid the overhead of attempting to deduplicate with unique indexes that always have few or no duplicates. +Note: Avoiding "unnecessary" page splits driven by version churn is also +the goal of bottom-up index deletion, which was added to PostgreSQL 14. +Bottom-up index deletion is now the preferred way to deal with this +problem (with all kinds of indexes, though especially with unique +indexes). Still, deduplication can sometimes augment bottom-up index +deletion. When deletion cannot free tuples (due to an old snapshot +holding up cleanup), falling back on deduplication provides additional +capacity. Delaying the page split by deduplicating can allow a future +bottom-up deletion pass of the same page to succeed. + Posting list splits ------------------- diff --git a/src/backend/access/nbtree/nbtdedup.c b/src/backend/access/nbtree/nbtdedup.c index 54fd7658e446e..854e3b2cf9acf 100644 --- a/src/backend/access/nbtree/nbtdedup.c +++ b/src/backend/access/nbtree/nbtdedup.c @@ -1,7 +1,7 @@ /*------------------------------------------------------------------------- * * nbtdedup.c - * Deduplicate items in Postgres btrees. + * Deduplicate or bottom-up delete items in Postgres btrees. * * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California @@ -19,6 +19,8 @@ #include "miscadmin.h" #include "utils/rel.h" +static void _bt_bottomupdel_finish_pending(Page page, BTDedupState state, + TM_IndexDeleteOp *delstate); static bool _bt_do_singleval(Relation rel, Page page, BTDedupState state, OffsetNumber minoff, IndexTuple newitem); static void _bt_singleval_fillfactor(Page page, BTDedupState state, @@ -267,6 +269,147 @@ _bt_dedup_pass(Relation rel, Buffer buf, Relation heapRel, IndexTuple newitem, pfree(state); } +/* + * Perform bottom-up index deletion pass. + * + * See if duplicate index tuples (plus certain nearby tuples) are eligible to + * be deleted via bottom-up index deletion. The high level goal here is to + * entirely prevent "unnecessary" page splits caused by MVCC version churn + * from UPDATEs (when the UPDATEs don't logically modify any of the columns + * covered by the 'rel' index). This is qualitative, not quantitative -- we + * do not particularly care about once-off opportunities to delete many index + * tuples together. + * + * See nbtree/README for details on the design of nbtree bottom-up deletion. + * See access/tableam.h for a description of how we're expected to cooperate + * with the tableam. + * + * Returns true on success, in which case caller can assume page split will be + * avoided for a reasonable amount of time. Returns false when caller should + * deduplicate the page (if possible at all). + * + * Note: Occasionally we return true despite failing to delete enough items to + * avoid a split. This makes caller skip deduplication and go split the page + * right away. Our return value is always just advisory information. + * + * Note: Caller should have already deleted all existing items with their + * LP_DEAD bits set. + */ +bool +_bt_bottomupdel_pass(Relation rel, Buffer buf, Relation heapRel, + Size newitemsz) +{ + OffsetNumber offnum, + minoff, + maxoff; + Page page = BufferGetPage(buf); + BTPageOpaque opaque = (BTPageOpaque) PageGetSpecialPointer(page); + BTDedupState state; + TM_IndexDeleteOp delstate; + bool neverdedup; + int nkeyatts = IndexRelationGetNumberOfKeyAttributes(rel); + + /* Passed-in newitemsz is MAXALIGNED but does not include line pointer */ + newitemsz += sizeof(ItemIdData); + + /* Initialize deduplication state */ + state = (BTDedupState) palloc(sizeof(BTDedupStateData)); + state->deduplicate = true; + state->nmaxitems = 0; + state->maxpostingsize = BLCKSZ; /* We're not really deduplicating */ + state->base = NULL; + state->baseoff = InvalidOffsetNumber; + state->basetupsize = 0; + state->htids = palloc(state->maxpostingsize); + state->nhtids = 0; + state->nitems = 0; + state->phystupsize = 0; + state->nintervals = 0; + + /* + * Initialize tableam state that describes bottom-up index deletion + * operation. + * + * We'll go on to ask the tableam to search for TIDs whose index tuples we + * can safely delete. The tableam will search until our leaf page space + * target is satisfied, or until the cost of continuing with the tableam + * operation seems too high. It focuses its efforts on TIDs associated + * with duplicate index tuples that we mark "promising". + * + * This space target is a little arbitrary. The tableam must be able to + * keep the costs and benefits in balance. We provide the tableam with + * exhaustive information about what might work, without directly + * concerning ourselves with avoiding work during the tableam call. Our + * role in costing the bottom-up deletion process is strictly advisory. + */ + delstate.bottomup = true; + delstate.bottomupfreespace = Max(BLCKSZ / 16, newitemsz); + delstate.ndeltids = 0; + delstate.deltids = palloc(MaxTIDsPerBTreePage * sizeof(TM_IndexDelete)); + delstate.status = palloc(MaxTIDsPerBTreePage * sizeof(TM_IndexStatus)); + + minoff = P_FIRSTDATAKEY(opaque); + maxoff = PageGetMaxOffsetNumber(page); + for (offnum = minoff; + offnum <= maxoff; + offnum = OffsetNumberNext(offnum)) + { + ItemId itemid = PageGetItemId(page, offnum); + IndexTuple itup = (IndexTuple) PageGetItem(page, itemid); + + Assert(!ItemIdIsDead(itemid)); + + if (offnum == minoff) + { + /* itup starts first pending interval */ + _bt_dedup_start_pending(state, itup, offnum); + } + else if (_bt_keep_natts_fast(rel, state->base, itup) > nkeyatts && + _bt_dedup_save_htid(state, itup)) + { + /* Tuple is equal; just added its TIDs to pending interval */ + } + else + { + /* Finalize interval -- move its TIDs to delete state */ + _bt_bottomupdel_finish_pending(page, state, &delstate); + + /* itup starts new pending interval */ + _bt_dedup_start_pending(state, itup, offnum); + } + } + /* Finalize final interval -- move its TIDs to delete state */ + _bt_bottomupdel_finish_pending(page, state, &delstate); + + /* + * We don't give up now in the event of having few (or even zero) + * promising tuples for the tableam because it's not up to us as the index + * AM to manage costs (note that the tableam might have heuristics of its + * own that work out what to do). We should at least avoid having our + * caller do a useless deduplication pass after we return in the event of + * zero promising tuples, though. + */ + neverdedup = false; + if (state->nintervals == 0) + neverdedup = true; + + pfree(state->htids); + pfree(state); + + /* Ask tableam which TIDs are deletable, then physically delete them */ + _bt_delitems_delete_check(rel, buf, heapRel, &delstate); + + pfree(delstate.deltids); + pfree(delstate.status); + + /* Report "success" to caller unconditionally to avoid deduplication */ + if (neverdedup) + return true; + + /* Don't dedup when we won't end up back here any time soon anyway */ + return PageGetExactFreeSpace(page) >= Max(BLCKSZ / 24, newitemsz); +} + /* * Create a new pending posting list tuple based on caller's base tuple. * @@ -452,6 +595,150 @@ _bt_dedup_finish_pending(Page newpage, BTDedupState state) return spacesaving; } +/* + * Finalize interval during bottom-up index deletion. + * + * During a bottom-up pass we expect that TIDs will be recorded in dedup state + * first, and then get moved over to delstate (in variable-sized batches) by + * calling here. Call here happens when the number of TIDs in a dedup + * interval is known, and interval gets finalized (i.e. when caller sees next + * tuple on the page is not a duplicate, or when caller runs out of tuples to + * process from leaf page). + * + * This is where bottom-up deletion determines and remembers which entries are + * duplicates. This will be important information to the tableam delete + * infrastructure later on. Plain index tuple duplicates are marked + * "promising" here, per tableam contract. + * + * Our approach to marking entries whose TIDs come from posting lists is more + * complicated. Posting lists can only be formed by a deduplication pass (or + * during an index build), so recent version churn affecting the pointed-to + * logical rows is not particularly likely. We may still give a weak signal + * about posting list tuples' entries (by marking just one of its TIDs/entries + * promising), though this is only a possibility in the event of further + * duplicate index tuples in final interval that covers posting list tuple (as + * in the plain tuple case). A weak signal/hint will be useful to the tableam + * when it has no stronger signal to go with for the deletion operation as a + * whole. + * + * The heuristics we use work well in practice because we only need to give + * the tableam the right _general_ idea about where to look. Garbage tends to + * naturally get concentrated in relatively few table blocks with workloads + * that bottom-up deletion targets. The tableam cannot possibly rank all + * available table blocks sensibly based on the hints we provide, but that's + * okay -- only the extremes matter. The tableam just needs to be able to + * predict which few table blocks will have the most tuples that are safe to + * delete for each deletion operation, with low variance across related + * deletion operations. + */ +static void +_bt_bottomupdel_finish_pending(Page page, BTDedupState state, + TM_IndexDeleteOp *delstate) +{ + bool dupinterval = (state->nitems > 1); + + Assert(state->nitems > 0); + Assert(state->nitems <= state->nhtids); + Assert(state->intervals[state->nintervals].baseoff == state->baseoff); + + for (int i = 0; i < state->nitems; i++) + { + OffsetNumber offnum = state->baseoff + i; + ItemId itemid = PageGetItemId(page, offnum); + IndexTuple itup = (IndexTuple) PageGetItem(page, itemid); + TM_IndexDelete *ideltid = &delstate->deltids[delstate->ndeltids]; + TM_IndexStatus *istatus = &delstate->status[delstate->ndeltids]; + + if (!BTreeTupleIsPosting(itup)) + { + /* Simple case: A plain non-pivot tuple */ + ideltid->tid = itup->t_tid; + ideltid->id = delstate->ndeltids; + istatus->idxoffnum = offnum; + istatus->knowndeletable = false; /* for now */ + istatus->promising = dupinterval; /* simple rule */ + istatus->freespace = ItemIdGetLength(itemid) + sizeof(ItemIdData); + + delstate->ndeltids++; + } + else + { + /* + * Complicated case: A posting list tuple. + * + * We make the conservative assumption that there can only be at + * most one affected logical row per posting list tuple. There + * will be at most one promising entry in deltids to represent + * this presumed lone logical row. Note that this isn't even + * considered unless the posting list tuple is also in an interval + * of duplicates -- this complicated rule is just a variant of the + * simple rule used to decide if plain index tuples are promising. + */ + int nitem = BTreeTupleGetNPosting(itup); + bool firstpromising = false; + bool lastpromising = false; + + Assert(_bt_posting_valid(itup)); + + if (dupinterval) + { + /* + * Complicated rule: either the first or last TID in the + * posting list gets marked promising (if any at all) + */ + BlockNumber minblocklist, + midblocklist, + maxblocklist; + ItemPointer mintid, + midtid, + maxtid; + + mintid = BTreeTupleGetHeapTID(itup); + midtid = BTreeTupleGetPostingN(itup, nitem / 2); + maxtid = BTreeTupleGetMaxHeapTID(itup); + minblocklist = ItemPointerGetBlockNumber(mintid); + midblocklist = ItemPointerGetBlockNumber(midtid); + maxblocklist = ItemPointerGetBlockNumber(maxtid); + + /* Only entry with predominant table block can be promising */ + firstpromising = (minblocklist == midblocklist); + lastpromising = (!firstpromising && + midblocklist == maxblocklist); + } + + for (int p = 0; p < nitem; p++) + { + ItemPointer htid = BTreeTupleGetPostingN(itup, p); + + ideltid->tid = *htid; + ideltid->id = delstate->ndeltids; + istatus->idxoffnum = offnum; + istatus->knowndeletable = false; /* for now */ + istatus->promising = false; + if ((firstpromising && p == 0) || + (lastpromising && p == nitem - 1)) + istatus->promising = true; + istatus->freespace = sizeof(ItemPointerData); /* at worst */ + + ideltid++; + istatus++; + delstate->ndeltids++; + } + } + } + + if (dupinterval) + { + state->intervals[state->nintervals].nitems = state->nitems; + state->nintervals++; + } + + /* Reset state for next interval */ + state->nhtids = 0; + state->nitems = 0; + state->phystupsize = 0; +} + /* * Determine if page non-pivot tuples (data items) are all duplicates of the * same value -- if they are, deduplication's "single value" strategy should @@ -622,8 +909,8 @@ _bt_form_posting(IndexTuple base, ItemPointer htids, int nhtids) * Generate a replacement tuple by "updating" a posting list tuple so that it * no longer has TIDs that need to be deleted. * - * Used by VACUUM. Caller's vacposting argument points to the existing - * posting list tuple to be updated. + * Used by both VACUUM and index deletion. Caller's vacposting argument + * points to the existing posting list tuple to be updated. * * On return, caller's vacposting argument will point to final "updated" * tuple, which will be palloc()'d in caller's memory context. diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c index d7566ba082fec..e3336039125c9 100644 --- a/src/backend/access/nbtree/nbtinsert.c +++ b/src/backend/access/nbtree/nbtinsert.c @@ -17,9 +17,9 @@ #include "access/nbtree.h" #include "access/nbtxlog.h" -#include "access/tableam.h" #include "access/transam.h" #include "access/xloginsert.h" +#include "lib/qunique.h" #include "miscadmin.h" #include "storage/lmgr.h" #include "storage/predicate.h" @@ -37,6 +37,7 @@ static TransactionId _bt_check_unique(Relation rel, BTInsertState insertstate, static OffsetNumber _bt_findinsertloc(Relation rel, BTInsertState insertstate, bool checkingunique, + bool indexUnchanged, BTStack stack, Relation heapRel); static void _bt_stepright(Relation rel, BTInsertState insertstate, BTStack stack); @@ -60,8 +61,16 @@ static inline bool _bt_pgaddtup(Page page, Size itemsize, IndexTuple itup, OffsetNumber itup_off, bool newfirstdataitem); static void _bt_delete_or_dedup_one_page(Relation rel, Relation heapRel, BTInsertState insertstate, - bool lpdeadonly, bool checkingunique, - bool uniquedup); + bool simpleonly, bool checkingunique, + bool uniquedup, bool indexUnchanged); +static void _bt_simpledel_pass(Relation rel, Buffer buffer, Relation heapRel, + OffsetNumber *deletable, int ndeletable, + IndexTuple newitem, OffsetNumber minoff, + OffsetNumber maxoff); +static BlockNumber *_bt_deadblocks(Page page, OffsetNumber *deletable, + int ndeletable, IndexTuple newitem, + int *nblocks); +static inline int _bt_blk_cmp(const void *arg1, const void *arg2); /* * _bt_doinsert() -- Handle insertion of a single index tuple in the tree. @@ -75,6 +84,11 @@ static void _bt_delete_or_dedup_one_page(Relation rel, Relation heapRel, * For UNIQUE_CHECK_EXISTING we merely run the duplicate check, and * don't actually insert. * + * indexUnchanged executor hint indicates if itup is from an + * UPDATE that didn't logically change the indexed value, but + * must nevertheless have a new entry to point to a successor + * version. + * * The result value is only significant for UNIQUE_CHECK_PARTIAL: * it must be true if the entry is known unique, else false. * (In the current implementation we'll also return true after a @@ -83,7 +97,8 @@ static void _bt_delete_or_dedup_one_page(Relation rel, Relation heapRel, */ bool _bt_doinsert(Relation rel, IndexTuple itup, - IndexUniqueCheck checkUnique, Relation heapRel) + IndexUniqueCheck checkUnique, bool indexUnchanged, + Relation heapRel) { bool is_unique = false; BTInsertStateData insertstate; @@ -238,7 +253,7 @@ _bt_doinsert(Relation rel, IndexTuple itup, * checkingunique. */ newitemoff = _bt_findinsertloc(rel, &insertstate, checkingunique, - stack, heapRel); + indexUnchanged, stack, heapRel); _bt_insertonpg(rel, itup_key, insertstate.buf, InvalidBuffer, stack, itup, insertstate.itemsz, newitemoff, insertstate.postingoff, false); @@ -480,11 +495,7 @@ _bt_check_unique(Relation rel, BTInsertState insertstate, Relation heapRel, * items as quickly as we can. We only apply _bt_compare() when * we get to a non-killed item. We could reuse the bounds to * avoid _bt_compare() calls for known equal tuples, but it - * doesn't seem worth it. Workloads with heavy update activity - * tend to have many deduplication passes, so we'll often avoid - * most of those comparisons, too (we call _bt_compare() when the - * posting list tuple is initially encountered, though not when - * processing later TIDs from the same tuple). + * doesn't seem worth it. */ if (!inposting) curitemid = PageGetItemId(page, offset); @@ -777,6 +788,17 @@ _bt_check_unique(Relation rel, BTInsertState insertstate, Relation heapRel, * room for the new tuple, this function moves right, trying to find a * legal page that does.) * + * If 'indexUnchanged' is true, this is for an UPDATE that didn't + * logically change the indexed value, but must nevertheless have a new + * entry to point to a successor version. This hint from the executor + * will influence our behavior when the page might have to be split and + * we must consider our options. Bottom-up index deletion can avoid + * pathological version-driven page splits, but we only want to go to the + * trouble of trying it when we already have moderate confidence that + * it's appropriate. The hint should not significantly affect our + * behavior over time unless practically all inserts on to the leaf page + * get the hint. + * * On exit, insertstate buffer contains the chosen insertion page, and * the offset within that page is returned. If _bt_findinsertloc needed * to move right, the lock and pin on the original page are released, and @@ -793,6 +815,7 @@ static OffsetNumber _bt_findinsertloc(Relation rel, BTInsertState insertstate, bool checkingunique, + bool indexUnchanged, BTStack stack, Relation heapRel) { @@ -817,7 +840,7 @@ _bt_findinsertloc(Relation rel, if (itup_key->heapkeyspace) { /* Keep track of whether checkingunique duplicate seen */ - bool uniquedup = false; + bool uniquedup = indexUnchanged; /* * If we're inserting into a unique index, we may have to walk right @@ -874,14 +897,13 @@ _bt_findinsertloc(Relation rel, } /* - * If the target page is full, see if we can obtain enough space using - * one or more strategies (e.g. erasing LP_DEAD items, deduplication). - * Page splits are expensive, and should only go ahead when truly - * necessary. + * If the target page cannot fit newitem, try to avoid splitting the + * page on insert by performing deletion or deduplication now */ if (PageGetFreeSpace(page) < insertstate->itemsz) _bt_delete_or_dedup_one_page(rel, heapRel, insertstate, false, - checkingunique, uniquedup); + checkingunique, uniquedup, + indexUnchanged); } else { @@ -921,9 +943,9 @@ _bt_findinsertloc(Relation rel, */ if (P_HAS_GARBAGE(opaque)) { - /* Erase LP_DEAD items (won't deduplicate) */ + /* Perform simple deletion */ _bt_delete_or_dedup_one_page(rel, heapRel, insertstate, true, - checkingunique, false); + false, false, false); if (PageGetFreeSpace(page) >= insertstate->itemsz) break; /* OK, now we have enough space */ @@ -970,14 +992,11 @@ _bt_findinsertloc(Relation rel, /* * There is an overlapping posting list tuple with its LP_DEAD bit * set. We don't want to unnecessarily unset its LP_DEAD bit while - * performing a posting list split, so delete all LP_DEAD items early. - * This is the only case where LP_DEAD deletes happen even though - * there is space for newitem on the page. - * - * This can only erase LP_DEAD items (it won't deduplicate). + * performing a posting list split, so perform simple index tuple + * deletion early. */ _bt_delete_or_dedup_one_page(rel, heapRel, insertstate, true, - checkingunique, false); + false, false, false); /* * Do new binary search. New insert location cannot overlap with any @@ -2606,21 +2625,19 @@ _bt_pgaddtup(Page page, } /* - * _bt_delete_or_dedup_one_page - Try to avoid a leaf page split by attempting - * a variety of operations. - * - * There are two operations performed here: deleting items already marked - * LP_DEAD, and deduplication. If both operations fail to free enough space - * for the incoming item then caller will go on to split the page. We always - * attempt our preferred strategy (which is to delete items whose LP_DEAD bit - * are set) first. If that doesn't work out we move on to deduplication. + * _bt_delete_or_dedup_one_page - Try to avoid a leaf page split. * - * Caller's checkingunique and uniquedup arguments help us decide if we should - * perform deduplication, which is primarily useful with low cardinality data, - * but can sometimes absorb version churn. + * There are three operations performed here: simple index deletion, bottom-up + * index deletion, and deduplication. If all three operations fail to free + * enough space for the incoming item then caller will go on to split the + * page. We always consider simple deletion first. If that doesn't work out + * we consider alternatives. Callers that only want us to consider simple + * deletion (without any fallback) ask for that using the 'simpleonly' + * argument. * - * Callers that only want us to look for/delete LP_DEAD items can ask for that - * directly by passing true 'lpdeadonly' argument. + * We usually pick only one alternative "complex" operation when simple + * deletion alone won't prevent a page split. The 'checkingunique', + * 'uniquedup', and 'indexUnchanged' arguments are used for that. * * Note: We used to only delete LP_DEAD items when the BTP_HAS_GARBAGE page * level flag was found set. The flag was useful back when there wasn't @@ -2638,12 +2655,13 @@ _bt_pgaddtup(Page page, static void _bt_delete_or_dedup_one_page(Relation rel, Relation heapRel, BTInsertState insertstate, - bool lpdeadonly, bool checkingunique, - bool uniquedup) + bool simpleonly, bool checkingunique, + bool uniquedup, bool indexUnchanged) { OffsetNumber deletable[MaxIndexTuplesPerPage]; int ndeletable = 0; OffsetNumber offnum, + minoff, maxoff; Buffer buffer = insertstate->buf; BTScanInsert itup_key = insertstate->itup_key; @@ -2651,14 +2669,19 @@ _bt_delete_or_dedup_one_page(Relation rel, Relation heapRel, BTPageOpaque opaque = (BTPageOpaque) PageGetSpecialPointer(page); Assert(P_ISLEAF(opaque)); - Assert(lpdeadonly || itup_key->heapkeyspace); + Assert(simpleonly || itup_key->heapkeyspace); + Assert(!simpleonly || (!checkingunique && !uniquedup && !indexUnchanged)); /* * Scan over all items to see which ones need to be deleted according to - * LP_DEAD flags. + * LP_DEAD flags. We'll usually manage to delete a few extra items that + * are not marked LP_DEAD in passing. Often the extra items that actually + * end up getting deleted are items that would have had their LP_DEAD bit + * set before long anyway (if we opted not to include them as extras). */ + minoff = P_FIRSTDATAKEY(opaque); maxoff = PageGetMaxOffsetNumber(page); - for (offnum = P_FIRSTDATAKEY(opaque); + for (offnum = minoff; offnum <= maxoff; offnum = OffsetNumberNext(offnum)) { @@ -2670,7 +2693,8 @@ _bt_delete_or_dedup_one_page(Relation rel, Relation heapRel, if (ndeletable > 0) { - _bt_delitems_delete(rel, buffer, deletable, ndeletable, heapRel); + _bt_simpledel_pass(rel, buffer, heapRel, deletable, ndeletable, + insertstate->itup, minoff, maxoff); insertstate->bounds_valid = false; /* Return when a page split has already been avoided */ @@ -2682,37 +2706,288 @@ _bt_delete_or_dedup_one_page(Relation rel, Relation heapRel, } /* - * Some callers only want to delete LP_DEAD items. Return early for these - * callers. + * We're done with simple deletion. Return early with callers that only + * call here so that simple deletion can be considered. This includes + * callers that explicitly ask for this and checkingunique callers that + * probably don't have any version churn duplicates on the page. * * Note: The page's BTP_HAS_GARBAGE hint flag may still be set when we * return at this point (or when we go on the try either or both of our * other strategies and they also fail). We do not bother expending a * separate write to clear it, however. Caller will definitely clear it - * when it goes on to split the page (plus deduplication knows to clear - * the flag when it actually modifies the page). + * when it goes on to split the page (note also that the deduplication + * process will clear the flag in passing, just to keep things tidy). */ - if (lpdeadonly) - return; - - /* - * We can get called in the checkingunique case when there is no reason to - * believe that there are any duplicates on the page; we should at least - * still check for LP_DEAD items. If that didn't work out, give up and - * let caller split the page. Deduplication cannot be justified given - * there is no reason to think that there are duplicates. - */ - if (checkingunique && !uniquedup) + if (simpleonly || (checkingunique && !uniquedup)) + { + Assert(!indexUnchanged); return; + } /* Assume bounds about to be invalidated (this is almost certain now) */ insertstate->bounds_valid = false; /* - * Perform deduplication pass, though only when it is enabled for the - * index and known to be safe (it must be an allequalimage index). + * Perform bottom-up index deletion pass when executor hint indicated that + * incoming item is logically unchanged, or for a unique index that is + * known to have physical duplicates for some other reason. (There is a + * large overlap between these two cases for a unique index. It's worth + * having both triggering conditions in order to apply the optimization in + * the event of successive related INSERT and DELETE statements.) + * + * We'll go on to do a deduplication pass when a bottom-up pass fails to + * delete an acceptable amount of free space (a significant fraction of + * the page, or space for the new item, whichever is greater). + * + * Note: Bottom-up index deletion uses the same equality/equivalence + * routines as deduplication internally. However, it does not merge + * together index tuples, so the same correctness considerations do not + * apply. We deliberately omit an index-is-allequalimage test here. */ + if ((indexUnchanged || uniquedup) && + _bt_bottomupdel_pass(rel, buffer, heapRel, insertstate->itemsz)) + return; + + /* Perform deduplication pass (when enabled and index-is-allequalimage) */ if (BTGetDeduplicateItems(rel) && itup_key->allequalimage) _bt_dedup_pass(rel, buffer, heapRel, insertstate->itup, insertstate->itemsz, checkingunique); } + +/* + * _bt_simpledel_pass - Simple index tuple deletion pass. + * + * We delete all LP_DEAD-set index tuples on a leaf page. The offset numbers + * of all such tuples are determined by caller (caller passes these to us as + * its 'deletable' argument). + * + * We might also delete extra index tuples that turn out to be safe to delete + * in passing (though they must be cheap to check in passing to begin with). + * There is no certainty that any extra tuples will be deleted, though. The + * high level goal of the approach we take is to get the most out of each call + * here (without noticeably increasing the per-call overhead compared to what + * we need to do just to be able to delete the page's LP_DEAD-marked index + * tuples). + * + * The number of extra index tuples that turn out to be deletable might + * greatly exceed the number of LP_DEAD-marked index tuples due to various + * locality related effects. For example, it's possible that the total number + * of table blocks (pointed to by all TIDs on the leaf page) is naturally + * quite low, in which case we might end up checking if it's possible to + * delete _most_ index tuples on the page (without the tableam needing to + * access additional table blocks). The tableam will sometimes stumble upon + * _many_ extra deletable index tuples in indexes where this pattern is + * common. + * + * See nbtree/README for further details on simple index tuple deletion. + */ +static void +_bt_simpledel_pass(Relation rel, Buffer buffer, Relation heapRel, + OffsetNumber *deletable, int ndeletable, IndexTuple newitem, + OffsetNumber minoff, OffsetNumber maxoff) +{ + Page page = BufferGetPage(buffer); + BlockNumber *deadblocks; + int ndeadblocks; + TM_IndexDeleteOp delstate; + OffsetNumber offnum; + + /* Get array of table blocks pointed to by LP_DEAD-set tuples */ + deadblocks = _bt_deadblocks(page, deletable, ndeletable, newitem, + &ndeadblocks); + + /* Initialize tableam state that describes index deletion operation */ + delstate.bottomup = false; + delstate.bottomupfreespace = 0; + delstate.ndeltids = 0; + delstate.deltids = palloc(MaxTIDsPerBTreePage * sizeof(TM_IndexDelete)); + delstate.status = palloc(MaxTIDsPerBTreePage * sizeof(TM_IndexStatus)); + + for (offnum = minoff; + offnum <= maxoff; + offnum = OffsetNumberNext(offnum)) + { + ItemId itemid = PageGetItemId(page, offnum); + IndexTuple itup = (IndexTuple) PageGetItem(page, itemid); + TM_IndexDelete *odeltid = &delstate.deltids[delstate.ndeltids]; + TM_IndexStatus *ostatus = &delstate.status[delstate.ndeltids]; + BlockNumber tidblock; + void *match; + + if (!BTreeTupleIsPosting(itup)) + { + tidblock = ItemPointerGetBlockNumber(&itup->t_tid); + match = bsearch(&tidblock, deadblocks, ndeadblocks, + sizeof(BlockNumber), _bt_blk_cmp); + + if (!match) + { + Assert(!ItemIdIsDead(itemid)); + continue; + } + + /* + * TID's table block is among those pointed to by the TIDs from + * LP_DEAD-bit set tuples on page -- add TID to deltids + */ + odeltid->tid = itup->t_tid; + odeltid->id = delstate.ndeltids; + ostatus->idxoffnum = offnum; + ostatus->knowndeletable = ItemIdIsDead(itemid); + ostatus->promising = false; /* unused */ + ostatus->freespace = 0; /* unused */ + + delstate.ndeltids++; + } + else + { + int nitem = BTreeTupleGetNPosting(itup); + + for (int p = 0; p < nitem; p++) + { + ItemPointer tid = BTreeTupleGetPostingN(itup, p); + + tidblock = ItemPointerGetBlockNumber(tid); + match = bsearch(&tidblock, deadblocks, ndeadblocks, + sizeof(BlockNumber), _bt_blk_cmp); + + if (!match) + { + Assert(!ItemIdIsDead(itemid)); + continue; + } + + /* + * TID's table block is among those pointed to by the TIDs + * from LP_DEAD-bit set tuples on page -- add TID to deltids + */ + odeltid->tid = *tid; + odeltid->id = delstate.ndeltids; + ostatus->idxoffnum = offnum; + ostatus->knowndeletable = ItemIdIsDead(itemid); + ostatus->promising = false; /* unused */ + ostatus->freespace = 0; /* unused */ + + odeltid++; + ostatus++; + delstate.ndeltids++; + } + } + } + + pfree(deadblocks); + + Assert(delstate.ndeltids >= ndeletable); + + /* Physically delete LP_DEAD tuples (plus any delete-safe extra TIDs) */ + _bt_delitems_delete_check(rel, buffer, heapRel, &delstate); + + pfree(delstate.deltids); + pfree(delstate.status); +} + +/* + * _bt_deadblocks() -- Get LP_DEAD related table blocks. + * + * Builds sorted and unique-ified array of table block numbers from index + * tuple TIDs whose line pointers are marked LP_DEAD. Also adds the table + * block from incoming newitem just in case it isn't among the LP_DEAD-related + * table blocks. + * + * Always counting the newitem's table block as an LP_DEAD related block makes + * sense because the cost is consistently low; it is practically certain that + * the table block will not incur a buffer miss in tableam. On the other hand + * the benefit is often quite high. There is a decent chance that there will + * be some deletable items from this block, since in general most garbage + * tuples became garbage in the recent past (in many cases this won't be the + * first logical row that core code added to/modified in table block + * recently). + * + * Returns final array, and sets *nblocks to its final size for caller. + */ +static BlockNumber * +_bt_deadblocks(Page page, OffsetNumber *deletable, int ndeletable, + IndexTuple newitem, int *nblocks) +{ + int spacentids, + ntids; + BlockNumber *tidblocks; + + /* + * Accumulate each TID's block in array whose initial size has space for + * one table block per LP_DEAD-set tuple (plus space for the newitem table + * block). Array will only need to grow when there are LP_DEAD-marked + * posting list tuples (which is not that common). + */ + spacentids = ndeletable + 1; + ntids = 0; + tidblocks = (BlockNumber *) palloc(sizeof(BlockNumber) * spacentids); + + /* + * First add the table block for the incoming newitem. This is the one + * case where simple deletion can visit a table block that doesn't have + * any known deletable items. + */ + Assert(!BTreeTupleIsPosting(newitem) && !BTreeTupleIsPivot(newitem)); + tidblocks[ntids++] = ItemPointerGetBlockNumber(&newitem->t_tid); + + for (int i = 0; i < ndeletable; i++) + { + ItemId itemid = PageGetItemId(page, deletable[i]); + IndexTuple itup = (IndexTuple) PageGetItem(page, itemid); + + Assert(ItemIdIsDead(itemid)); + + if (!BTreeTupleIsPosting(itup)) + { + if (ntids + 1 > spacentids) + { + spacentids *= 2; + tidblocks = (BlockNumber *) + repalloc(tidblocks, sizeof(BlockNumber) * spacentids); + } + + tidblocks[ntids++] = ItemPointerGetBlockNumber(&itup->t_tid); + } + else + { + int nposting = BTreeTupleGetNPosting(itup); + + if (ntids + nposting > spacentids) + { + spacentids = Max(spacentids * 2, ntids + nposting); + tidblocks = (BlockNumber *) + repalloc(tidblocks, sizeof(BlockNumber) * spacentids); + } + + for (int j = 0; j < nposting; j++) + { + ItemPointer tid = BTreeTupleGetPostingN(itup, j); + + tidblocks[ntids++] = ItemPointerGetBlockNumber(tid); + } + } + } + + qsort(tidblocks, ntids, sizeof(BlockNumber), _bt_blk_cmp); + *nblocks = qunique(tidblocks, ntids, sizeof(BlockNumber), _bt_blk_cmp); + + return tidblocks; +} + +/* + * _bt_blk_cmp() -- qsort comparison function for _bt_simpledel_pass + */ +static inline int +_bt_blk_cmp(const void *arg1, const void *arg2) +{ + BlockNumber b1 = *((BlockNumber *) arg1); + BlockNumber b2 = *((BlockNumber *) arg2); + + if (b1 < b2) + return -1; + else if (b1 > b2) + return 1; + + return 0; +} diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c index 89eb66a8a60a0..e230f912c28dc 100644 --- a/src/backend/access/nbtree/nbtpage.c +++ b/src/backend/access/nbtree/nbtpage.c @@ -38,8 +38,14 @@ static BTMetaPageData *_bt_getmeta(Relation rel, Buffer metabuf); static void _bt_log_reuse_page(Relation rel, BlockNumber blkno, TransactionId latestRemovedXid); -static TransactionId _bt_xid_horizon(Relation rel, Relation heapRel, Page page, - OffsetNumber *deletable, int ndeletable); +static void _bt_delitems_delete(Relation rel, Buffer buf, + TransactionId latestRemovedXid, + OffsetNumber *deletable, int ndeletable, + BTVacuumPosting *updatable, int nupdatable, + Relation heapRel); +static char *_bt_delitems_update(BTVacuumPosting *updatable, int nupdatable, + OffsetNumber *updatedoffsets, + Size *updatedbuflen, bool needswal); static bool _bt_mark_page_halfdead(Relation rel, Buffer leafbuf, BTStack stack); static bool _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, @@ -1110,15 +1116,16 @@ _bt_page_recyclable(Page page) * sorted in ascending order. * * Routine deals with deleting TIDs when some (but not all) of the heap TIDs - * in an existing posting list item are to be removed by VACUUM. This works - * by updating/overwriting an existing item with caller's new version of the - * item (a version that lacks the TIDs that are to be deleted). + * in an existing posting list item are to be removed. This works by + * updating/overwriting an existing item with caller's new version of the item + * (a version that lacks the TIDs that are to be deleted). * * We record VACUUMs and b-tree deletes differently in WAL. Deletes must - * generate their own latestRemovedXid by accessing the heap directly, whereas - * VACUUMs rely on the initial heap scan taking care of it indirectly. Also, - * only VACUUM can perform granular deletes of individual TIDs in posting list - * tuples. + * generate their own latestRemovedXid by accessing the table directly, + * whereas VACUUMs rely on the initial VACUUM table scan performing + * WAL-logging that takes care of the issue for the table's indexes + * indirectly. Also, we remove the VACUUM cycle ID from pages, which b-tree + * deletes don't do. */ void _bt_delitems_vacuum(Relation rel, Buffer buf, @@ -1127,7 +1134,7 @@ _bt_delitems_vacuum(Relation rel, Buffer buf, { Page page = BufferGetPage(buf); BTPageOpaque opaque; - Size itemsz; + bool needswal = RelationNeedsWAL(rel); char *updatedbuf = NULL; Size updatedbuflen = 0; OffsetNumber updatedoffsets[MaxIndexTuplesPerPage]; @@ -1135,45 +1142,11 @@ _bt_delitems_vacuum(Relation rel, Buffer buf, /* Shouldn't be called unless there's something to do */ Assert(ndeletable > 0 || nupdatable > 0); - for (int i = 0; i < nupdatable; i++) - { - /* Replace work area IndexTuple with updated version */ - _bt_update_posting(updatable[i]); - - /* Maintain array of updatable page offsets for WAL record */ - updatedoffsets[i] = updatable[i]->updatedoffset; - } - - /* XLOG stuff -- allocate and fill buffer before critical section */ - if (nupdatable > 0 && RelationNeedsWAL(rel)) - { - Size offset = 0; - - for (int i = 0; i < nupdatable; i++) - { - BTVacuumPosting vacposting = updatable[i]; - - itemsz = SizeOfBtreeUpdate + - vacposting->ndeletedtids * sizeof(uint16); - updatedbuflen += itemsz; - } - - updatedbuf = palloc(updatedbuflen); - for (int i = 0; i < nupdatable; i++) - { - BTVacuumPosting vacposting = updatable[i]; - xl_btree_update update; - - update.ndeletedtids = vacposting->ndeletedtids; - memcpy(updatedbuf + offset, &update.ndeletedtids, - SizeOfBtreeUpdate); - offset += SizeOfBtreeUpdate; - - itemsz = update.ndeletedtids * sizeof(uint16); - memcpy(updatedbuf + offset, vacposting->deletetids, itemsz); - offset += itemsz; - } - } + /* Generate new version of posting lists without deleted TIDs */ + if (nupdatable > 0) + updatedbuf = _bt_delitems_update(updatable, nupdatable, + updatedoffsets, &updatedbuflen, + needswal); /* No ereport(ERROR) until changes are logged */ START_CRIT_SECTION(); @@ -1194,6 +1167,7 @@ _bt_delitems_vacuum(Relation rel, Buffer buf, { OffsetNumber updatedoffset = updatedoffsets[i]; IndexTuple itup; + Size itemsz; itup = updatable[i]->itup; itemsz = MAXALIGN(IndexTupleSize(itup)); @@ -1218,7 +1192,7 @@ _bt_delitems_vacuum(Relation rel, Buffer buf, * Clear the BTP_HAS_GARBAGE page flag. * * This flag indicates the presence of LP_DEAD items on the page (though - * not reliably). Note that we only trust it with pg_upgrade'd + * not reliably). Note that we only rely on it with pg_upgrade'd * !heapkeyspace indexes. That's why clearing it here won't usually * interfere with _bt_delitems_delete(). */ @@ -1227,7 +1201,7 @@ _bt_delitems_vacuum(Relation rel, Buffer buf, MarkBufferDirty(buf); /* XLOG stuff */ - if (RelationNeedsWAL(rel)) + if (needswal) { XLogRecPtr recptr; xl_btree_vacuum xlrec_vacuum; @@ -1260,7 +1234,7 @@ _bt_delitems_vacuum(Relation rel, Buffer buf, /* can't leak memory here */ if (updatedbuf != NULL) pfree(updatedbuf); - /* free tuples generated by calling _bt_update_posting() */ + /* free tuples allocated within _bt_delitems_update() */ for (int i = 0; i < nupdatable; i++) pfree(updatable[i]->itup); } @@ -1269,40 +1243,66 @@ _bt_delitems_vacuum(Relation rel, Buffer buf, * Delete item(s) from a btree leaf page during single-page cleanup. * * This routine assumes that the caller has pinned and write locked the - * buffer. Also, the given deletable array *must* be sorted in ascending - * order. + * buffer. Also, the given deletable and updatable arrays *must* be sorted in + * ascending order. + * + * Routine deals with deleting TIDs when some (but not all) of the heap TIDs + * in an existing posting list item are to be removed. This works by + * updating/overwriting an existing item with caller's new version of the item + * (a version that lacks the TIDs that are to be deleted). * * This is nearly the same as _bt_delitems_vacuum as far as what it does to - * the page, but it needs to generate its own latestRemovedXid by accessing - * the heap. This is used by the REDO routine to generate recovery conflicts. - * Also, it doesn't handle posting list tuples unless the entire tuple can be - * deleted as a whole (since there is only one LP_DEAD bit per line pointer). + * the page, but it needs its own latestRemovedXid from caller (caller gets + * this from tableam). This is used by the REDO routine to generate recovery + * conflicts. The other difference is that only _bt_delitems_vacuum will + * clear page's VACUUM cycle ID. */ -void -_bt_delitems_delete(Relation rel, Buffer buf, +static void +_bt_delitems_delete(Relation rel, Buffer buf, TransactionId latestRemovedXid, OffsetNumber *deletable, int ndeletable, + BTVacuumPosting *updatable, int nupdatable, Relation heapRel) { Page page = BufferGetPage(buf); BTPageOpaque opaque; - TransactionId latestRemovedXid = InvalidTransactionId; + bool needswal = RelationNeedsWAL(rel); + char *updatedbuf = NULL; + Size updatedbuflen = 0; + OffsetNumber updatedoffsets[MaxIndexTuplesPerPage]; /* Shouldn't be called unless there's something to do */ - Assert(ndeletable > 0); + Assert(ndeletable > 0 || nupdatable > 0); - if (XLogStandbyInfoActive() && RelationNeedsWAL(rel)) - latestRemovedXid = - _bt_xid_horizon(rel, heapRel, page, deletable, ndeletable); + /* Generate new versions of posting lists without deleted TIDs */ + if (nupdatable > 0) + updatedbuf = _bt_delitems_update(updatable, nupdatable, + updatedoffsets, &updatedbuflen, + needswal); /* No ereport(ERROR) until changes are logged */ START_CRIT_SECTION(); - /* Fix the page */ - PageIndexMultiDelete(page, deletable, ndeletable); + /* Handle updates and deletes just like _bt_delitems_vacuum */ + for (int i = 0; i < nupdatable; i++) + { + OffsetNumber updatedoffset = updatedoffsets[i]; + IndexTuple itup; + Size itemsz; + + itup = updatable[i]->itup; + itemsz = MAXALIGN(IndexTupleSize(itup)); + if (!PageIndexTupleOverwrite(page, updatedoffset, (Item) itup, + itemsz)) + elog(PANIC, "failed to update partially dead item in block %u of index \"%s\"", + BufferGetBlockNumber(buf), RelationGetRelationName(rel)); + } + + if (ndeletable > 0) + PageIndexMultiDelete(page, deletable, ndeletable); /* - * Unlike _bt_delitems_vacuum, we *must not* clear the vacuum cycle ID, - * because this is not called by VACUUM + * Unlike _bt_delitems_vacuum, we *must not* clear the vacuum cycle ID at + * this point. The VACUUM command alone controls vacuum cycle IDs. */ opaque = (BTPageOpaque) PageGetSpecialPointer(page); @@ -1310,7 +1310,7 @@ _bt_delitems_delete(Relation rel, Buffer buf, * Clear the BTP_HAS_GARBAGE page flag. * * This flag indicates the presence of LP_DEAD items on the page (though - * not reliably). Note that we only trust it with pg_upgrade'd + * not reliably). Note that we only rely on it with pg_upgrade'd * !heapkeyspace indexes. */ opaque->btpo_flags &= ~BTP_HAS_GARBAGE; @@ -1318,25 +1318,29 @@ _bt_delitems_delete(Relation rel, Buffer buf, MarkBufferDirty(buf); /* XLOG stuff */ - if (RelationNeedsWAL(rel)) + if (needswal) { XLogRecPtr recptr; xl_btree_delete xlrec_delete; xlrec_delete.latestRemovedXid = latestRemovedXid; xlrec_delete.ndeleted = ndeletable; + xlrec_delete.nupdated = nupdatable; XLogBeginInsert(); XLogRegisterBuffer(0, buf, REGBUF_STANDARD); XLogRegisterData((char *) &xlrec_delete, SizeOfBtreeDelete); - /* - * The deletable array is not in the buffer, but pretend that it is. - * When XLogInsert stores the whole buffer, the array need not be - * stored too. - */ - XLogRegisterBufData(0, (char *) deletable, - ndeletable * sizeof(OffsetNumber)); + if (ndeletable > 0) + XLogRegisterBufData(0, (char *) deletable, + ndeletable * sizeof(OffsetNumber)); + + if (nupdatable > 0) + { + XLogRegisterBufData(0, (char *) updatedoffsets, + nupdatable * sizeof(OffsetNumber)); + XLogRegisterBufData(0, updatedbuf, updatedbuflen); + } recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_DELETE); @@ -1344,83 +1348,313 @@ _bt_delitems_delete(Relation rel, Buffer buf, } END_CRIT_SECTION(); + + /* can't leak memory here */ + if (updatedbuf != NULL) + pfree(updatedbuf); + /* free tuples allocated within _bt_delitems_update() */ + for (int i = 0; i < nupdatable; i++) + pfree(updatable[i]->itup); } /* - * Get the latestRemovedXid from the table entries pointed to by the non-pivot - * tuples being deleted. + * Set up state needed to delete TIDs from posting list tuples via "updating" + * the tuple. Performs steps common to both _bt_delitems_vacuum and + * _bt_delitems_delete. These steps must take place before each function's + * critical section begins. + * + * updatabable and nupdatable are inputs, though note that we will use + * _bt_update_posting() to replace the original itup with a pointer to a final + * version in palloc()'d memory. Caller should free the tuples when its done. + * + * The first nupdatable entries from updatedoffsets are set to the page offset + * number for posting list tuples that caller updates. This is mostly useful + * because caller may need to WAL-log the page offsets (though we always do + * this for caller out of convenience). * - * This is a specialized version of index_compute_xid_horizon_for_tuples(). - * It's needed because btree tuples don't always store table TID using the - * standard index tuple header field. + * Returns buffer consisting of an array of xl_btree_update structs that + * describe the steps we perform here for caller (though only when needswal is + * true). Also sets *updatedbuflen to the final size of the buffer. This + * buffer is used by caller when WAL logging is required. */ -static TransactionId -_bt_xid_horizon(Relation rel, Relation heapRel, Page page, - OffsetNumber *deletable, int ndeletable) +static char * +_bt_delitems_update(BTVacuumPosting *updatable, int nupdatable, + OffsetNumber *updatedoffsets, Size *updatedbuflen, + bool needswal) { - TransactionId latestRemovedXid = InvalidTransactionId; - int spacenhtids; - int nhtids; - ItemPointer htids; - - /* Array will grow iff there are posting list tuples to consider */ - spacenhtids = ndeletable; - nhtids = 0; - htids = (ItemPointer) palloc(sizeof(ItemPointerData) * spacenhtids); - for (int i = 0; i < ndeletable; i++) + char *updatedbuf = NULL; + Size buflen = 0; + + /* Shouldn't be called unless there's something to do */ + Assert(nupdatable > 0); + + for (int i = 0; i < nupdatable; i++) { - ItemId itemid; - IndexTuple itup; + BTVacuumPosting vacposting = updatable[i]; + Size itemsz; - itemid = PageGetItemId(page, deletable[i]); - itup = (IndexTuple) PageGetItem(page, itemid); + /* Replace work area IndexTuple with updated version */ + _bt_update_posting(vacposting); - Assert(ItemIdIsDead(itemid)); - Assert(!BTreeTupleIsPivot(itup)); + /* Keep track of size of xl_btree_update for updatedbuf in passing */ + itemsz = SizeOfBtreeUpdate + vacposting->ndeletedtids * sizeof(uint16); + buflen += itemsz; - if (!BTreeTupleIsPosting(itup)) + /* Build updatedoffsets buffer in passing */ + updatedoffsets[i] = vacposting->updatedoffset; + } + + /* XLOG stuff */ + if (needswal) + { + Size offset = 0; + + /* Allocate, set final size for caller */ + updatedbuf = palloc(buflen); + *updatedbuflen = buflen; + for (int i = 0; i < nupdatable; i++) { - if (nhtids + 1 > spacenhtids) - { - spacenhtids *= 2; - htids = (ItemPointer) - repalloc(htids, sizeof(ItemPointerData) * spacenhtids); - } + BTVacuumPosting vacposting = updatable[i]; + Size itemsz; + xl_btree_update update; + + update.ndeletedtids = vacposting->ndeletedtids; + memcpy(updatedbuf + offset, &update.ndeletedtids, + SizeOfBtreeUpdate); + offset += SizeOfBtreeUpdate; - Assert(ItemPointerIsValid(&itup->t_tid)); - ItemPointerCopy(&itup->t_tid, &htids[nhtids]); - nhtids++; + itemsz = update.ndeletedtids * sizeof(uint16); + memcpy(updatedbuf + offset, vacposting->deletetids, itemsz); + offset += itemsz; } - else + } + + return updatedbuf; +} + +/* + * Comparator used by _bt_delitems_delete_check() to restore deltids array + * back to its original leaf-page-wise sort order + */ +static int +_bt_delitems_cmp(const void *a, const void *b) +{ + TM_IndexDelete *indexdelete1 = (TM_IndexDelete *) a; + TM_IndexDelete *indexdelete2 = (TM_IndexDelete *) b; + + if (indexdelete1->id > indexdelete2->id) + return 1; + if (indexdelete1->id < indexdelete2->id) + return -1; + + Assert(false); + + return 0; +} + +/* + * Try to delete item(s) from a btree leaf page during single-page cleanup. + * + * nbtree interface to table_index_delete_tuples(). Deletes a subset of index + * tuples from caller's deltids array: those whose TIDs are found safe to + * delete by the tableam (or already marked LP_DEAD in index, and so already + * known to be deletable by our simple index deletion caller). We physically + * delete index tuples from buf leaf page last of all (for index tuples where + * that is known to be safe following our table_index_delete_tuples() call). + * + * Simple index deletion caller only includes TIDs from index tuples marked + * LP_DEAD, as well as extra TIDs it found on the same leaf page that can be + * included without increasing the total number of distinct table blocks for + * the deletion operation as a whole. This approach often allows us to delete + * some extra index tuples that were practically free for tableam to check in + * passing (when they actually turn out to be safe to delete). It probably + * only makes sense for the tableam to go ahead with these extra checks when + * it is block-orientated (otherwise the checks probably won't be practically + * free, which we rely on). The tableam interface requires the tableam side + * to handle the problem, though, so this is okay (we as an index AM are free + * to make the simplifying assumption that all tableams must be block-based). + * + * Bottom-up index deletion caller provides all the TIDs from the leaf page, + * without expecting that tableam will check most of them. The tableam has + * considerable discretion around which entries/blocks it checks. Our role in + * costing the bottom-up deletion operation is strictly advisory. + * + * Note: Caller must have added deltids entries (i.e. entries that go in + * delstate's main array) in leaf-page-wise order: page offset number order, + * TID order among entries taken from the same posting list tuple (tiebreak on + * TID). This order is convenient to work with here. + * + * Note: We also rely on the id field of each deltids element "capturing" this + * original leaf-page-wise order. That is, we expect to be able to get back + * to the original leaf-page-wise order just by sorting deltids on the id + * field (tableam will sort deltids for its own reasons, so we'll need to put + * it back in leaf-page-wise order afterwards). + */ +void +_bt_delitems_delete_check(Relation rel, Buffer buf, Relation heapRel, + TM_IndexDeleteOp *delstate) +{ + Page page = BufferGetPage(buf); + TransactionId latestRemovedXid; + OffsetNumber postingidxoffnum = InvalidOffsetNumber; + int ndeletable = 0, + nupdatable = 0; + OffsetNumber deletable[MaxIndexTuplesPerPage]; + BTVacuumPosting updatable[MaxIndexTuplesPerPage]; + + /* Use tableam interface to determine which tuples to delete first */ + latestRemovedXid = table_index_delete_tuples(heapRel, delstate); + + /* Should not WAL-log latestRemovedXid unless it's required */ + if (!XLogStandbyInfoActive() || !RelationNeedsWAL(rel)) + latestRemovedXid = InvalidTransactionId; + + /* + * Construct a leaf-page-wise description of what _bt_delitems_delete() + * needs to do to physically delete index tuples from the page. + * + * Must sort deltids array to restore leaf-page-wise order (original order + * before call to tableam). This is the order that the loop expects. + * + * Note that deltids array might be a lot smaller now. It might even have + * no entries at all (with bottom-up deletion caller), in which case there + * is nothing left to do. + */ + qsort(delstate->deltids, delstate->ndeltids, sizeof(TM_IndexDelete), + _bt_delitems_cmp); + if (delstate->ndeltids == 0) + { + Assert(delstate->bottomup); + return; + } + + /* We definitely have to delete at least one index tuple (or one TID) */ + for (int i = 0; i < delstate->ndeltids; i++) + { + TM_IndexStatus *dstatus = delstate->status + delstate->deltids[i].id; + OffsetNumber idxoffnum = dstatus->idxoffnum; + ItemId itemid = PageGetItemId(page, idxoffnum); + IndexTuple itup = (IndexTuple) PageGetItem(page, itemid); + int nestedi, + nitem; + BTVacuumPosting vacposting; + + Assert(OffsetNumberIsValid(idxoffnum)); + + if (idxoffnum == postingidxoffnum) + { + /* + * This deltid entry is a TID from a posting list tuple that has + * already been completely processed + */ + Assert(BTreeTupleIsPosting(itup)); + Assert(ItemPointerCompare(BTreeTupleGetHeapTID(itup), + &delstate->deltids[i].tid) < 0); + Assert(ItemPointerCompare(BTreeTupleGetMaxHeapTID(itup), + &delstate->deltids[i].tid) >= 0); + continue; + } + + if (!BTreeTupleIsPosting(itup)) + { + /* Plain non-pivot tuple */ + Assert(ItemPointerEquals(&itup->t_tid, &delstate->deltids[i].tid)); + if (dstatus->knowndeletable) + deletable[ndeletable++] = idxoffnum; + continue; + } + + /* + * itup is a posting list tuple whose lowest deltids entry (which may + * or may not be for the first TID from itup) is considered here now. + * We should process all of the deltids entries for the posting list + * together now, though (not just the lowest). Remember to skip over + * later itup-related entries during later iterations of outermost + * loop. + */ + postingidxoffnum = idxoffnum; /* Remember work in outermost loop */ + nestedi = i; /* Initialize for first itup deltids entry */ + vacposting = NULL; /* Describes final action for itup */ + nitem = BTreeTupleGetNPosting(itup); + for (int p = 0; p < nitem; p++) { - int nposting = BTreeTupleGetNPosting(itup); + ItemPointer ptid = BTreeTupleGetPostingN(itup, p); + int ptidcmp = -1; - if (nhtids + nposting > spacenhtids) + /* + * This nested loop reuses work across ptid TIDs taken from itup. + * We take advantage of the fact that both itup's TIDs and deltids + * entries (within a single itup/posting list grouping) must both + * be in ascending TID order. + */ + for (; nestedi < delstate->ndeltids; nestedi++) { - spacenhtids = Max(spacenhtids * 2, nhtids + nposting); - htids = (ItemPointer) - repalloc(htids, sizeof(ItemPointerData) * spacenhtids); + TM_IndexDelete *tcdeltid = &delstate->deltids[nestedi]; + TM_IndexStatus *tdstatus = (delstate->status + tcdeltid->id); + + /* Stop once we get past all itup related deltids entries */ + Assert(tdstatus->idxoffnum >= idxoffnum); + if (tdstatus->idxoffnum != idxoffnum) + break; + + /* Skip past non-deletable itup related entries up front */ + if (!tdstatus->knowndeletable) + continue; + + /* Entry is first partial ptid match (or an exact match)? */ + ptidcmp = ItemPointerCompare(&tcdeltid->tid, ptid); + if (ptidcmp >= 0) + { + /* Greater than or equal (partial or exact) match... */ + break; + } } - for (int j = 0; j < nposting; j++) - { - ItemPointer htid = BTreeTupleGetPostingN(itup, j); + /* ...exact ptid match to a deletable deltids entry? */ + if (ptidcmp != 0) + continue; - Assert(ItemPointerIsValid(htid)); - ItemPointerCopy(htid, &htids[nhtids]); - nhtids++; + /* Exact match for deletable deltids entry -- ptid gets deleted */ + if (vacposting == NULL) + { + vacposting = palloc(offsetof(BTVacuumPostingData, deletetids) + + nitem * sizeof(uint16)); + vacposting->itup = itup; + vacposting->updatedoffset = idxoffnum; + vacposting->ndeletedtids = 0; } + vacposting->deletetids[vacposting->ndeletedtids++] = p; } - } - Assert(nhtids >= ndeletable); + /* Final decision on itup, a posting list tuple */ - latestRemovedXid = - table_compute_xid_horizon_for_tuples(heapRel, htids, nhtids); + if (vacposting == NULL) + { + /* No TIDs to delete from itup -- do nothing */ + } + else if (vacposting->ndeletedtids == nitem) + { + /* Straight delete of itup (to delete all TIDs) */ + deletable[ndeletable++] = idxoffnum; + /* Turns out we won't need granular information */ + pfree(vacposting); + } + else + { + /* Delete some (but not all) TIDs from itup */ + Assert(vacposting->ndeletedtids > 0 && + vacposting->ndeletedtids < nitem); + updatable[nupdatable++] = vacposting; + } + } - pfree(htids); + /* Physically delete tuples (or TIDs) using deletable (or updatable) */ + _bt_delitems_delete(rel, buf, latestRemovedXid, deletable, ndeletable, + updatable, nupdatable, heapRel); - return latestRemovedXid; + /* be tidy */ + for (int i = 0; i < nupdatable; i++) + pfree(updatable[i]); } /* diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index c50c4e8434ba6..289bd3c15daa0 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -209,7 +209,7 @@ btinsert(Relation rel, Datum *values, bool *isnull, itup = index_form_tuple(RelationGetDescr(rel), values, isnull); itup->t_tid = *ht_ctid; - result = _bt_doinsert(rel, itup, checkUnique, heapRel); + result = _bt_doinsert(rel, itup, checkUnique, indexUnchanged, heapRel); pfree(itup); @@ -1282,10 +1282,10 @@ btvacuumpage(BTVacState *vstate, BlockNumber scanblkno) * as long as the callback function only considers whether the * index tuple refers to pre-cutoff heap tuples that were * certainly already pruned away during VACUUM's initial heap - * scan by the time we get here. (XLOG_HEAP2_CLEANUP_INFO - * records produce conflicts using a latestRemovedXid value - * for the entire VACUUM, so there is no need to produce our - * own conflict now.) + * scan by the time we get here. (heapam's XLOG_HEAP2_CLEAN + * and XLOG_HEAP2_CLEANUP_INFO records produce conflicts using + * a latestRemovedXid value for the pointed-to heap tuples, so + * there is no need to produce our own conflict now.) * * Backends with snapshots acquired after a VACUUM starts but * before it finishes could have visibility cutoff with a diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c index c904fc8ef7bd3..c319b6c88b3ee 100644 --- a/src/backend/access/nbtree/nbtsort.c +++ b/src/backend/access/nbtree/nbtsort.c @@ -49,7 +49,6 @@ #include "access/parallel.h" #include "access/relscan.h" #include "access/table.h" -#include "access/tableam.h" #include "access/xact.h" #include "access/xlog.h" #include "access/xloginsert.h" diff --git a/src/backend/access/nbtree/nbtxlog.c b/src/backend/access/nbtree/nbtxlog.c index 45313d924c1fc..c1d578cc01609 100644 --- a/src/backend/access/nbtree/nbtxlog.c +++ b/src/backend/access/nbtree/nbtxlog.c @@ -556,6 +556,47 @@ btree_xlog_dedup(XLogReaderState *record) UnlockReleaseBuffer(buf); } +static void +btree_xlog_updates(Page page, OffsetNumber *updatedoffsets, + xl_btree_update *updates, int nupdated) +{ + BTVacuumPosting vacposting; + IndexTuple origtuple; + ItemId itemid; + Size itemsz; + + for (int i = 0; i < nupdated; i++) + { + itemid = PageGetItemId(page, updatedoffsets[i]); + origtuple = (IndexTuple) PageGetItem(page, itemid); + + vacposting = palloc(offsetof(BTVacuumPostingData, deletetids) + + updates->ndeletedtids * sizeof(uint16)); + vacposting->updatedoffset = updatedoffsets[i]; + vacposting->itup = origtuple; + vacposting->ndeletedtids = updates->ndeletedtids; + memcpy(vacposting->deletetids, + (char *) updates + SizeOfBtreeUpdate, + updates->ndeletedtids * sizeof(uint16)); + + _bt_update_posting(vacposting); + + /* Overwrite updated version of tuple */ + itemsz = MAXALIGN(IndexTupleSize(vacposting->itup)); + if (!PageIndexTupleOverwrite(page, updatedoffsets[i], + (Item) vacposting->itup, itemsz)) + elog(PANIC, "failed to update partially dead item"); + + pfree(vacposting->itup); + pfree(vacposting); + + /* advance to next xl_btree_update from array */ + updates = (xl_btree_update *) + ((char *) updates + SizeOfBtreeUpdate + + updates->ndeletedtids * sizeof(uint16)); + } +} + static void btree_xlog_vacuum(XLogReaderState *record) { @@ -589,41 +630,7 @@ btree_xlog_vacuum(XLogReaderState *record) xlrec->nupdated * sizeof(OffsetNumber)); - for (int i = 0; i < xlrec->nupdated; i++) - { - BTVacuumPosting vacposting; - IndexTuple origtuple; - ItemId itemid; - Size itemsz; - - itemid = PageGetItemId(page, updatedoffsets[i]); - origtuple = (IndexTuple) PageGetItem(page, itemid); - - vacposting = palloc(offsetof(BTVacuumPostingData, deletetids) + - updates->ndeletedtids * sizeof(uint16)); - vacposting->updatedoffset = updatedoffsets[i]; - vacposting->itup = origtuple; - vacposting->ndeletedtids = updates->ndeletedtids; - memcpy(vacposting->deletetids, - (char *) updates + SizeOfBtreeUpdate, - updates->ndeletedtids * sizeof(uint16)); - - _bt_update_posting(vacposting); - - /* Overwrite updated version of tuple */ - itemsz = MAXALIGN(IndexTupleSize(vacposting->itup)); - if (!PageIndexTupleOverwrite(page, updatedoffsets[i], - (Item) vacposting->itup, itemsz)) - elog(PANIC, "failed to update partially dead item"); - - pfree(vacposting->itup); - pfree(vacposting); - - /* advance to next xl_btree_update from array */ - updates = (xl_btree_update *) - ((char *) updates + SizeOfBtreeUpdate + - updates->ndeletedtids * sizeof(uint16)); - } + btree_xlog_updates(page, updatedoffsets, updates, xlrec->nupdated); } if (xlrec->ndeleted > 0) @@ -675,7 +682,22 @@ btree_xlog_delete(XLogReaderState *record) page = (Page) BufferGetPage(buffer); - PageIndexMultiDelete(page, (OffsetNumber *) ptr, xlrec->ndeleted); + if (xlrec->nupdated > 0) + { + OffsetNumber *updatedoffsets; + xl_btree_update *updates; + + updatedoffsets = (OffsetNumber *) + (ptr + xlrec->ndeleted * sizeof(OffsetNumber)); + updates = (xl_btree_update *) ((char *) updatedoffsets + + xlrec->nupdated * + sizeof(OffsetNumber)); + + btree_xlog_updates(page, updatedoffsets, updates, xlrec->nupdated); + } + + if (xlrec->ndeleted > 0) + PageIndexMultiDelete(page, (OffsetNumber *) ptr, xlrec->ndeleted); /* Mark the page as not containing any LP_DEAD items */ opaque = (BTPageOpaque) PageGetSpecialPointer(page); diff --git a/src/backend/access/rmgrdesc/nbtdesc.c b/src/backend/access/rmgrdesc/nbtdesc.c index 4c4af9fce012c..6e0d6a2b729e8 100644 --- a/src/backend/access/rmgrdesc/nbtdesc.c +++ b/src/backend/access/rmgrdesc/nbtdesc.c @@ -63,8 +63,8 @@ btree_desc(StringInfo buf, XLogReaderState *record) { xl_btree_delete *xlrec = (xl_btree_delete *) rec; - appendStringInfo(buf, "latestRemovedXid %u; ndeleted %u", - xlrec->latestRemovedXid, xlrec->ndeleted); + appendStringInfo(buf, "latestRemovedXid %u; ndeleted %u; nupdated %u", + xlrec->latestRemovedXid, xlrec->ndeleted, xlrec->nupdated); break; } case XLOG_BTREE_MARK_PAGE_HALFDEAD: diff --git a/src/backend/access/table/tableamapi.c b/src/backend/access/table/tableamapi.c index d5a859ea88213..325ecdc122914 100644 --- a/src/backend/access/table/tableamapi.c +++ b/src/backend/access/table/tableamapi.c @@ -66,7 +66,7 @@ GetTableAmRoutine(Oid amhandler) Assert(routine->tuple_tid_valid != NULL); Assert(routine->tuple_get_latest_tid != NULL); Assert(routine->tuple_satisfies_snapshot != NULL); - Assert(routine->compute_xid_horizon_for_tuples != NULL); + Assert(routine->index_delete_tuples != NULL); Assert(routine->tuple_insert != NULL); diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h index 95cb1e346b2d6..d96a47b1cec13 100644 --- a/src/include/access/heapam.h +++ b/src/include/access/heapam.h @@ -166,9 +166,8 @@ extern void simple_heap_delete(Relation relation, ItemPointer tid); extern void simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup); -extern TransactionId heap_compute_xid_horizon_for_tuples(Relation rel, - ItemPointerData *items, - int nitems); +extern TransactionId heap_index_delete_tuples(Relation rel, + TM_IndexDeleteOp *delstate); /* in heap/pruneheap.c */ struct GlobalVisState; diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h index 7f8489aac2a00..cad4f2bdeb9ab 100644 --- a/src/include/access/nbtree.h +++ b/src/include/access/nbtree.h @@ -17,6 +17,7 @@ #include "access/amapi.h" #include "access/itup.h" #include "access/sdir.h" +#include "access/tableam.h" #include "access/xlogreader.h" #include "catalog/pg_am_d.h" #include "catalog/pg_index.h" @@ -168,7 +169,7 @@ typedef struct BTMetaPageData /* * MaxTIDsPerBTreePage is an upper bound on the number of heap TIDs tuples * that may be stored on a btree leaf page. It is used to size the - * per-page temporary buffers used by index scans. + * per-page temporary buffers. * * Note: we don't bother considering per-tuple overheads here to keep * things simple (value is based on how many elements a single array of @@ -766,8 +767,9 @@ typedef struct BTDedupStateData typedef BTDedupStateData *BTDedupState; /* - * BTVacuumPostingData is state that represents how to VACUUM a posting list - * tuple when some (though not all) of its TIDs are to be deleted. + * BTVacuumPostingData is state that represents how to VACUUM (or delete) a + * posting list tuple when some (though not all) of its TIDs are to be + * deleted. * * Convention is that itup field is the original posting list tuple on input, * and palloc()'d final tuple used to overwrite existing tuple on output. @@ -1031,6 +1033,8 @@ extern void _bt_parallel_advance_array_keys(IndexScanDesc scan); extern void _bt_dedup_pass(Relation rel, Buffer buf, Relation heapRel, IndexTuple newitem, Size newitemsz, bool checkingunique); +extern bool _bt_bottomupdel_pass(Relation rel, Buffer buf, Relation heapRel, + Size newitemsz); extern void _bt_dedup_start_pending(BTDedupState state, IndexTuple base, OffsetNumber baseoff); extern bool _bt_dedup_save_htid(BTDedupState state, IndexTuple itup); @@ -1045,7 +1049,8 @@ extern IndexTuple _bt_swap_posting(IndexTuple newitem, IndexTuple oposting, * prototypes for functions in nbtinsert.c */ extern bool _bt_doinsert(Relation rel, IndexTuple itup, - IndexUniqueCheck checkUnique, Relation heapRel); + IndexUniqueCheck checkUnique, bool indexUnchanged, + Relation heapRel); extern void _bt_finish_split(Relation rel, Buffer lbuf, BTStack stack); extern Buffer _bt_getstackbuf(Relation rel, BTStack stack, BlockNumber child); @@ -1083,9 +1088,9 @@ extern bool _bt_page_recyclable(Page page); extern void _bt_delitems_vacuum(Relation rel, Buffer buf, OffsetNumber *deletable, int ndeletable, BTVacuumPosting *updatable, int nupdatable); -extern void _bt_delitems_delete(Relation rel, Buffer buf, - OffsetNumber *deletable, int ndeletable, - Relation heapRel); +extern void _bt_delitems_delete_check(Relation rel, Buffer buf, + Relation heapRel, + TM_IndexDeleteOp *delstate); extern uint32 _bt_pagedel(Relation rel, Buffer leafbuf, TransactionId *oldestBtpoXact); diff --git a/src/include/access/nbtxlog.h b/src/include/access/nbtxlog.h index f5d3e9f5e09c0..7ae5c98c2b823 100644 --- a/src/include/access/nbtxlog.h +++ b/src/include/access/nbtxlog.h @@ -176,24 +176,6 @@ typedef struct xl_btree_dedup #define SizeOfBtreeDedup (offsetof(xl_btree_dedup, nintervals) + sizeof(uint16)) -/* - * This is what we need to know about delete of individual leaf index tuples. - * The WAL record can represent deletion of any number of index tuples on a - * single index page when *not* executed by VACUUM. Deletion of a subset of - * the TIDs within a posting list tuple is not supported. - * - * Backup Blk 0: index page - */ -typedef struct xl_btree_delete -{ - TransactionId latestRemovedXid; - uint32 ndeleted; - - /* DELETED TARGET OFFSET NUMBERS FOLLOW */ -} xl_btree_delete; - -#define SizeOfBtreeDelete (offsetof(xl_btree_delete, ndeleted) + sizeof(uint32)) - /* * This is what we need to know about page reuse within btree. This record * only exists to generate a conflict point for Hot Standby. @@ -211,31 +193,30 @@ typedef struct xl_btree_reuse_page #define SizeOfBtreeReusePage (sizeof(xl_btree_reuse_page)) /* - * This is what we need to know about which TIDs to remove from an individual - * posting list tuple during vacuuming. An array of these may appear at the - * end of xl_btree_vacuum records. - */ -typedef struct xl_btree_update -{ - uint16 ndeletedtids; - - /* POSTING LIST uint16 OFFSETS TO A DELETED TID FOLLOW */ -} xl_btree_update; - -#define SizeOfBtreeUpdate (offsetof(xl_btree_update, ndeletedtids) + sizeof(uint16)) - -/* - * This is what we need to know about a VACUUM of a leaf page. The WAL record - * can represent deletion of any number of index tuples on a single index page - * when executed by VACUUM. It can also support "updates" of index tuples, - * which is how deletes of a subset of TIDs contained in an existing posting - * list tuple are implemented. (Updates are only used when there will be some - * remaining TIDs once VACUUM finishes; otherwise the posting list tuple can - * just be deleted). + * xl_btree_vacuum and xl_btree_delete records describe deletion of index + * tuples on a leaf page. The former variant is used by VACUUM, while the + * latter variant is used by the ad-hoc deletions that sometimes take place + * when btinsert() is called. + * + * The records are very similar. The only difference is that xl_btree_delete + * has to include a latestRemovedXid field to generate recovery conflicts. + * (VACUUM operations can just rely on earlier conflicts generated during + * pruning of the table whose TIDs the to-be-deleted index tuples point to. + * There are also small differences between each REDO routine that we don't go + * into here.) + * + * xl_btree_vacuum and xl_btree_delete both represent deletion of any number + * of index tuples on a single leaf page using page offset numbers. Both also + * support "updates" of index tuples, which is how deletes of a subset of TIDs + * contained in an existing posting list tuple are implemented. * * Updated posting list tuples are represented using xl_btree_update metadata. - * The REDO routine uses each xl_btree_update (plus its corresponding original - * index tuple from the target leaf page) to generate the final updated tuple. + * The REDO routines each use the xl_btree_update entries (plus each + * corresponding original index tuple from the target leaf page) to generate + * the final updated tuple. + * + * Updates are only used when there will be some remaining TIDs left by the + * REDO routine. Otherwise the posting list tuple just gets deleted outright. */ typedef struct xl_btree_vacuum { @@ -244,11 +225,39 @@ typedef struct xl_btree_vacuum /* DELETED TARGET OFFSET NUMBERS FOLLOW */ /* UPDATED TARGET OFFSET NUMBERS FOLLOW */ - /* UPDATED TUPLES METADATA ARRAY FOLLOWS */ + /* UPDATED TUPLES METADATA (xl_btree_update) ARRAY FOLLOWS */ } xl_btree_vacuum; #define SizeOfBtreeVacuum (offsetof(xl_btree_vacuum, nupdated) + sizeof(uint16)) +typedef struct xl_btree_delete +{ + TransactionId latestRemovedXid; + uint16 ndeleted; + uint16 nupdated; + + /* DELETED TARGET OFFSET NUMBERS FOLLOW */ + /* UPDATED TARGET OFFSET NUMBERS FOLLOW */ + /* UPDATED TUPLES METADATA (xl_btree_update) ARRAY FOLLOWS */ +} xl_btree_delete; + +#define SizeOfBtreeDelete (offsetof(xl_btree_delete, nupdated) + sizeof(uint16)) + +/* + * The offsets that appear in xl_btree_update metadata are offsets into the + * original posting list from tuple, not page offset numbers. These are + * 0-based. The page offset number for the original posting list tuple comes + * from the main xl_btree_vacuum/xl_btree_delete record. + */ +typedef struct xl_btree_update +{ + uint16 ndeletedtids; + + /* POSTING LIST uint16 OFFSETS TO A DELETED TID FOLLOW */ +} xl_btree_update; + +#define SizeOfBtreeUpdate (offsetof(xl_btree_update, ndeletedtids) + sizeof(uint16)) + /* * This is what we need to know about marking an empty subtree for deletion. * The target identifies the tuple removed from the parent page (note that we diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h index c2357a72e4864..33bffb6815b46 100644 --- a/src/include/access/tableam.h +++ b/src/include/access/tableam.h @@ -128,6 +128,106 @@ typedef struct TM_FailureData bool traversed; } TM_FailureData; +/* + * State used when calling table_index_delete_tuples(). + * + * Represents the status of table tuples, referenced by table TID and taken by + * index AM from index tuples. State consists of high level parameters of the + * deletion operation, plus two mutable palloc()'d arrays for information + * about the status of individual table tuples. These are conceptually one + * single array. Using two arrays keeps the TM_IndexDelete struct small, + * which makes sorting the first array (the deltids array) fast. + * + * Some index AM callers perform simple index tuple deletion (by specifying + * bottomup = false), and include only known-dead deltids. These known-dead + * entries are all marked knowndeletable = true directly (typically these are + * TIDs from LP_DEAD-marked index tuples), but that isn't strictly required. + * + * Callers that specify bottomup = true are "bottom-up index deletion" + * callers. The considerations for the tableam are more subtle with these + * callers because they ask the tableam to perform highly speculative work, + * and might only expect the tableam to check a small fraction of all entries. + * Caller is not allowed to specify knowndeletable = true for any entry + * because everything is highly speculative. Bottom-up caller provides + * context and hints to tableam -- see comments below for details on how index + * AMs and tableams should coordinate during bottom-up index deletion. + * + * Simple index deletion callers may ask the tableam to perform speculative + * work, too. This is a little like bottom-up deletion, but not too much. + * The tableam will only perform speculative work when it's practically free + * to do so in passing for simple deletion caller (while always performing + * whatever work is is needed to enable knowndeletable/LP_DEAD index tuples to + * be deleted within index AM). This is the real reason why it's possible for + * simple index deletion caller to specify knowndeletable = false up front + * (this means "check if it's possible for me to delete corresponding index + * tuple when it's cheap to do so in passing"). The index AM should only + * include "extra" entries for index tuples whose TIDs point to a table block + * that tableam is expected to have to visit anyway (in the event of a block + * orientated tableam). The tableam isn't strictly obligated to check these + * "extra" TIDs, but a block-based AM should always manage to do so in + * practice. + * + * The final contents of the deltids/status arrays are interesting to callers + * that ask tableam to perform speculative work (i.e. when _any_ items have + * knowndeletable set to false up front). These index AM callers will + * naturally need to consult final state to determine which index tuples are + * in fact deletable. + * + * The index AM can keep track of which index tuple relates to which deltid by + * setting idxoffnum (and/or relying on each entry being uniquely identifiable + * using tid), which is important when the final contents of the array will + * need to be interpreted -- the array can shrink from initial size after + * tableam processing and/or have entries in a new order (tableam may sort + * deltids array for its own reasons). Bottom-up callers may find that final + * ndeltids is 0 on return from call to tableam, in which case no index tuple + * deletions are possible. Simple deletion callers can rely on any entries + * they know to be deletable appearing in the final array as deletable. + */ +typedef struct TM_IndexDelete +{ + ItemPointerData tid; /* table TID from index tuple */ + int16 id; /* Offset into TM_IndexStatus array */ +} TM_IndexDelete; + +typedef struct TM_IndexStatus +{ + OffsetNumber idxoffnum; /* Index am page offset number */ + bool knowndeletable; /* Currently known to be deletable? */ + + /* Bottom-up index deletion specific fields follow */ + bool promising; /* Promising (duplicate) index tuple? */ + int16 freespace; /* Space freed in index if deleted */ +} TM_IndexStatus; + +/* + * Index AM/tableam coordination is central to the design of bottom-up index + * deletion. The index AM provides hints about where to look to the tableam + * by marking some entries as "promising". Index AM does this with duplicate + * index tuples that are strongly suspected to be old versions left behind by + * UPDATEs that did not logically modify indexed values. Index AM may find it + * helpful to only mark entries as promising when they're thought to have been + * affected by such an UPDATE in the recent past. + * + * Bottom-up index deletion casts a wide net at first, usually by including + * all TIDs on a target index page. It is up to the tableam to worry about + * the cost of checking transaction status information. The tableam is in + * control, but needs careful guidance from the index AM. Index AM requests + * that bottomupfreespace target be met, while tableam measures progress + * towards that goal by tallying the per-entry freespace value for known + * deletable entries. (All !bottomup callers can just set these space related + * fields to zero.) + */ +typedef struct TM_IndexDeleteOp +{ + bool bottomup; /* Bottom-up (not simple) deletion? */ + int bottomupfreespace; /* Bottom-up space target */ + + /* Mutable per-TID information follows (index AM initializes entries) */ + int ndeltids; /* Current # of deltids/status elements */ + TM_IndexDelete *deltids; + TM_IndexStatus *status; +} TM_IndexDeleteOp; + /* "options" flag bits for table_tuple_insert */ /* TABLE_INSERT_SKIP_WAL was 0x0001; RelationNeedsWAL() now governs */ #define TABLE_INSERT_SKIP_FSM 0x0002 @@ -342,10 +442,9 @@ typedef struct TableAmRoutine TupleTableSlot *slot, Snapshot snapshot); - /* see table_compute_xid_horizon_for_tuples() */ - TransactionId (*compute_xid_horizon_for_tuples) (Relation rel, - ItemPointerData *items, - int nitems); + /* see table_index_delete_tuples() */ + TransactionId (*index_delete_tuples) (Relation rel, + TM_IndexDeleteOp *delstate); /* ------------------------------------------------------------------------ @@ -1122,16 +1221,23 @@ table_tuple_satisfies_snapshot(Relation rel, TupleTableSlot *slot, } /* - * Compute the newest xid among the tuples pointed to by items. This is used - * to compute what snapshots to conflict with when replaying WAL records for - * page-level index vacuums. + * Determine which index tuples are safe to delete based on their table TID. + * + * Determines which entries from index AM caller's TM_IndexDeleteOp state + * point to vacuumable table tuples. Entries that are found by tableam to be + * vacuumable are naturally safe for index AM to delete, and so get directly + * marked as deletable. See comments above TM_IndexDelete and comments above + * TM_IndexDeleteOp for full details. + * + * Returns a latestRemovedXid transaction ID that caller generally places in + * its index deletion WAL record. This might be used during subsequent REDO + * of the WAL record when in Hot Standby mode -- a recovery conflict for the + * index deletion operation might be required on the standby. */ static inline TransactionId -table_compute_xid_horizon_for_tuples(Relation rel, - ItemPointerData *items, - int nitems) +table_index_delete_tuples(Relation rel, TM_IndexDeleteOp *delstate) { - return rel->rd_tableam->compute_xid_horizon_for_tuples(rel, items, nitems); + return rel->rd_tableam->index_delete_tuples(rel, delstate); } diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h index 9585ad17b3cfb..224cae0246fe1 100644 --- a/src/include/access/xlog_internal.h +++ b/src/include/access/xlog_internal.h @@ -31,7 +31,7 @@ /* * Each page of XLOG file has a header like this: */ -#define XLOG_PAGE_MAGIC 0xD108 /* can be used as WAL version indicator */ +#define XLOG_PAGE_MAGIC 0xD109 /* can be used as WAL version indicator */ typedef struct XLogPageHeaderData { From 06ed235adeb621a73cafd6ab35fa2405b3177329 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 13 Jan 2021 13:30:04 -0500 Subject: [PATCH 091/240] Doc: clarify behavior of back-half options in pg_dump. Options that change how the archive data is converted to SQL text are ignored when dumping to archive formats. The documentation previously said "not meaningful", which is not helpful. Discussion: https://postgr.es/m/161052021249.12228.9598689907884726185@wrigleys.postgresql.org --- doc/src/sgml/ref/pg_dump.sgml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/doc/src/sgml/ref/pg_dump.sgml b/doc/src/sgml/ref/pg_dump.sgml index dcb25dc3cd43f..bcbb7a25fb735 100644 --- a/doc/src/sgml/ref/pg_dump.sgml +++ b/doc/src/sgml/ref/pg_dump.sgml @@ -176,8 +176,8 @@ PostgreSQL documentation - This option is only meaningful for the plain-text format. For - the archive formats, you can specify the option when you + This option is ignored when emitting an archive (non-text) output + file. For the archive formats, you can specify the option when you call pg_restore. @@ -208,8 +208,8 @@ PostgreSQL documentation - This option is only meaningful for the plain-text format. For - the archive formats, you can specify the option when you + This option is ignored when emitting an archive (non-text) output + file. For the archive formats, you can specify the option when you call pg_restore. @@ -456,8 +456,8 @@ PostgreSQL documentation - This option is only meaningful for the plain-text format. For - the archive formats, you can specify the option when you + This option is ignored when emitting an archive (non-text) output + file. For the archive formats, you can specify the option when you call pg_restore. @@ -693,8 +693,8 @@ PostgreSQL documentation - This option is only meaningful for the plain-text format. For - the archive formats, you can specify the option when you + This option is ignored when emitting an archive (non-text) output + file. For the archive formats, you can specify the option when you call pg_restore. @@ -924,8 +924,8 @@ PostgreSQL documentation - This option is only meaningful for the plain-text format. For - the archive formats, you can specify the option when you + This option is ignored when emitting an archive (non-text) output + file. For the archive formats, you can specify the option when you call pg_restore. From 5abca4b1cd7193d6a5c8235c97eb240312190bcb Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Wed, 13 Jan 2021 20:57:21 +0200 Subject: [PATCH 092/240] Fix test failure with wal_level=minimal. The newly-added gist pageinspect test prints the LSNs of GiST pages, expecting them all to be 1 (GistBuildLSN). But with wal_level=minimal, they got updated by the whole-relation WAL-logging at commit. Fix by wrapping the problematic tests in the same transaction with the CREATE INDEX. Per buildfarm failure on thorntail. Discussion: https://www.postgresql.org/message-id/3B4F97E5-40FB-4142-8CAA-B301CDFBF982%40iki.fi --- contrib/pageinspect/expected/gist.out | 10 ++++++++++ contrib/pageinspect/sql/gist.sql | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/contrib/pageinspect/expected/gist.out b/contrib/pageinspect/expected/gist.out index 508f5adb550b5..5f7d8cea71b83 100644 --- a/contrib/pageinspect/expected/gist.out +++ b/contrib/pageinspect/expected/gist.out @@ -1,3 +1,12 @@ +-- The gist_page_opaque_info() function prints the page's LSN. Normally, +-- that's constant 1 (GistBuildLSN) on every page of a freshly built GiST +-- index. But with wal_level=minimal, the whole relation is dumped to WAL at +-- the end of the transaction if it's smaller than wal_skip_threshold, which +-- updates the LSNs. Wrap the tests on gist_page_opaque_info() in the +-- same transaction with the CREATE INDEX so that we see the LSNs before +-- they are possibly overwritten at end of transaction. +BEGIN; +-- Create a test table and GiST index. CREATE TABLE test_gist AS SELECT point(i,i) p, i::text t FROM generate_series(1,1000) i; CREATE INDEX test_gist_idx ON test_gist USING gist (p); @@ -20,6 +29,7 @@ SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 2)); 0/1 | 0/0 | 1 | {leaf} (1 row) +COMMIT; SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 0), 'test_gist_idx'); itemoffset | ctid | itemlen | keys ------------+-----------+---------+------------------- diff --git a/contrib/pageinspect/sql/gist.sql b/contrib/pageinspect/sql/gist.sql index e6f6e42a5ef54..1560d1e15c315 100644 --- a/contrib/pageinspect/sql/gist.sql +++ b/contrib/pageinspect/sql/gist.sql @@ -1,3 +1,13 @@ +-- The gist_page_opaque_info() function prints the page's LSN. Normally, +-- that's constant 1 (GistBuildLSN) on every page of a freshly built GiST +-- index. But with wal_level=minimal, the whole relation is dumped to WAL at +-- the end of the transaction if it's smaller than wal_skip_threshold, which +-- updates the LSNs. Wrap the tests on gist_page_opaque_info() in the +-- same transaction with the CREATE INDEX so that we see the LSNs before +-- they are possibly overwritten at end of transaction. +BEGIN; + +-- Create a test table and GiST index. CREATE TABLE test_gist AS SELECT point(i,i) p, i::text t FROM generate_series(1,1000) i; CREATE INDEX test_gist_idx ON test_gist USING gist (p); @@ -7,6 +17,8 @@ SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 0)); SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 1)); SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 2)); +COMMIT; + SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 0), 'test_gist_idx'); SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 1), 'test_gist_idx') LIMIT 5; From c21ea4d53e9404279273da800daa49b7b9a5e81e Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 13 Jan 2021 14:52:49 -0500 Subject: [PATCH 093/240] Disallow a digit as the first character of a variable name in pgbench. The point of this restriction is to avoid trying to substitute variables into timestamp literal values, which may contain strings like '12:34'. There is a good deal more that should be done to reduce pgbench's tendency to substitute where it shouldn't. But this is sufficient to solve the case complained of by Jaime Soler, and it's simple enough to back-patch. Back-patch to v11; before commit 9d36a3866, pgbench had a slightly different definition of what a variable name is, and anyway it seems unwise to change long-stable branches for this. Fabien Coelho Discussion: https://postgr.es/m/alpine.DEB.2.22.394.2006291740420.805678@pseudo --- doc/src/sgml/ref/pgbench.sgml | 2 +- src/bin/pgbench/pgbench.c | 32 +++++++++++++++++++++++--------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/doc/src/sgml/ref/pgbench.sgml b/doc/src/sgml/ref/pgbench.sgml index b03d0cc50f5b5..faa7c26b0a1fd 100644 --- a/doc/src/sgml/ref/pgbench.sgml +++ b/doc/src/sgml/ref/pgbench.sgml @@ -1008,7 +1008,7 @@ pgbench options d There is a simple variable-substitution facility for script files. Variable names must consist of letters (including non-Latin letters), - digits, and underscores. + digits, and underscores, with the first character not being a digit. Variables can be set by the command-line option, explained above, or by the meta commands explained below. In addition to any variables preset by command-line options, diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index 99b06a5e05038..f7da3e1f62692 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -1375,6 +1375,7 @@ makeVariableValue(Variable *var) * "src/bin/pgbench/exprscan.l". Also see parseVariable(), below. * * Note: this static function is copied from "src/bin/psql/variables.c" + * but changed to disallow variable names starting with a digit. */ static bool valid_variable_name(const char *name) @@ -1385,6 +1386,15 @@ valid_variable_name(const char *name) if (*ptr == '\0') return false; + /* must not start with [0-9] */ + if (IS_HIGHBIT_SET(*ptr) || + strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" + "_", *ptr) != NULL) + ptr++; + else + return false; + + /* remaining characters can include [0-9] */ while (*ptr) { if (IS_HIGHBIT_SET(*ptr) || @@ -1505,23 +1515,27 @@ putVariableInt(CState *st, const char *context, char *name, int64 value) * * "sql" points at a colon. If what follows it looks like a valid * variable name, return a malloc'd string containing the variable name, - * and set *eaten to the number of characters consumed. + * and set *eaten to the number of characters consumed (including the colon). * Otherwise, return NULL. */ static char * parseVariable(const char *sql, int *eaten) { - int i = 0; + int i = 1; /* starting at 1 skips the colon */ char *name; - do - { + /* keep this logic in sync with valid_variable_name() */ + if (IS_HIGHBIT_SET(sql[i]) || + strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" + "_", sql[i]) != NULL) + i++; + else + return NULL; + + while (IS_HIGHBIT_SET(sql[i]) || + strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" + "_0123456789", sql[i]) != NULL) i++; - } while (IS_HIGHBIT_SET(sql[i]) || - strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" - "_0123456789", sql[i]) != NULL); - if (i == 1) - return NULL; /* no valid variable name chars */ name = pg_malloc(i); memcpy(name, &sql[1], i - 1); From 93c39f987e9c019cd28c450ece8a621b2d8ce28a Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Wed, 13 Jan 2021 17:55:41 -0300 Subject: [PATCH 094/240] Call out vacuum considerations in create index docs Backpatch to pg12, which is as far as it goes without conflicts. Author: James Coleman Reviewed-by: "David G. Johnston" Discussion: https://postgr.es/m/CAAaqYe9oEfbz7AxXq7OX+FFVi5w5p1e_Of8ON8ZnKO9QqBfmjg@mail.gmail.com --- doc/src/sgml/ref/create_index.sgml | 6 ++++++ doc/src/sgml/ref/reindex.sgml | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/doc/src/sgml/ref/create_index.sgml b/doc/src/sgml/ref/create_index.sgml index 6fff02d824302..a5271a9f8f2e2 100644 --- a/doc/src/sgml/ref/create_index.sgml +++ b/doc/src/sgml/ref/create_index.sgml @@ -851,6 +851,12 @@ Indexes: to remove an index. + + Like any long-running transaction, CREATE INDEX on a + table can affect which tuples can be removed by concurrent + VACUUM on any other table. + + Prior releases of PostgreSQL also had an R-tree index method. This method has been removed because diff --git a/doc/src/sgml/ref/reindex.sgml b/doc/src/sgml/ref/reindex.sgml index 6e1cf067130c9..627b36300c984 100644 --- a/doc/src/sgml/ref/reindex.sgml +++ b/doc/src/sgml/ref/reindex.sgml @@ -436,6 +436,12 @@ Indexes: CONCURRENTLY cannot. + + Like any long-running transaction, REINDEX on a table + can affect which tuples can be removed by concurrent + VACUUM on any other table. + + REINDEX SYSTEM does not support CONCURRENTLY since system catalogs cannot be reindexed From dce62490818170b6479dfe08a28aae4bcdf7cc2d Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 13 Jan 2021 15:59:57 -0500 Subject: [PATCH 095/240] Doc, more or less: uncomment tutorial example that was fixed long ago. Reverts a portion of commit 344190b7e. Apparently, back in the twentieth century we had some issues with multi-statement SQL functions, but they've worked fine for a long time. Daniel Westermann Discussion: https://postgr.es/m/GVAP278MB04242DCBF5E31F528D53FA18D2A90@GVAP278MB0424.CHEP278.PROD.OUTLOOK.COM --- src/tutorial/funcs.source | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/tutorial/funcs.source b/src/tutorial/funcs.source index 7bbda599a6369..542b5c81ec951 100644 --- a/src/tutorial/funcs.source +++ b/src/tutorial/funcs.source @@ -99,24 +99,21 @@ SELECT name(high_pay()) AS overpaid; ----------------------------- -- Creating SQL Functions with multiple SQL statements -- you can also create functions that do more than just a SELECT. --- --- 14MAR99 Clark Evans: Does not quite work, commented out for now. --- ----------------------------- -- you may have noticed that Andy has a negative salary. We'll create a -- function that removes employees with negative salaries. --- --- SELECT * FROM EMP; --- --- CREATE FUNCTION clean_EMP () RETURNS integer --- AS 'DELETE FROM EMP WHERE EMP.salary <= 0; --- SELECT 1 AS ignore_this' --- LANGUAGE SQL; --- --- SELECT clean_EMP(); --- --- SELECT * FROM EMP; + +SELECT * FROM EMP; + +CREATE FUNCTION clean_EMP () RETURNS integer + AS 'DELETE FROM EMP WHERE EMP.salary <= 0; + SELECT 1 AS ignore_this' + LANGUAGE SQL; + +SELECT clean_EMP(); + +SELECT * FROM EMP; ----------------------------- From 8b411b8ff41566a1aa601d1f05aeebbebbdb4a54 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 13 Jan 2021 16:14:38 -0500 Subject: [PATCH 096/240] Run reformat-dat-files to declutter the catalog data files. Things had gotten pretty messy here, apparently mostly but not entirely the fault of the multirange patch. No functional changes. --- src/include/catalog/pg_aggregate.dat | 3 +- src/include/catalog/pg_amop.dat | 4 +- src/include/catalog/pg_amproc.dat | 15 ++- src/include/catalog/pg_cast.dat | 29 +++-- src/include/catalog/pg_collation.dat | 3 +- src/include/catalog/pg_opclass.dat | 17 +-- src/include/catalog/pg_operator.dat | 72 ++++++----- src/include/catalog/pg_proc.dat | 183 +++++++++++++++------------ src/include/catalog/pg_range.dat | 30 ++--- src/include/catalog/pg_type.dat | 47 ++++--- 10 files changed, 229 insertions(+), 174 deletions(-) diff --git a/src/include/catalog/pg_aggregate.dat b/src/include/catalog/pg_aggregate.dat index 40c6616f8fb32..5c1f96225143b 100644 --- a/src/include/catalog/pg_aggregate.dat +++ b/src/include/catalog/pg_aggregate.dat @@ -544,7 +544,8 @@ aggcombinefn => 'range_intersect_agg_transfn', aggtranstype => 'anyrange' }, { aggfnoid => 'range_intersect_agg(anymultirange)', aggtransfn => 'multirange_intersect_agg_transfn', - aggcombinefn => 'multirange_intersect_agg_transfn', aggtranstype => 'anymultirange' }, + aggcombinefn => 'multirange_intersect_agg_transfn', + aggtranstype => 'anymultirange' }, { aggfnoid => 'range_agg(anyrange)', aggtransfn => 'range_agg_transfn', aggfinalfn => 'range_agg_finalfn', aggfinalextra => 't', aggtranstype => 'internal' }, diff --git a/src/include/catalog/pg_amop.dat b/src/include/catalog/pg_amop.dat index 9339971e77c6a..0f7ff63669028 100644 --- a/src/include/catalog/pg_amop.dat +++ b/src/include/catalog/pg_amop.dat @@ -981,8 +981,8 @@ # record_ops { amopfamily => 'hash/record_ops', amoplefttype => 'record', - amoprighttype => 'record', amopstrategy => '1', - amopopr => '=(record,record)', amopmethod => 'hash' }, + amoprighttype => 'record', amopstrategy => '1', amopopr => '=(record,record)', + amopmethod => 'hash' }, # text_ops { amopfamily => 'hash/text_ops', amoplefttype => 'text', diff --git a/src/include/catalog/pg_amproc.dat b/src/include/catalog/pg_amproc.dat index 9b90f4d806d7e..36b5235c80330 100644 --- a/src/include/catalog/pg_amproc.dat +++ b/src/include/catalog/pg_amproc.dat @@ -286,7 +286,8 @@ { amprocfamily => 'btree/range_ops', amproclefttype => 'anyrange', amprocrighttype => 'anyrange', amprocnum => '1', amproc => 'range_cmp' }, { amprocfamily => 'btree/multirange_ops', amproclefttype => 'anymultirange', - amprocrighttype => 'anymultirange', amprocnum => '1', amproc => 'multirange_cmp' }, + amprocrighttype => 'anymultirange', amprocnum => '1', + amproc => 'multirange_cmp' }, { amprocfamily => 'btree/jsonb_ops', amproclefttype => 'jsonb', amprocrighttype => 'jsonb', amprocnum => '1', amproc => 'jsonb_cmp' }, { amprocfamily => 'btree/xid8_ops', amproclefttype => 'xid8', @@ -438,7 +439,8 @@ { amprocfamily => 'hash/record_ops', amproclefttype => 'record', amprocrighttype => 'record', amprocnum => '1', amproc => 'hash_record' }, { amprocfamily => 'hash/record_ops', amproclefttype => 'record', - amprocrighttype => 'record', amprocnum => '2', amproc => 'hash_record_extended' }, + amprocrighttype => 'record', amprocnum => '2', + amproc => 'hash_record_extended' }, { amprocfamily => 'hash/pg_lsn_ops', amproclefttype => 'pg_lsn', amprocrighttype => 'pg_lsn', amprocnum => '1', amproc => 'pg_lsn_hash' }, { amprocfamily => 'hash/pg_lsn_ops', amproclefttype => 'pg_lsn', @@ -460,7 +462,8 @@ amprocrighttype => 'anyrange', amprocnum => '2', amproc => 'hash_range_extended' }, { amprocfamily => 'hash/multirange_ops', amproclefttype => 'anymultirange', - amprocrighttype => 'anymultirange', amprocnum => '1', amproc => 'hash_multirange' }, + amprocrighttype => 'anymultirange', amprocnum => '1', + amproc => 'hash_multirange' }, { amprocfamily => 'hash/multirange_ops', amproclefttype => 'anymultirange', amprocrighttype => 'anymultirange', amprocnum => '2', amproc => 'hash_multirange_extended' }, @@ -492,7 +495,8 @@ { amprocfamily => 'gist/point_ops', amproclefttype => 'point', amprocrighttype => 'point', amprocnum => '9', amproc => 'gist_point_fetch' }, { amprocfamily => 'gist/point_ops', amproclefttype => 'point', - amprocrighttype => 'point', amprocnum => '11', amproc => 'gist_point_sortsupport' }, + amprocrighttype => 'point', amprocnum => '11', + amproc => 'gist_point_sortsupport' }, { amprocfamily => 'gist/box_ops', amproclefttype => 'box', amprocrighttype => 'box', amprocnum => '1', amproc => 'gist_box_consistent' }, { amprocfamily => 'gist/box_ops', amproclefttype => 'box', @@ -1311,7 +1315,8 @@ amprocrighttype => 'anyrange', amprocnum => '13', amproc => 'range_contains' }, { amprocfamily => 'brin/range_inclusion_ops', amproclefttype => 'anyrange', - amprocrighttype => 'anyrange', amprocnum => '14', amproc => 'isempty(anyrange)' }, + amprocrighttype => 'anyrange', amprocnum => '14', + amproc => 'isempty(anyrange)' }, # minmax pg_lsn { amprocfamily => 'brin/pg_lsn_minmax_ops', amproclefttype => 'pg_lsn', diff --git a/src/include/catalog/pg_cast.dat b/src/include/catalog/pg_cast.dat index b807a34355ff3..67f73cb6fb2b6 100644 --- a/src/include/catalog/pg_cast.dat +++ b/src/include/catalog/pg_cast.dat @@ -531,16 +531,21 @@ castcontext => 'e', castmethod => 'f' }, # range to multirange -{ castsource => 'int4range', casttarget => 'int4multirange', castfunc => 'int4multirange(int4range)', - castcontext => 'e', castmethod => 'f' }, -{ castsource => 'int8range', casttarget => 'int8multirange', castfunc => 'int8multirange(int8range)', - castcontext => 'e', castmethod => 'f' }, -{ castsource => 'numrange', casttarget => 'nummultirange', castfunc => 'nummultirange(numrange)', - castcontext => 'e', castmethod => 'f' }, -{ castsource => 'daterange', casttarget => 'datemultirange', castfunc => 'datemultirange(daterange)', - castcontext => 'e', castmethod => 'f' }, -{ castsource => 'tsrange', casttarget => 'tsmultirange', castfunc => 'tsmultirange(tsrange)', - castcontext => 'e', castmethod => 'f' }, -{ castsource => 'tstzrange', casttarget => 'tstzmultirange', castfunc => 'tstzmultirange(tstzrange)', - castcontext => 'e', castmethod => 'f' }, +{ castsource => 'int4range', casttarget => 'int4multirange', + castfunc => 'int4multirange(int4range)', castcontext => 'e', + castmethod => 'f' }, +{ castsource => 'int8range', casttarget => 'int8multirange', + castfunc => 'int8multirange(int8range)', castcontext => 'e', + castmethod => 'f' }, +{ castsource => 'numrange', casttarget => 'nummultirange', + castfunc => 'nummultirange(numrange)', castcontext => 'e', + castmethod => 'f' }, +{ castsource => 'daterange', casttarget => 'datemultirange', + castfunc => 'datemultirange(daterange)', castcontext => 'e', + castmethod => 'f' }, +{ castsource => 'tsrange', casttarget => 'tsmultirange', + castfunc => 'tsmultirange(tsrange)', castcontext => 'e', castmethod => 'f' }, +{ castsource => 'tstzrange', casttarget => 'tstzmultirange', + castfunc => 'tstzmultirange(tstzrange)', castcontext => 'e', + castmethod => 'f' }, ] diff --git a/src/include/catalog/pg_collation.dat b/src/include/catalog/pg_collation.dat index 7905fc4833659..ad57b0fa6d141 100644 --- a/src/include/catalog/pg_collation.dat +++ b/src/include/catalog/pg_collation.dat @@ -15,7 +15,8 @@ { oid => '100', oid_symbol => 'DEFAULT_COLLATION_OID', descr => 'database\'s default collation', collname => 'default', collnamespace => 'PGNSP', collowner => 'PGUID', - collprovider => 'd', collencoding => '-1', collcollate => '', collctype => '' }, + collprovider => 'd', collencoding => '-1', collcollate => '', + collctype => '' }, { oid => '950', oid_symbol => 'C_COLLATION_OID', descr => 'standard C collation', collname => 'C', collnamespace => 'PGNSP', collowner => 'PGUID', diff --git a/src/include/catalog/pg_opclass.dat b/src/include/catalog/pg_opclass.dat index 5128d6eded87b..24b1433e1f11a 100644 --- a/src/include/catalog/pg_opclass.dat +++ b/src/include/catalog/pg_opclass.dat @@ -114,8 +114,8 @@ opcfamily => 'hash/oidvector_ops', opcintype => 'oidvector' }, { opcmethod => 'btree', opcname => 'record_ops', opcfamily => 'btree/record_ops', opcintype => 'record' }, -{ opcmethod => 'hash', opcname => 'record_ops', - opcfamily => 'hash/record_ops', opcintype => 'record' }, +{ opcmethod => 'hash', opcname => 'record_ops', opcfamily => 'hash/record_ops', + opcintype => 'record' }, { opcmethod => 'btree', opcname => 'record_image_ops', opcfamily => 'btree/record_image_ops', opcintype => 'record', opcdefault => 'f' }, @@ -232,12 +232,13 @@ opcintype => 'anyrange' }, { opcmethod => 'spgist', opcname => 'range_ops', opcfamily => 'spgist/range_ops', opcintype => 'anyrange' }, -{ opcmethod => 'btree', opcname => 'multirange_ops', opcfamily => 'btree/multirange_ops', - opcintype => 'anymultirange' }, -{ opcmethod => 'hash', opcname => 'multirange_ops', opcfamily => 'hash/multirange_ops', - opcintype => 'anymultirange' }, -{ opcmethod => 'gist', opcname => 'multirange_ops', opcfamily => 'gist/multirange_ops', - opcintype => 'anymultirange', opckeytype => 'anyrange' }, +{ opcmethod => 'btree', opcname => 'multirange_ops', + opcfamily => 'btree/multirange_ops', opcintype => 'anymultirange' }, +{ opcmethod => 'hash', opcname => 'multirange_ops', + opcfamily => 'hash/multirange_ops', opcintype => 'anymultirange' }, +{ opcmethod => 'gist', opcname => 'multirange_ops', + opcfamily => 'gist/multirange_ops', opcintype => 'anymultirange', + opckeytype => 'anyrange' }, { opcmethod => 'spgist', opcname => 'box_ops', opcfamily => 'spgist/box_ops', opcintype => 'box' }, { opcmethod => 'spgist', opcname => 'quad_point_ops', diff --git a/src/include/catalog/pg_operator.dat b/src/include/catalog/pg_operator.dat index a7a2a94692cf9..0d4eac8f96375 100644 --- a/src/include/catalog/pg_operator.dat +++ b/src/include/catalog/pg_operator.dat @@ -3009,8 +3009,8 @@ # generic record comparison operators { oid => '2988', oid_symbol => 'RECORD_EQ_OP', descr => 'equal', - oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'record', oprright => 'record', - oprresult => 'bool', oprcom => '=(record,record)', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'record', + oprright => 'record', oprresult => 'bool', oprcom => '=(record,record)', oprnegate => '<>(record,record)', oprcode => 'record_eq', oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, { oid => '2989', descr => 'not equal', @@ -3278,8 +3278,9 @@ oprresult => 'bool', oprcode => 'jsonb_path_match_opr(jsonb,jsonpath)', oprrest => 'matchingsel', oprjoin => 'matchingjoinsel' }, { oid => '2860', descr => 'equal', - oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'anymultirange', - oprright => 'anymultirange', oprresult => 'bool', oprcom => '=(anymultirange,anymultirange)', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', + oprleft => 'anymultirange', oprright => 'anymultirange', oprresult => 'bool', + oprcom => '=(anymultirange,anymultirange)', oprnegate => '<>(anymultirange,anymultirange)', oprcode => 'multirange_eq', oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, { oid => '2861', descr => 'not equal', @@ -3316,12 +3317,14 @@ oprresult => 'bool', oprcom => '&&(anymultirange,anyrange)', oprcode => 'range_overlaps_multirange', oprrest => 'multirangesel', oprjoin => 'areajoinsel' }, -{ oid => '2867', oid_symbol => 'OID_MULTIRANGE_OVERLAPS_RANGE_OP', descr => 'contains', +{ oid => '2867', oid_symbol => 'OID_MULTIRANGE_OVERLAPS_RANGE_OP', + descr => 'contains', oprname => '&&', oprleft => 'anymultirange', oprright => 'anyrange', oprresult => 'bool', oprcom => '&&(anyrange,anymultirange)', oprcode => 'multirange_overlaps_range', oprrest => 'multirangesel', oprjoin => 'areajoinsel' }, -{ oid => '2868', oid_symbol => 'OID_MULTIRANGE_OVERLAPS_MULTIRANGE_OP', descr => 'contains', +{ oid => '2868', oid_symbol => 'OID_MULTIRANGE_OVERLAPS_MULTIRANGE_OP', + descr => 'contains', oprname => '&&', oprleft => 'anymultirange', oprright => 'anymultirange', oprresult => 'bool', oprcom => '&&(anymultirange,anymultirange)', oprcode => 'multirange_overlaps_multirange', oprrest => 'multirangesel', @@ -3332,12 +3335,14 @@ oprresult => 'bool', oprcom => '<@(anyelement,anymultirange)', oprcode => 'multirange_contains_elem', oprrest => 'multirangesel', oprjoin => 'contjoinsel' }, -{ oid => '2870', oid_symbol => 'OID_MULTIRANGE_CONTAINS_RANGE_OP', descr => 'contains', +{ oid => '2870', oid_symbol => 'OID_MULTIRANGE_CONTAINS_RANGE_OP', + descr => 'contains', oprname => '@>', oprleft => 'anymultirange', oprright => 'anyrange', oprresult => 'bool', oprcom => '<@(anyrange,anymultirange)', oprcode => 'multirange_contains_range', oprrest => 'multirangesel', oprjoin => 'contjoinsel' }, -{ oid => '2871', oid_symbol => 'OID_MULTIRANGE_CONTAINS_MULTIRANGE_OP', descr => 'contains', +{ oid => '2871', oid_symbol => 'OID_MULTIRANGE_CONTAINS_MULTIRANGE_OP', + descr => 'contains', oprname => '@>', oprleft => 'anymultirange', oprright => 'anymultirange', oprresult => 'bool', oprcom => '<@(anymultirange,anymultirange)', oprcode => 'multirange_contains_multirange', oprrest => 'multirangesel', @@ -3375,44 +3380,47 @@ { oid => '2875', oid_symbol => 'OID_RANGE_OVERLAPS_LEFT_MULTIRANGE_OP', descr => 'overlaps or is left of', oprname => '&<', oprleft => 'anyrange', oprright => 'anymultirange', - oprresult => 'bool', oprcode => 'range_overleft_multirange', oprrest => 'multirangesel', - oprjoin => 'scalarltjoinsel' }, + oprresult => 'bool', oprcode => 'range_overleft_multirange', + oprrest => 'multirangesel', oprjoin => 'scalarltjoinsel' }, { oid => '2876', oid_symbol => 'OID_MULTIRANGE_OVERLAPS_LEFT_RANGE_OP', descr => 'overlaps or is left of', oprname => '&<', oprleft => 'anymultirange', oprright => 'anyrange', - oprresult => 'bool', oprcode => 'multirange_overleft_range', oprrest => 'multirangesel', - oprjoin => 'scalarltjoinsel' }, + oprresult => 'bool', oprcode => 'multirange_overleft_range', + oprrest => 'multirangesel', oprjoin => 'scalarltjoinsel' }, { oid => '2877', oid_symbol => 'OID_MULTIRANGE_OVERLAPS_LEFT_MULTIRANGE_OP', descr => 'overlaps or is left of', oprname => '&<', oprleft => 'anymultirange', oprright => 'anymultirange', - oprresult => 'bool', oprcode => 'multirange_overleft_multirange', oprrest => 'multirangesel', - oprjoin => 'scalargtjoinsel' }, + oprresult => 'bool', oprcode => 'multirange_overleft_multirange', + oprrest => 'multirangesel', oprjoin => 'scalargtjoinsel' }, { oid => '3585', oid_symbol => 'OID_RANGE_OVERLAPS_RIGHT_MULTIRANGE_OP', descr => 'overlaps or is right of', oprname => '&>', oprleft => 'anyrange', oprright => 'anymultirange', - oprresult => 'bool', oprcode => 'range_overright_multirange', oprrest => 'multirangesel', - oprjoin => 'scalargtjoinsel' }, + oprresult => 'bool', oprcode => 'range_overright_multirange', + oprrest => 'multirangesel', oprjoin => 'scalargtjoinsel' }, { oid => '4035', oid_symbol => 'OID_MULTIRANGE_OVERLAPS_RIGHT_RANGE_OP', descr => 'overlaps or is right of', oprname => '&>', oprleft => 'anymultirange', oprright => 'anyrange', - oprresult => 'bool', oprcode => 'multirange_overright_range', oprrest => 'multirangesel', - oprjoin => 'scalargtjoinsel' }, + oprresult => 'bool', oprcode => 'multirange_overright_range', + oprrest => 'multirangesel', oprjoin => 'scalargtjoinsel' }, { oid => '4142', oid_symbol => 'OID_MULTIRANGE_OVERLAPS_RIGHT_MULTIRANGE_OP', descr => 'overlaps or is right of', oprname => '&>', oprleft => 'anymultirange', oprright => 'anymultirange', - oprresult => 'bool', oprcode => 'multirange_overright_multirange', oprrest => 'multirangesel', - oprjoin => 'scalargtjoinsel' }, -{ oid => '4179', oid_symbol => 'OID_RANGE_ADJACENT_MULTIRANGE_OP', descr => 'is adjacent to', + oprresult => 'bool', oprcode => 'multirange_overright_multirange', + oprrest => 'multirangesel', oprjoin => 'scalargtjoinsel' }, +{ oid => '4179', oid_symbol => 'OID_RANGE_ADJACENT_MULTIRANGE_OP', + descr => 'is adjacent to', oprname => '-|-', oprleft => 'anyrange', oprright => 'anymultirange', oprresult => 'bool', oprcom => '-|-(anymultirange,anyrange)', oprcode => 'range_adjacent_multirange', oprrest => 'matchingsel', oprjoin => 'matchingjoinsel' }, -{ oid => '4180', oid_symbol => 'OID_MULTIRANGE_ADJACENT_RANGE_OP', descr => 'is adjacent to', +{ oid => '4180', oid_symbol => 'OID_MULTIRANGE_ADJACENT_RANGE_OP', + descr => 'is adjacent to', oprname => '-|-', oprleft => 'anymultirange', oprright => 'anyrange', oprresult => 'bool', oprcom => '-|-(anyrange,anymultirange)', oprcode => 'multirange_adjacent_range', oprrest => 'matchingsel', oprjoin => 'matchingjoinsel' }, -{ oid => '4198', oid_symbol => 'OID_MULTIRANGE_ADJACENT_MULTIRANGE_OP', descr => 'is adjacent to', +{ oid => '4198', oid_symbol => 'OID_MULTIRANGE_ADJACENT_MULTIRANGE_OP', + descr => 'is adjacent to', oprname => '-|-', oprleft => 'anymultirange', oprright => 'anymultirange', oprresult => 'bool', oprcom => '-|-(anymultirange,anymultirange)', oprcode => 'multirange_adjacent_multirange', oprrest => 'matchingsel', @@ -3428,32 +3436,38 @@ oprname => '*', oprleft => 'anymultirange', oprright => 'anymultirange', oprresult => 'anymultirange', oprcom => '*(anymultirange,anymultirange)', oprcode => 'multirange_intersect' }, -{ oid => '4395', oid_symbol => 'OID_RANGE_LEFT_MULTIRANGE_OP', descr => 'is left of', +{ oid => '4395', oid_symbol => 'OID_RANGE_LEFT_MULTIRANGE_OP', + descr => 'is left of', oprname => '<<', oprleft => 'anyrange', oprright => 'anymultirange', oprresult => 'bool', oprcom => '>>(anymultirange,anyrange)', oprcode => 'range_before_multirange', oprrest => 'multirangesel', oprjoin => 'scalarltjoinsel' }, -{ oid => '4396', oid_symbol => 'OID_MULTIRANGE_LEFT_RANGE_OP', descr => 'is left of', +{ oid => '4396', oid_symbol => 'OID_MULTIRANGE_LEFT_RANGE_OP', + descr => 'is left of', oprname => '<<', oprleft => 'anymultirange', oprright => 'anyrange', oprresult => 'bool', oprcom => '>>(anyrange,anymultirange)', oprcode => 'multirange_before_range', oprrest => 'multirangesel', oprjoin => 'scalarltjoinsel' }, -{ oid => '4397', oid_symbol => 'OID_MULTIRANGE_LEFT_MULTIRANGE_OP', descr => 'is left of', +{ oid => '4397', oid_symbol => 'OID_MULTIRANGE_LEFT_MULTIRANGE_OP', + descr => 'is left of', oprname => '<<', oprleft => 'anymultirange', oprright => 'anymultirange', oprresult => 'bool', oprcom => '>>(anymultirange,anymultirange)', oprcode => 'multirange_before_multirange', oprrest => 'multirangesel', oprjoin => 'scalarltjoinsel' }, -{ oid => '4398', oid_symbol => 'OID_RANGE_RIGHT_MULTIRANGE_OP', descr => 'is right of', +{ oid => '4398', oid_symbol => 'OID_RANGE_RIGHT_MULTIRANGE_OP', + descr => 'is right of', oprname => '>>', oprleft => 'anyrange', oprright => 'anymultirange', oprresult => 'bool', oprcom => '<<(anymultirange,anyrange)', oprcode => 'range_after_multirange', oprrest => 'multirangesel', oprjoin => 'scalargtjoinsel' }, -{ oid => '4399', oid_symbol => 'OID_MULTIRANGE_RIGHT_RANGE_OP', descr => 'is right of', +{ oid => '4399', oid_symbol => 'OID_MULTIRANGE_RIGHT_RANGE_OP', + descr => 'is right of', oprname => '>>', oprleft => 'anymultirange', oprright => 'anyrange', oprresult => 'bool', oprcom => '<<(anyrange,anymultirange)', oprcode => 'multirange_after_range', oprrest => 'multirangesel', oprjoin => 'scalargtjoinsel' }, -{ oid => '4400', oid_symbol => 'OID_MULTIRANGE_RIGHT_MULTIRANGE_OP', descr => 'is right of', +{ oid => '4400', oid_symbol => 'OID_MULTIRANGE_RIGHT_MULTIRANGE_OP', + descr => 'is right of', oprname => '>>', oprleft => 'anymultirange', oprright => 'anymultirange', oprresult => 'bool', oprcom => '<<(anymultirange,anymultirange)', oprcode => 'multirange_after_multirange', oprrest => 'multirangesel', diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index d7b55f57ea77f..fd878fc032d23 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -5500,9 +5500,9 @@ { oid => '1136', descr => 'statistics: information about WAL activity', proname => 'pg_stat_get_wal', proisstrict => 'f', provolatile => 's', proparallel => 'r', prorettype => 'record', proargtypes => '', - proallargtypes => '{int8,int8,numeric,int8,timestamptz}', - proargmodes => '{o,o,o,o,o}', - proargnames => '{wal_records,wal_fpi,wal_bytes,wal_buffers_full,stats_reset}', + proallargtypes => '{int8,int8,numeric,int8,timestamptz}', + proargmodes => '{o,o,o,o,o}', + proargnames => '{wal_records,wal_fpi,wal_bytes,wal_buffers_full,stats_reset}', prosrc => 'pg_stat_get_wal' }, { oid => '2306', descr => 'statistics: information about SLRU caches', @@ -9693,8 +9693,8 @@ proname => 'hash_record', prorettype => 'int4', proargtypes => 'record', prosrc => 'hash_record' }, { oid => '9610', descr => 'hash', - proname => 'hash_record_extended', prorettype => 'int8', proargtypes => 'record int8', - prosrc => 'hash_record_extended' }, + proname => 'hash_record_extended', prorettype => 'int8', + proargtypes => 'record int8', prosrc => 'hash_record_extended' }, # record comparison using raw byte images { oid => '3181', @@ -9928,8 +9928,7 @@ prosrc => 'multirange_gist_consistent' }, { oid => '8019', descr => 'GiST support', proname => 'multirange_gist_compress', prorettype => 'internal', - proargtypes => 'internal', - prosrc => 'multirange_gist_compress' }, + proargtypes => 'internal', prosrc => 'multirange_gist_compress' }, { oid => '3902', descr => 'hash a range', proname => 'hash_range', prorettype => 'int4', proargtypes => 'anyrange', prosrc => 'hash_range' }, @@ -9944,11 +9943,11 @@ proargtypes => 'internal oid internal int4', prosrc => 'rangesel' }, { oid => '4401', descr => 'range aggregate by intersecting', proname => 'range_intersect_agg_transfn', prorettype => 'anyrange', - proargtypes => 'anyrange anyrange', prosrc => 'range_intersect_agg_transfn'}, + proargtypes => 'anyrange anyrange', prosrc => 'range_intersect_agg_transfn' }, { oid => '4450', descr => 'range aggregate by intersecting', proname => 'range_intersect_agg', prokind => 'a', proisstrict => 'f', prorettype => 'anyrange', proargtypes => 'anyrange', - prosrc => 'aggregate_dummy'}, + prosrc => 'aggregate_dummy' }, { oid => '3914', descr => 'convert an int4 range to canonical form', proname => 'int4range_canonical', prorettype => 'int4range', @@ -10019,8 +10018,9 @@ # functions for multiranges { oid => '4229', descr => 'I/O', - proname => 'anymultirange_in', provolatile => 's', prorettype => 'anymultirange', - proargtypes => 'cstring oid int4', prosrc => 'anymultirange_in' }, + proname => 'anymultirange_in', provolatile => 's', + prorettype => 'anymultirange', proargtypes => 'cstring oid int4', + prosrc => 'anymultirange_in' }, { oid => '4230', descr => 'I/O', proname => 'anymultirange_out', provolatile => 's', prorettype => 'cstring', proargtypes => 'anymultirange', prosrc => 'anymultirange_out' }, @@ -10031,20 +10031,21 @@ proname => 'multirange_out', provolatile => 's', prorettype => 'cstring', proargtypes => 'anymultirange', prosrc => 'multirange_out' }, { oid => '4233', descr => 'I/O', - proname => 'multirange_recv', provolatile => 's', prorettype => 'anymultirange', - proargtypes => 'internal oid int4', prosrc => 'multirange_recv' }, + proname => 'multirange_recv', provolatile => 's', + prorettype => 'anymultirange', proargtypes => 'internal oid int4', + prosrc => 'multirange_recv' }, { oid => '4234', descr => 'I/O', proname => 'multirange_send', provolatile => 's', prorettype => 'bytea', proargtypes => 'anymultirange', prosrc => 'multirange_send' }, { oid => '4235', descr => 'lower bound of multirange', - proname => 'lower', prorettype => 'anyelement', proargtypes => 'anymultirange', - prosrc => 'multirange_lower' }, + proname => 'lower', prorettype => 'anyelement', + proargtypes => 'anymultirange', prosrc => 'multirange_lower' }, { oid => '4236', descr => 'upper bound of multirange', - proname => 'upper', prorettype => 'anyelement', proargtypes => 'anymultirange', - prosrc => 'multirange_upper' }, + proname => 'upper', prorettype => 'anyelement', + proargtypes => 'anymultirange', prosrc => 'multirange_upper' }, { oid => '4237', descr => 'is the multirange empty?', - proname => 'isempty', prorettype => 'bool', - proargtypes => 'anymultirange', prosrc => 'multirange_empty' }, + proname => 'isempty', prorettype => 'bool', proargtypes => 'anymultirange', + prosrc => 'multirange_empty' }, { oid => '4238', descr => 'is the multirange\'s lower bound inclusive?', proname => 'lower_inc', prorettype => 'bool', proargtypes => 'anymultirange', prosrc => 'multirange_lower_inc' }, @@ -10071,55 +10072,72 @@ proargtypes => 'anymultirange anymultirange', prosrc => 'multirange_ne' }, { oid => '4246', proname => 'range_overlaps_multirange', prorettype => 'bool', - proargtypes => 'anyrange anymultirange', prosrc => 'range_overlaps_multirange' }, + proargtypes => 'anyrange anymultirange', + prosrc => 'range_overlaps_multirange' }, { oid => '4247', proname => 'multirange_overlaps_range', prorettype => 'bool', - proargtypes => 'anymultirange anyrange', prosrc => 'multirange_overlaps_range' }, + proargtypes => 'anymultirange anyrange', + prosrc => 'multirange_overlaps_range' }, { oid => '4248', proname => 'multirange_overlaps_multirange', prorettype => 'bool', - proargtypes => 'anymultirange anymultirange', prosrc => 'multirange_overlaps_multirange' }, + proargtypes => 'anymultirange anymultirange', + prosrc => 'multirange_overlaps_multirange' }, { oid => '4249', proname => 'multirange_contains_elem', prorettype => 'bool', - proargtypes => 'anymultirange anyelement', prosrc => 'multirange_contains_elem' }, + proargtypes => 'anymultirange anyelement', + prosrc => 'multirange_contains_elem' }, { oid => '4250', proname => 'multirange_contains_range', prorettype => 'bool', - proargtypes => 'anymultirange anyrange', prosrc => 'multirange_contains_range' }, + proargtypes => 'anymultirange anyrange', + prosrc => 'multirange_contains_range' }, { oid => '4251', proname => 'multirange_contains_multirange', prorettype => 'bool', - proargtypes => 'anymultirange anymultirange', prosrc => 'multirange_contains_multirange' }, + proargtypes => 'anymultirange anymultirange', + prosrc => 'multirange_contains_multirange' }, { oid => '4252', proname => 'elem_contained_by_multirange', prorettype => 'bool', - proargtypes => 'anyelement anymultirange', prosrc => 'elem_contained_by_multirange' }, + proargtypes => 'anyelement anymultirange', + prosrc => 'elem_contained_by_multirange' }, { oid => '4253', proname => 'range_contained_by_multirange', prorettype => 'bool', - proargtypes => 'anyrange anymultirange', prosrc => 'range_contained_by_multirange' }, + proargtypes => 'anyrange anymultirange', + prosrc => 'range_contained_by_multirange' }, { oid => '4541', proname => 'range_contains_multirange', prorettype => 'bool', - proargtypes => 'anyrange anymultirange', prosrc => 'range_contains_multirange' }, + proargtypes => 'anyrange anymultirange', + prosrc => 'range_contains_multirange' }, { oid => '4542', proname => 'multirange_contained_by_range', prorettype => 'bool', - proargtypes => 'anymultirange anyrange', prosrc => 'multirange_contained_by_range' }, + proargtypes => 'anymultirange anyrange', + prosrc => 'multirange_contained_by_range' }, { oid => '4254', proname => 'multirange_contained_by_multirange', prorettype => 'bool', - proargtypes => 'anymultirange anymultirange', prosrc => 'multirange_contained_by_multirange' }, + proargtypes => 'anymultirange anymultirange', + prosrc => 'multirange_contained_by_multirange' }, { oid => '4255', proname => 'range_adjacent_multirange', prorettype => 'bool', - proargtypes => 'anyrange anymultirange', prosrc => 'range_adjacent_multirange' }, + proargtypes => 'anyrange anymultirange', + prosrc => 'range_adjacent_multirange' }, { oid => '4256', proname => 'multirange_adjacent_multirange', prorettype => 'bool', - proargtypes => 'anymultirange anymultirange', prosrc => 'multirange_adjacent_multirange' }, + proargtypes => 'anymultirange anymultirange', + prosrc => 'multirange_adjacent_multirange' }, { oid => '4257', proname => 'multirange_adjacent_range', prorettype => 'bool', - proargtypes => 'anymultirange anyrange', prosrc => 'multirange_adjacent_range' }, + proargtypes => 'anymultirange anyrange', + prosrc => 'multirange_adjacent_range' }, { oid => '4258', proname => 'range_before_multirange', prorettype => 'bool', - proargtypes => 'anyrange anymultirange', prosrc => 'range_before_multirange' }, + proargtypes => 'anyrange anymultirange', + prosrc => 'range_before_multirange' }, { oid => '4259', proname => 'multirange_before_range', prorettype => 'bool', - proargtypes => 'anymultirange anyrange', prosrc => 'multirange_before_range' }, + proargtypes => 'anymultirange anyrange', + prosrc => 'multirange_before_range' }, { oid => '4260', proname => 'multirange_before_multirange', prorettype => 'bool', - proargtypes => 'anymultirange anymultirange', prosrc => 'multirange_before_multirange' }, + proargtypes => 'anymultirange anymultirange', + prosrc => 'multirange_before_multirange' }, { oid => '4261', proname => 'range_after_multirange', prorettype => 'bool', proargtypes => 'anyrange anymultirange', prosrc => 'range_after_multirange' }, @@ -10128,25 +10146,32 @@ proargtypes => 'anymultirange anyrange', prosrc => 'multirange_after_range' }, { oid => '4263', proname => 'multirange_after_multirange', prorettype => 'bool', - proargtypes => 'anymultirange anymultirange', prosrc => 'multirange_after_multirange' }, + proargtypes => 'anymultirange anymultirange', + prosrc => 'multirange_after_multirange' }, { oid => '4264', proname => 'range_overleft_multirange', prorettype => 'bool', - proargtypes => 'anyrange anymultirange', prosrc => 'range_overleft_multirange' }, + proargtypes => 'anyrange anymultirange', + prosrc => 'range_overleft_multirange' }, { oid => '4265', proname => 'multirange_overleft_range', prorettype => 'bool', - proargtypes => 'anymultirange anyrange', prosrc => 'multirange_overleft_range' }, + proargtypes => 'anymultirange anyrange', + prosrc => 'multirange_overleft_range' }, { oid => '4266', proname => 'multirange_overleft_multirange', prorettype => 'bool', - proargtypes => 'anymultirange anymultirange', prosrc => 'multirange_overleft_multirange' }, + proargtypes => 'anymultirange anymultirange', + prosrc => 'multirange_overleft_multirange' }, { oid => '4267', proname => 'range_overright_multirange', prorettype => 'bool', - proargtypes => 'anyrange anymultirange', prosrc => 'range_overright_multirange' }, + proargtypes => 'anyrange anymultirange', + prosrc => 'range_overright_multirange' }, { oid => '4268', proname => 'multirange_overright_range', prorettype => 'bool', - proargtypes => 'anymultirange anyrange', prosrc => 'multirange_overright_range' }, + proargtypes => 'anymultirange anyrange', + prosrc => 'multirange_overright_range' }, { oid => '4269', proname => 'multirange_overright_multirange', prorettype => 'bool', - proargtypes => 'anymultirange anymultirange', prosrc => 'multirange_overright_multirange' }, + proargtypes => 'anymultirange anymultirange', + prosrc => 'multirange_overright_multirange' }, { oid => '4270', proname => 'multirange_union', prorettype => 'anymultirange', proargtypes => 'anymultirange anymultirange', prosrc => 'multirange_union' }, @@ -10155,7 +10180,8 @@ proargtypes => 'anymultirange anymultirange', prosrc => 'multirange_minus' }, { oid => '4272', proname => 'multirange_intersect', prorettype => 'anymultirange', - proargtypes => 'anymultirange anymultirange', prosrc => 'multirange_intersect' }, + proargtypes => 'anymultirange anymultirange', + prosrc => 'multirange_intersect' }, { oid => '4273', descr => 'less-equal-greater', proname => 'multirange_cmp', prorettype => 'int4', proargtypes => 'anymultirange anymultirange', prosrc => 'multirange_cmp' }, @@ -10172,8 +10198,8 @@ proname => 'multirange_gt', prorettype => 'bool', proargtypes => 'anymultirange anymultirange', prosrc => 'multirange_gt' }, { oid => '4278', descr => 'hash a multirange', - proname => 'hash_multirange', prorettype => 'int4', proargtypes => 'anymultirange', - prosrc => 'hash_multirange' }, + proname => 'hash_multirange', prorettype => 'int4', + proargtypes => 'anymultirange', prosrc => 'hash_multirange' }, { oid => '4279', descr => 'hash a multirange', proname => 'hash_multirange_extended', prorettype => 'int8', proargtypes => 'anymultirange int8', prosrc => 'hash_multirange_extended' }, @@ -10183,35 +10209,30 @@ prorettype => 'int4multirange', proargtypes => '', prosrc => 'multirange_constructor0' }, { oid => '4281', descr => 'int4multirange constructor', - proname => 'int4multirange', proisstrict => 't', - prorettype => 'int4multirange', proargtypes => 'int4range', - prosrc => 'multirange_constructor1' }, + proname => 'int4multirange', prorettype => 'int4multirange', + proargtypes => 'int4range', prosrc => 'multirange_constructor1' }, { oid => '4282', descr => 'int4multirange constructor', proname => 'int4multirange', provariadic => 'int4range', proisstrict => 'f', prorettype => 'int4multirange', proargtypes => '_int4range', proallargtypes => '{_int4range}', proargmodes => '{v}', prosrc => 'multirange_constructor2' }, { oid => '4283', descr => 'nummultirange constructor', - proname => 'nummultirange', proisstrict => 'f', - prorettype => 'nummultirange', proargtypes => '', - prosrc => 'multirange_constructor0' }, + proname => 'nummultirange', proisstrict => 'f', prorettype => 'nummultirange', + proargtypes => '', prosrc => 'multirange_constructor0' }, { oid => '4284', descr => 'nummultirange constructor', - proname => 'nummultirange', proisstrict => 't', - prorettype => 'nummultirange', proargtypes => 'numrange', - prosrc => 'multirange_constructor1' }, + proname => 'nummultirange', prorettype => 'nummultirange', + proargtypes => 'numrange', prosrc => 'multirange_constructor1' }, { oid => '4285', descr => 'nummultirange constructor', proname => 'nummultirange', provariadic => 'numrange', proisstrict => 'f', prorettype => 'nummultirange', proargtypes => '_numrange', proallargtypes => '{_numrange}', proargmodes => '{v}', prosrc => 'multirange_constructor2' }, { oid => '4286', descr => 'tsmultirange constructor', - proname => 'tsmultirange', proisstrict => 'f', - prorettype => 'tsmultirange', proargtypes => '', - prosrc => 'multirange_constructor0' }, + proname => 'tsmultirange', proisstrict => 'f', prorettype => 'tsmultirange', + proargtypes => '', prosrc => 'multirange_constructor0' }, { oid => '4287', descr => 'tsmultirange constructor', - proname => 'tsmultirange', proisstrict => 't', - prorettype => 'tsmultirange', proargtypes => 'tsrange', - prosrc => 'multirange_constructor1' }, + proname => 'tsmultirange', prorettype => 'tsmultirange', + proargtypes => 'tsrange', prosrc => 'multirange_constructor1' }, { oid => '4288', descr => 'tsmultirange constructor', proname => 'tsmultirange', provariadic => 'tsrange', proisstrict => 'f', prorettype => 'tsmultirange', proargtypes => '_tsrange', @@ -10222,9 +10243,8 @@ prorettype => 'tstzmultirange', proargtypes => '', prosrc => 'multirange_constructor0' }, { oid => '4290', descr => 'tstzmultirange constructor', - proname => 'tstzmultirange', proisstrict => 't', - prorettype => 'tstzmultirange', proargtypes => 'tstzrange', - prosrc => 'multirange_constructor1' }, + proname => 'tstzmultirange', prorettype => 'tstzmultirange', + proargtypes => 'tstzrange', prosrc => 'multirange_constructor1' }, { oid => '4291', descr => 'tstzmultirange constructor', proname => 'tstzmultirange', provariadic => 'tstzrange', proisstrict => 'f', prorettype => 'tstzmultirange', proargtypes => '_tstzrange', @@ -10235,9 +10255,8 @@ prorettype => 'datemultirange', proargtypes => '', prosrc => 'multirange_constructor0' }, { oid => '4293', descr => 'datemultirange constructor', - proname => 'datemultirange', proisstrict => 't', - prorettype => 'datemultirange', proargtypes => 'daterange', - prosrc => 'multirange_constructor1' }, + proname => 'datemultirange', prorettype => 'datemultirange', + proargtypes => 'daterange', prosrc => 'multirange_constructor1' }, { oid => '4294', descr => 'datemultirange constructor', proname => 'datemultirange', provariadic => 'daterange', proisstrict => 'f', prorettype => 'datemultirange', proargtypes => '_daterange', @@ -10248,35 +10267,35 @@ prorettype => 'int8multirange', proargtypes => '', prosrc => 'multirange_constructor0' }, { oid => '4296', descr => 'int8multirange constructor', - proname => 'int8multirange', proisstrict => 't', - prorettype => 'int8multirange', proargtypes => 'int8range', - prosrc => 'multirange_constructor1' }, + proname => 'int8multirange', prorettype => 'int8multirange', + proargtypes => 'int8range', prosrc => 'multirange_constructor1' }, { oid => '4297', descr => 'int8multirange constructor', proname => 'int8multirange', provariadic => 'int8range', proisstrict => 'f', prorettype => 'int8multirange', proargtypes => '_int8range', proallargtypes => '{_int8range}', proargmodes => '{v}', prosrc => 'multirange_constructor2' }, { oid => '4298', descr => 'anymultirange cast', - proname => 'multirange', proisstrict => 't', - prorettype => 'anymultirange', proargtypes => 'anyrange', - prosrc => 'multirange_constructor1' }, + proname => 'multirange', prorettype => 'anymultirange', + proargtypes => 'anyrange', prosrc => 'multirange_constructor1' }, { oid => '4299', descr => 'aggregate transition function', proname => 'range_agg_transfn', proisstrict => 'f', prorettype => 'internal', proargtypes => 'internal anyrange', prosrc => 'range_agg_transfn' }, { oid => '4300', descr => 'aggregate final function', - proname => 'range_agg_finalfn', proisstrict => 'f', prorettype => 'anymultirange', - proargtypes => 'internal anyrange', prosrc => 'range_agg_finalfn' }, + proname => 'range_agg_finalfn', proisstrict => 'f', + prorettype => 'anymultirange', proargtypes => 'internal anyrange', + prosrc => 'range_agg_finalfn' }, { oid => '4301', descr => 'combine aggregate input into a multirange', proname => 'range_agg', prokind => 'a', proisstrict => 'f', prorettype => 'anymultirange', proargtypes => 'anyrange', prosrc => 'aggregate_dummy' }, { oid => '4388', descr => 'range aggregate by intersecting', proname => 'multirange_intersect_agg_transfn', prorettype => 'anymultirange', - proargtypes => 'anymultirange anymultirange', prosrc => 'multirange_intersect_agg_transfn'}, + proargtypes => 'anymultirange anymultirange', + prosrc => 'multirange_intersect_agg_transfn' }, { oid => '4389', descr => 'range aggregate by intersecting', proname => 'range_intersect_agg', prokind => 'a', proisstrict => 'f', prorettype => 'anymultirange', proargtypes => 'anymultirange', - prosrc => 'aggregate_dummy'}, + prosrc => 'aggregate_dummy' }, # date, time, timestamp constructors { oid => '3846', descr => 'construct date', @@ -10661,12 +10680,14 @@ proparallel => 'r', prorettype => 'void', proargtypes => 'oid', prosrc => 'binary_upgrade_set_next_array_pg_type_oid' }, { oid => '4390', descr => 'for use by pg_upgrade', - proname => 'binary_upgrade_set_next_multirange_pg_type_oid', provolatile => 'v', - proparallel => 'r', prorettype => 'void', proargtypes => 'oid', + proname => 'binary_upgrade_set_next_multirange_pg_type_oid', + provolatile => 'v', proparallel => 'r', prorettype => 'void', + proargtypes => 'oid', prosrc => 'binary_upgrade_set_next_multirange_pg_type_oid' }, { oid => '4391', descr => 'for use by pg_upgrade', - proname => 'binary_upgrade_set_next_multirange_array_pg_type_oid', provolatile => 'v', - proparallel => 'r', prorettype => 'void', proargtypes => 'oid', + proname => 'binary_upgrade_set_next_multirange_array_pg_type_oid', + provolatile => 'v', proparallel => 'r', prorettype => 'void', + proargtypes => 'oid', prosrc => 'binary_upgrade_set_next_multirange_array_pg_type_oid' }, { oid => '3586', descr => 'for use by pg_upgrade', proname => 'binary_upgrade_set_next_heap_pg_class_oid', provolatile => 'v', diff --git a/src/include/catalog/pg_range.dat b/src/include/catalog/pg_range.dat index 5ba23aa21dc37..3bd2d83b383b2 100644 --- a/src/include/catalog/pg_range.dat +++ b/src/include/catalog/pg_range.dat @@ -12,23 +12,23 @@ [ -{ rngtypid => 'int4range', rngsubtype => 'int4', rngsubopc => 'btree/int4_ops', - rngcanonical => 'int4range_canonical', rngsubdiff => 'int4range_subdiff', - rngmultitypid => 'int4multirange' }, +{ rngtypid => 'int4range', rngsubtype => 'int4', + rngmultitypid => 'int4multirange', rngsubopc => 'btree/int4_ops', + rngcanonical => 'int4range_canonical', rngsubdiff => 'int4range_subdiff' }, { rngtypid => 'numrange', rngsubtype => 'numeric', - rngsubopc => 'btree/numeric_ops', rngcanonical => '-', - rngsubdiff => 'numrange_subdiff', rngmultitypid => 'nummultirange' }, + rngmultitypid => 'nummultirange', rngsubopc => 'btree/numeric_ops', + rngcanonical => '-', rngsubdiff => 'numrange_subdiff' }, { rngtypid => 'tsrange', rngsubtype => 'timestamp', - rngsubopc => 'btree/timestamp_ops', rngcanonical => '-', - rngsubdiff => 'tsrange_subdiff', rngmultitypid => 'tsmultirange' }, + rngmultitypid => 'tsmultirange', rngsubopc => 'btree/timestamp_ops', + rngcanonical => '-', rngsubdiff => 'tsrange_subdiff' }, { rngtypid => 'tstzrange', rngsubtype => 'timestamptz', - rngsubopc => 'btree/timestamptz_ops', rngcanonical => '-', - rngsubdiff => 'tstzrange_subdiff', rngmultitypid => 'tstzmultirange' }, -{ rngtypid => 'daterange', rngsubtype => 'date', rngsubopc => 'btree/date_ops', - rngcanonical => 'daterange_canonical', rngsubdiff => 'daterange_subdiff', - rngmultitypid => 'datemultirange' }, -{ rngtypid => 'int8range', rngsubtype => 'int8', rngsubopc => 'btree/int8_ops', - rngcanonical => 'int8range_canonical', rngsubdiff => 'int8range_subdiff', - rngmultitypid => 'int8multirange' }, + rngmultitypid => 'tstzmultirange', rngsubopc => 'btree/timestamptz_ops', + rngcanonical => '-', rngsubdiff => 'tstzrange_subdiff' }, +{ rngtypid => 'daterange', rngsubtype => 'date', + rngmultitypid => 'datemultirange', rngsubopc => 'btree/date_ops', + rngcanonical => 'daterange_canonical', rngsubdiff => 'daterange_subdiff' }, +{ rngtypid => 'int8range', rngsubtype => 'int8', + rngmultitypid => 'int8multirange', rngsubopc => 'btree/int8_ops', + rngcanonical => 'int8range_canonical', rngsubdiff => 'int8range_subdiff' }, ] diff --git a/src/include/catalog/pg_type.dat b/src/include/catalog/pg_type.dat index 49dc3e18e011f..56da2913bdac9 100644 --- a/src/include/catalog/pg_type.dat +++ b/src/include/catalog/pg_type.dat @@ -499,36 +499,42 @@ # multirange types { oid => '4451', array_type_oid => '8010', descr => 'multirange of integers', typname => 'int4multirange', typlen => '-1', typbyval => 'f', typtype => 'm', - typcategory => 'R', typinput => 'multirange_in', typoutput => 'multirange_out', - typreceive => 'multirange_recv', typsend => 'multirange_send', - typanalyze => 'multirange_typanalyze', typalign => 'i', typstorage => 'x' }, + typcategory => 'R', typinput => 'multirange_in', + typoutput => 'multirange_out', typreceive => 'multirange_recv', + typsend => 'multirange_send', typanalyze => 'multirange_typanalyze', + typalign => 'i', typstorage => 'x' }, { oid => '4532', array_type_oid => '8012', descr => 'multirange of numerics', typname => 'nummultirange', typlen => '-1', typbyval => 'f', typtype => 'm', - typcategory => 'R', typinput => 'multirange_in', typoutput => 'multirange_out', - typreceive => 'multirange_recv', typsend => 'multirange_send', - typanalyze => 'multirange_typanalyze', typalign => 'i', typstorage => 'x' }, + typcategory => 'R', typinput => 'multirange_in', + typoutput => 'multirange_out', typreceive => 'multirange_recv', + typsend => 'multirange_send', typanalyze => 'multirange_typanalyze', + typalign => 'i', typstorage => 'x' }, { oid => '4533', array_type_oid => '8014', descr => 'multirange of timestamps without time zone', typname => 'tsmultirange', typlen => '-1', typbyval => 'f', typtype => 'm', - typcategory => 'R', typinput => 'multirange_in', typoutput => 'multirange_out', - typreceive => 'multirange_recv', typsend => 'multirange_send', - typanalyze => 'multirange_typanalyze', typalign => 'd', typstorage => 'x' }, + typcategory => 'R', typinput => 'multirange_in', + typoutput => 'multirange_out', typreceive => 'multirange_recv', + typsend => 'multirange_send', typanalyze => 'multirange_typanalyze', + typalign => 'd', typstorage => 'x' }, { oid => '4534', array_type_oid => '8016', descr => 'multirange of timestamps with time zone', typname => 'tstzmultirange', typlen => '-1', typbyval => 'f', typtype => 'm', - typcategory => 'R', typinput => 'multirange_in', typoutput => 'multirange_out', - typreceive => 'multirange_recv', typsend => 'multirange_send', - typanalyze => 'multirange_typanalyze', typalign => 'd', typstorage => 'x' }, + typcategory => 'R', typinput => 'multirange_in', + typoutput => 'multirange_out', typreceive => 'multirange_recv', + typsend => 'multirange_send', typanalyze => 'multirange_typanalyze', + typalign => 'd', typstorage => 'x' }, { oid => '4535', array_type_oid => '8018', descr => 'multirange of dates', typname => 'datemultirange', typlen => '-1', typbyval => 'f', typtype => 'm', - typcategory => 'R', typinput => 'multirange_in', typoutput => 'multirange_out', - typreceive => 'multirange_recv', typsend => 'multirange_send', - typanalyze => 'multirange_typanalyze', typalign => 'i', typstorage => 'x' }, + typcategory => 'R', typinput => 'multirange_in', + typoutput => 'multirange_out', typreceive => 'multirange_recv', + typsend => 'multirange_send', typanalyze => 'multirange_typanalyze', + typalign => 'i', typstorage => 'x' }, { oid => '4536', array_type_oid => '8020', descr => 'multirange of bigints', typname => 'int8multirange', typlen => '-1', typbyval => 'f', typtype => 'm', - typcategory => 'R', typinput => 'multirange_in', typoutput => 'multirange_out', - typreceive => 'multirange_recv', typsend => 'multirange_send', - typanalyze => 'multirange_typanalyze', typalign => 'd', typstorage => 'x' }, + typcategory => 'R', typinput => 'multirange_in', + typoutput => 'multirange_out', typreceive => 'multirange_recv', + typsend => 'multirange_send', typanalyze => 'multirange_typanalyze', + typalign => 'd', typstorage => 'x' }, # pseudo-types # types with typtype='p' represent various special cases in the type system. @@ -663,8 +669,9 @@ { oid => '4537', descr => 'pseudo-type representing a polymorphic base type that is a multirange', typname => 'anymultirange', typlen => '-1', typbyval => 'f', typtype => 'p', - typcategory => 'P', typinput => 'anymultirange_in', typoutput => 'anymultirange_out', - typreceive => '-', typsend => '-', typalign => 'd', typstorage => 'x' }, + typcategory => 'P', typinput => 'anymultirange_in', + typoutput => 'anymultirange_out', typreceive => '-', typsend => '-', + typalign => 'd', typstorage => 'x' }, { oid => '4538', descr => 'pseudo-type representing a multirange over a polymorphic common type', typname => 'anycompatiblemultirange', typlen => '-1', typbyval => 'f', From 5a6f9bce8dabd371bdb4e3db5dda436f7f0a680f Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 13 Jan 2021 16:23:15 -0500 Subject: [PATCH 097/240] Mark inet_server_addr() and inet_server_port() as parallel-restricted. These need to be PR because they access the MyProcPort data structure, which doesn't get copied to parallel workers. The very similar functions inet_client_addr() and inet_client_port() are already marked PR, but somebody missed these. Although this is a pre-existing bug, we can't readily fix it in the back branches since we can't force initdb. Given the small usage of these two functions, and the even smaller likelihood that they'd get pushed to a parallel worker anyway, it doesn't seem worth the trouble to suggest that DBAs should fix it manually. Masahiko Sawada Discussion: https://postgr.es/m/CAD21AoAT4aHP0Uxq91qpD7NL009tnUYQe-b14R3MnSVOjtE71g@mail.gmail.com --- src/include/catalog/catversion.h | 2 +- src/include/catalog/pg_proc.dat | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index a6e39b3139a51..747135dab46f2 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202012293 +#define CATALOG_VERSION_NO 202101131 #endif diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index fd878fc032d23..d27336adcd9f5 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -4082,10 +4082,12 @@ prosrc => 'inet_client_port' }, { oid => '2198', descr => 'inet address of the server', proname => 'inet_server_addr', proisstrict => 'f', provolatile => 's', - prorettype => 'inet', proargtypes => '', prosrc => 'inet_server_addr' }, + proparallel => 'r', prorettype => 'inet', proargtypes => '', + prosrc => 'inet_server_addr' }, { oid => '2199', descr => 'server\'s port number for this connection', proname => 'inet_server_port', proisstrict => 'f', provolatile => 's', - prorettype => 'int4', proargtypes => '', prosrc => 'inet_server_port' }, + proparallel => 'r', prorettype => 'int4', proargtypes => '', + prosrc => 'inet_server_port' }, { oid => '2627', proname => 'inetnot', prorettype => 'inet', proargtypes => 'inet', From 0d56acfbaa799553c0c6ea350fd6e68d81025994 Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Thu, 14 Jan 2021 11:10:24 +1300 Subject: [PATCH 098/240] Move our p{read,write}v replacements into their own files. macOS's ranlib issued a warning about an empty pread.o file with the previous arrangement, on systems new enough to require no replacement functions. Let's go back to using configure's AC_REPLACE_FUNCS system to build and include each .o in the library only if it's needed, which requires moving the *v() functions to their own files. Also move the _with_retry() wrapper to a more permanent home. Reported-by: Tom Lane Discussion: https://postgr.es/m/1283127.1610554395%40sss.pgh.pa.us --- configure | 54 ++++++++++++++++- configure.ac | 8 +-- src/backend/storage/file/fd.c | 65 +++++++++++++++++++++ src/include/storage/fd.h | 5 ++ src/port/Makefile | 2 - src/port/pread.c | 43 +------------- src/port/preadv.c | 58 ++++++++++++++++++ src/port/pwrite.c | 107 +--------------------------------- src/port/pwritev.c | 58 ++++++++++++++++++ src/tools/msvc/Mkvcbuild.pm | 2 +- 10 files changed, 248 insertions(+), 154 deletions(-) create mode 100644 src/port/preadv.c create mode 100644 src/port/pwritev.c diff --git a/configure b/configure index b917a2a1c9dbf..8af4b990218cc 100755 --- a/configure +++ b/configure @@ -15155,7 +15155,7 @@ fi LIBS_including_readline="$LIBS" LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'` -for ac_func in backtrace_symbols clock_gettime copyfile fdatasync getifaddrs getpeerucred getrlimit kqueue mbstowcs_l memset_s poll posix_fallocate ppoll pread preadv pstat pthread_is_threaded_np pwrite pwritev readlink readv setproctitle setproctitle_fast setsid shm_open strchrnul strsignal symlink sync_file_range uselocale wcstombs_l writev +for ac_func in backtrace_symbols clock_gettime copyfile fdatasync getifaddrs getpeerucred getrlimit kqueue mbstowcs_l memset_s poll posix_fallocate ppoll pstat pthread_is_threaded_np readlink readv setproctitle setproctitle_fast setsid shm_open strchrnul strsignal symlink sync_file_range uselocale wcstombs_l writev do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" @@ -15832,6 +15832,58 @@ esac fi +ac_fn_c_check_func "$LINENO" "pread" "ac_cv_func_pread" +if test "x$ac_cv_func_pread" = xyes; then : + $as_echo "#define HAVE_PREAD 1" >>confdefs.h + +else + case " $LIBOBJS " in + *" pread.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS pread.$ac_objext" + ;; +esac + +fi + +ac_fn_c_check_func "$LINENO" "preadv" "ac_cv_func_preadv" +if test "x$ac_cv_func_preadv" = xyes; then : + $as_echo "#define HAVE_PREADV 1" >>confdefs.h + +else + case " $LIBOBJS " in + *" preadv.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS preadv.$ac_objext" + ;; +esac + +fi + +ac_fn_c_check_func "$LINENO" "pwrite" "ac_cv_func_pwrite" +if test "x$ac_cv_func_pwrite" = xyes; then : + $as_echo "#define HAVE_PWRITE 1" >>confdefs.h + +else + case " $LIBOBJS " in + *" pwrite.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS pwrite.$ac_objext" + ;; +esac + +fi + +ac_fn_c_check_func "$LINENO" "pwritev" "ac_cv_func_pwritev" +if test "x$ac_cv_func_pwritev" = xyes; then : + $as_echo "#define HAVE_PWRITEV 1" >>confdefs.h + +else + case " $LIBOBJS " in + *" pwritev.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS pwritev.$ac_objext" + ;; +esac + +fi + ac_fn_c_check_func "$LINENO" "random" "ac_cv_func_random" if test "x$ac_cv_func_random" = xyes; then : $as_echo "#define HAVE_RANDOM 1" >>confdefs.h diff --git a/configure.ac b/configure.ac index 838d47dc22e2a..868a94c9ba972 100644 --- a/configure.ac +++ b/configure.ac @@ -1661,12 +1661,8 @@ AC_CHECK_FUNCS(m4_normalize([ poll posix_fallocate ppoll - pread - preadv pstat pthread_is_threaded_np - pwrite - pwritev readlink readv setproctitle @@ -1740,6 +1736,10 @@ AC_REPLACE_FUNCS(m4_normalize([ inet_aton link mkdtemp + pread + preadv + pwrite + pwritev random srandom strlcat diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c index 931ed679307b2..b58502837aa59 100644 --- a/src/backend/storage/file/fd.c +++ b/src/backend/storage/file/fd.c @@ -92,6 +92,7 @@ #include "common/file_utils.h" #include "miscadmin.h" #include "pgstat.h" +#include "port/pg_iovec.h" #include "portability/mem.h" #include "storage/fd.h" #include "storage/ipc.h" @@ -3635,3 +3636,67 @@ data_sync_elevel(int elevel) { return data_sync_retry ? elevel : PANIC; } + +/* + * A convenience wrapper for pg_pwritev() that retries on partial write. If an + * error is returned, it is unspecified how much has been written. + */ +ssize_t +pg_pwritev_with_retry(int fd, const struct iovec *iov, int iovcnt, off_t offset) +{ + struct iovec iov_copy[PG_IOV_MAX]; + ssize_t sum = 0; + ssize_t part; + + /* We'd better have space to make a copy, in case we need to retry. */ + if (iovcnt > PG_IOV_MAX) + { + errno = EINVAL; + return -1; + } + + for (;;) + { + /* Write as much as we can. */ + part = pg_pwritev(fd, iov, iovcnt, offset); + if (part < 0) + return -1; + +#ifdef SIMULATE_SHORT_WRITE + part = Min(part, 4096); +#endif + + /* Count our progress. */ + sum += part; + offset += part; + + /* Step over iovecs that are done. */ + while (iovcnt > 0 && iov->iov_len <= part) + { + part -= iov->iov_len; + ++iov; + --iovcnt; + } + + /* Are they all done? */ + if (iovcnt == 0) + { + /* We don't expect the kernel to write more than requested. */ + Assert(part == 0); + break; + } + + /* + * Move whatever's left to the front of our mutable copy and adjust + * the leading iovec. + */ + Assert(iovcnt > 0); + memmove(iov_copy, iov, sizeof(*iov) * iovcnt); + Assert(iov->iov_len > part); + iov_copy[0].iov_base = (char *) iov_copy[0].iov_base + part; + iov_copy[0].iov_len -= part; + iov = iov_copy; + } + + return sum; +} diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h index f2662a96fd7bb..c430072af61d8 100644 --- a/src/include/storage/fd.h +++ b/src/include/storage/fd.h @@ -45,6 +45,7 @@ #include +struct iovec; /* avoid including port/pg_iovec.h here */ typedef int File; @@ -161,6 +162,10 @@ extern int durable_unlink(const char *fname, int loglevel); extern int durable_rename_excl(const char *oldfile, const char *newfile, int loglevel); extern void SyncDataDirectory(void); extern int data_sync_elevel(int elevel); +extern ssize_t pg_pwritev_with_retry(int fd, + const struct iovec *iov, + int iovcnt, + off_t offset); /* Filename components */ #define PG_TEMP_FILES_DIR "pgsql_tmp" diff --git a/src/port/Makefile b/src/port/Makefile index bc4923ce840e1..e41b005c4f1bf 100644 --- a/src/port/Makefile +++ b/src/port/Makefile @@ -53,8 +53,6 @@ OBJS = \ pgstrcasecmp.o \ pgstrsignal.o \ pqsignal.o \ - pread.o \ - pwrite.o \ qsort.o \ qsort_arg.o \ quotes.o \ diff --git a/src/port/pread.c b/src/port/pread.c index a5ae2759fa0e5..486f07a7dffcc 100644 --- a/src/port/pread.c +++ b/src/port/pread.c @@ -1,7 +1,7 @@ /*------------------------------------------------------------------------- * * pread.c - * Implementation of pread[v](2) for platforms that lack one. + * Implementation of pread(2) for platforms that lack one. * * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * @@ -9,8 +9,7 @@ * src/port/pread.c * * Note that this implementation changes the current file position, unlike - * the POSIX function, so we use the name pg_pread(). Likewise for the - * iovec version. + * the POSIX function, so we use the name pg_pread(). * *------------------------------------------------------------------------- */ @@ -24,9 +23,6 @@ #include #endif -#include "port/pg_iovec.h" - -#ifndef HAVE_PREAD ssize_t pg_pread(int fd, void *buf, size_t size, off_t offset) { @@ -60,38 +56,3 @@ pg_pread(int fd, void *buf, size_t size, off_t offset) return read(fd, buf, size); #endif } -#endif - -#ifndef HAVE_PREADV -ssize_t -pg_preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) -{ -#ifdef HAVE_READV - if (iovcnt == 1) - return pg_pread(fd, iov[0].iov_base, iov[0].iov_len, offset); - if (lseek(fd, offset, SEEK_SET) < 0) - return -1; - return readv(fd, iov, iovcnt); -#else - ssize_t sum = 0; - ssize_t part; - - for (int i = 0; i < iovcnt; ++i) - { - part = pg_pread(fd, iov[i].iov_base, iov[i].iov_len, offset); - if (part < 0) - { - if (i == 0) - return -1; - else - return sum; - } - sum += part; - offset += part; - if (part < iov[i].iov_len) - return sum; - } - return sum; -#endif -} -#endif diff --git a/src/port/preadv.c b/src/port/preadv.c new file mode 100644 index 0000000000000..29c808cd0c256 --- /dev/null +++ b/src/port/preadv.c @@ -0,0 +1,58 @@ +/*------------------------------------------------------------------------- + * + * preadv.c + * Implementation of preadv(2) for platforms that lack one. + * + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/port/preadv.c + * + * Note that this implementation changes the current file position, unlike + * the POSIX-like function, so we use the name pg_preadv(). + * + *------------------------------------------------------------------------- + */ + + +#include "postgres.h" + +#ifdef WIN32 +#include +#else +#include +#endif + +#include "port/pg_iovec.h" + +ssize_t +pg_preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) +{ +#ifdef HAVE_READV + if (iovcnt == 1) + return pg_pread(fd, iov[0].iov_base, iov[0].iov_len, offset); + if (lseek(fd, offset, SEEK_SET) < 0) + return -1; + return readv(fd, iov, iovcnt); +#else + ssize_t sum = 0; + ssize_t part; + + for (int i = 0; i < iovcnt; ++i) + { + part = pg_pread(fd, iov[i].iov_base, iov[i].iov_len, offset); + if (part < 0) + { + if (i == 0) + return -1; + else + return sum; + } + sum += part; + offset += part; + if (part < iov[i].iov_len) + return sum; + } + return sum; +#endif +} diff --git a/src/port/pwrite.c b/src/port/pwrite.c index a98343ec05b70..282b27115e509 100644 --- a/src/port/pwrite.c +++ b/src/port/pwrite.c @@ -1,7 +1,7 @@ /*------------------------------------------------------------------------- * * pwrite.c - * Implementation of pwrite[v](2) for platforms that lack one. + * Implementation of pwrite(2) for platforms that lack one. * * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group * @@ -9,8 +9,7 @@ * src/port/pwrite.c * * Note that this implementation changes the current file position, unlike - * the POSIX function, so we use the name pg_pwrite(). Likewise for the - * iovec version. + * the POSIX function, so we use the name pg_pwrite(). * *------------------------------------------------------------------------- */ @@ -24,9 +23,6 @@ #include #endif -#include "port/pg_iovec.h" - -#ifndef HAVE_PWRITE ssize_t pg_pwrite(int fd, const void *buf, size_t size, off_t offset) { @@ -57,102 +53,3 @@ pg_pwrite(int fd, const void *buf, size_t size, off_t offset) return write(fd, buf, size); #endif } -#endif - -#ifndef HAVE_PWRITEV -ssize_t -pg_pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) -{ -#ifdef HAVE_WRITEV - if (iovcnt == 1) - return pg_pwrite(fd, iov[0].iov_base, iov[0].iov_len, offset); - if (lseek(fd, offset, SEEK_SET) < 0) - return -1; - return writev(fd, iov, iovcnt); -#else - ssize_t sum = 0; - ssize_t part; - - for (int i = 0; i < iovcnt; ++i) - { - part = pg_pwrite(fd, iov[i].iov_base, iov[i].iov_len, offset); - if (part < 0) - { - if (i == 0) - return -1; - else - return sum; - } - sum += part; - offset += part; - if (part < iov[i].iov_len) - return sum; - } - return sum; -#endif -} -#endif - -/* - * A convenience wrapper for pg_pwritev() that retries on partial write. If an - * error is returned, it is unspecified how much has been written. - */ -ssize_t -pg_pwritev_with_retry(int fd, const struct iovec *iov, int iovcnt, off_t offset) -{ - struct iovec iov_copy[PG_IOV_MAX]; - ssize_t sum = 0; - ssize_t part; - - /* We'd better have space to make a copy, in case we need to retry. */ - if (iovcnt > PG_IOV_MAX) - { - errno = EINVAL; - return -1; - } - - for (;;) - { - /* Write as much as we can. */ - part = pg_pwritev(fd, iov, iovcnt, offset); - if (part < 0) - return -1; - -#ifdef SIMULATE_SHORT_WRITE - part = Min(part, 4096); -#endif - - /* Count our progress. */ - sum += part; - offset += part; - - /* Step over iovecs that are done. */ - while (iovcnt > 0 && iov->iov_len <= part) - { - part -= iov->iov_len; - ++iov; - --iovcnt; - } - - /* Are they all done? */ - if (iovcnt == 0) - { - /* We don't expect the kernel to write more than requested. */ - Assert(part == 0); - break; - } - - /* - * Move whatever's left to the front of our mutable copy and adjust - * the leading iovec. - */ - Assert(iovcnt > 0); - memmove(iov_copy, iov, sizeof(*iov) * iovcnt); - Assert(iov->iov_len > part); - iov_copy[0].iov_base = (char *) iov_copy[0].iov_base + part; - iov_copy[0].iov_len -= part; - iov = iov_copy; - } - - return sum; -} diff --git a/src/port/pwritev.c b/src/port/pwritev.c new file mode 100644 index 0000000000000..2e8ef7e3785a1 --- /dev/null +++ b/src/port/pwritev.c @@ -0,0 +1,58 @@ +/*------------------------------------------------------------------------- + * + * pwritev.c + * Implementation of pwritev(2) for platforms that lack one. + * + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/port/pwritev.c + * + * Note that this implementation changes the current file position, unlike + * the POSIX-like function, so we use the name pg_pwritev(). + * + *------------------------------------------------------------------------- + */ + + +#include "postgres.h" + +#ifdef WIN32 +#include +#else +#include +#endif + +#include "port/pg_iovec.h" + +ssize_t +pg_pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) +{ +#ifdef HAVE_WRITEV + if (iovcnt == 1) + return pg_pwrite(fd, iov[0].iov_base, iov[0].iov_len, offset); + if (lseek(fd, offset, SEEK_SET) < 0) + return -1; + return writev(fd, iov, iovcnt); +#else + ssize_t sum = 0; + ssize_t part; + + for (int i = 0; i < iovcnt; ++i) + { + part = pg_pwrite(fd, iov[i].iov_base, iov[i].iov_len, offset); + if (part < 0) + { + if (i == 0) + return -1; + else + return sum; + } + sum += part; + offset += part; + if (part < iov[i].iov_len) + return sum; + } + return sum; +#endif +} diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm index 7f014a12c9a47..535b67e668cb0 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -99,7 +99,7 @@ sub mkvcbuild srandom.c getaddrinfo.c gettimeofday.c inet_net_ntop.c kill.c open.c erand48.c snprintf.c strlcat.c strlcpy.c dirmod.c noblock.c path.c dirent.c dlopen.c getopt.c getopt_long.c link.c - pread.c pwrite.c pg_bitutils.c + pread.c preadv.c pwrite.c pwritev.c pg_bitutils.c pg_strong_random.c pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c pqsignal.c mkdtemp.c qsort.c qsort_arg.c quotes.c system.c strerror.c tar.c thread.c From aef8948f38d9f3aa58bf8c2d4c6f62a7a456a9d1 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Thu, 14 Jan 2021 11:13:24 +0900 Subject: [PATCH 099/240] Rework refactoring of hex and encoding routines This commit addresses some issues with c3826f83 that moved the hex decoding routine to src/common/: - The decoding function lacked overflow checks, so when used for security-related features it was an open door to out-of-bound writes if not carefully used that could remain undetected. Like the base64 routines already in src/common/ used by SCRAM, this routine is reworked to check for overflows by having the size of the destination buffer passed as argument, with overflows checked before doing any writes. - The encoding routine was missing. This is moved to src/common/ and it gains the same overflow checks as the decoding part. On failure, the hex routines of src/common/ issue an error as per the discussion done to make them usable by frontend tools, but not by shared libraries. Note that this is why ECPG is left out of this commit, and it still includes a duplicated logic doing hex encoding and decoding. While on it, this commit uses better variable names for the source and destination buffers in the existing escape and base64 routines in encode.c and it makes them more robust to overflow detection. The previous core code issued a FATAL after doing out-of-bound writes if going through the SQL functions, which would be enough to detect problems when working on changes that impacted this area of the code. Instead, an error is issued before doing an out-of-bound write. The hex routines were being directly called for bytea conversions and backup manifests without such sanity checks. The current calls happen to not have any problems, but careless uses of such APIs could easily lead to CVE-class bugs. Author: Bruce Momjian, Michael Paquier Reviewed-by: Sehrope Sarkuni Discussion: https://postgr.es/m/20201231003557.GB22199@momjian.us --- src/backend/replication/backup_manifest.c | 28 ++-- src/backend/utils/adt/encode.c | 96 ++++++----- src/backend/utils/adt/varlena.c | 16 +- src/common/Makefile | 2 +- src/common/hex.c | 192 ++++++++++++++++++++++ src/common/hex_decode.c | 106 ------------ src/include/common/hex.h | 25 +++ src/include/common/hex_decode.h | 16 -- src/include/utils/builtins.h | 3 - src/tools/msvc/Mkvcbuild.pm | 2 +- 10 files changed, 304 insertions(+), 182 deletions(-) create mode 100644 src/common/hex.c delete mode 100644 src/common/hex_decode.c create mode 100644 src/include/common/hex.h delete mode 100644 src/include/common/hex_decode.h diff --git a/src/backend/replication/backup_manifest.c b/src/backend/replication/backup_manifest.c index 8af94610b3989..0cefd181b5a11 100644 --- a/src/backend/replication/backup_manifest.c +++ b/src/backend/replication/backup_manifest.c @@ -13,11 +13,11 @@ #include "postgres.h" #include "access/timeline.h" +#include "common/hex.h" #include "libpq/libpq.h" #include "libpq/pqformat.h" #include "mb/pg_wchar.h" #include "replication/backup_manifest.h" -#include "utils/builtins.h" #include "utils/json.h" static void AppendStringToManifest(backup_manifest_info *manifest, char *s); @@ -150,10 +150,12 @@ AddFileToBackupManifest(backup_manifest_info *manifest, const char *spcoid, } else { + uint64 dstlen = pg_hex_enc_len(pathlen); + appendStringInfoString(&buf, "{ \"Encoded-Path\": \""); - enlargeStringInfo(&buf, 2 * pathlen); - buf.len += hex_encode(pathname, pathlen, - &buf.data[buf.len]); + enlargeStringInfo(&buf, dstlen); + buf.len += pg_hex_encode(pathname, pathlen, + &buf.data[buf.len], dstlen); appendStringInfoString(&buf, "\", "); } @@ -176,6 +178,7 @@ AddFileToBackupManifest(backup_manifest_info *manifest, const char *spcoid, { uint8 checksumbuf[PG_CHECKSUM_MAX_LENGTH]; int checksumlen; + uint64 dstlen; checksumlen = pg_checksum_final(checksum_ctx, checksumbuf); if (checksumlen < 0) @@ -185,9 +188,10 @@ AddFileToBackupManifest(backup_manifest_info *manifest, const char *spcoid, appendStringInfo(&buf, ", \"Checksum-Algorithm\": \"%s\", \"Checksum\": \"", pg_checksum_type_name(checksum_ctx->type)); - enlargeStringInfo(&buf, 2 * checksumlen); - buf.len += hex_encode((char *) checksumbuf, checksumlen, - &buf.data[buf.len]); + dstlen = pg_hex_enc_len(checksumlen); + enlargeStringInfo(&buf, dstlen); + buf.len += pg_hex_encode((char *) checksumbuf, checksumlen, + &buf.data[buf.len], dstlen); appendStringInfoChar(&buf, '"'); } @@ -307,8 +311,9 @@ SendBackupManifest(backup_manifest_info *manifest) { StringInfoData protobuf; uint8 checksumbuf[PG_SHA256_DIGEST_LENGTH]; - char checksumstringbuf[PG_SHA256_DIGEST_STRING_LENGTH]; + char *checksumstringbuf; size_t manifest_bytes_done = 0; + uint64 dstlen; if (!IsManifestEnabled(manifest)) return; @@ -328,8 +333,11 @@ SendBackupManifest(backup_manifest_info *manifest) if (pg_cryptohash_final(manifest->manifest_ctx, checksumbuf) < 0) elog(ERROR, "failed to finalize checksum of backup manifest"); AppendStringToManifest(manifest, "\"Manifest-Checksum\": \""); - hex_encode((char *) checksumbuf, sizeof checksumbuf, checksumstringbuf); - checksumstringbuf[PG_SHA256_DIGEST_STRING_LENGTH - 1] = '\0'; + dstlen = pg_hex_enc_len(PG_SHA256_DIGEST_LENGTH); + checksumstringbuf = palloc0(dstlen + 1); /* includes \0 */ + pg_hex_encode((char *) checksumbuf, sizeof checksumbuf, + checksumstringbuf, dstlen); + checksumstringbuf[dstlen] = '\0'; AppendStringToManifest(manifest, checksumstringbuf); AppendStringToManifest(manifest, "\"}\n"); diff --git a/src/backend/utils/adt/encode.c b/src/backend/utils/adt/encode.c index 4759be25e915c..8449aaac56ace 100644 --- a/src/backend/utils/adt/encode.c +++ b/src/backend/utils/adt/encode.c @@ -15,7 +15,7 @@ #include -#include "common/hex_decode.h" +#include "common/hex.h" #include "mb/pg_wchar.h" #include "utils/builtins.h" #include "utils/memutils.h" @@ -32,10 +32,12 @@ */ struct pg_encoding { - uint64 (*encode_len) (const char *data, size_t dlen); - uint64 (*decode_len) (const char *data, size_t dlen); - uint64 (*encode) (const char *data, size_t dlen, char *res); - uint64 (*decode) (const char *data, size_t dlen, char *res); + uint64 (*encode_len) (const char *src, size_t srclen); + uint64 (*decode_len) (const char *src, size_t srclen); + uint64 (*encode) (const char *src, size_t srclen, + char *dst, size_t dstlen); + uint64 (*decode) (const char *src, size_t srclen, + char *dst, size_t dstlen); }; static const struct pg_encoding *pg_find_encoding(const char *name); @@ -81,11 +83,7 @@ binary_encode(PG_FUNCTION_ARGS) result = palloc(VARHDRSZ + resultlen); - res = enc->encode(dataptr, datalen, VARDATA(result)); - - /* Make this FATAL 'cause we've trodden on memory ... */ - if (res > resultlen) - elog(FATAL, "overflow - encode estimate too small"); + res = enc->encode(dataptr, datalen, VARDATA(result), resultlen); SET_VARSIZE(result, VARHDRSZ + res); @@ -129,11 +127,7 @@ binary_decode(PG_FUNCTION_ARGS) result = palloc(VARHDRSZ + resultlen); - res = enc->decode(dataptr, datalen, VARDATA(result)); - - /* Make this FATAL 'cause we've trodden on memory ... */ - if (res > resultlen) - elog(FATAL, "overflow - decode estimate too small"); + res = enc->decode(dataptr, datalen, VARDATA(result), resultlen); SET_VARSIZE(result, VARHDRSZ + res); @@ -145,32 +139,20 @@ binary_decode(PG_FUNCTION_ARGS) * HEX */ -static const char hextbl[] = "0123456789abcdef"; - -uint64 -hex_encode(const char *src, size_t len, char *dst) -{ - const char *end = src + len; - - while (src < end) - { - *dst++ = hextbl[(*src >> 4) & 0xF]; - *dst++ = hextbl[*src & 0xF]; - src++; - } - return (uint64) len * 2; -} - +/* + * Those two wrappers are still needed to match with the layer of + * src/common/. + */ static uint64 hex_enc_len(const char *src, size_t srclen) { - return (uint64) srclen << 1; + return pg_hex_enc_len(srclen); } static uint64 hex_dec_len(const char *src, size_t srclen) { - return (uint64) srclen >> 1; + return pg_hex_dec_len(srclen); } /* @@ -192,12 +174,12 @@ static const int8 b64lookup[128] = { }; static uint64 -pg_base64_encode(const char *src, size_t len, char *dst) +pg_base64_encode(const char *src, size_t srclen, char *dst, size_t dstlen) { char *p, *lend = dst + 76; const char *s, - *end = src + len; + *end = src + srclen; int pos = 2; uint32 buf = 0; @@ -213,6 +195,8 @@ pg_base64_encode(const char *src, size_t len, char *dst) /* write it out */ if (pos < 0) { + if ((p - dst + 4) > dstlen) + elog(ERROR, "overflow of destination buffer in base64 encoding"); *p++ = _base64[(buf >> 18) & 0x3f]; *p++ = _base64[(buf >> 12) & 0x3f]; *p++ = _base64[(buf >> 6) & 0x3f]; @@ -223,25 +207,30 @@ pg_base64_encode(const char *src, size_t len, char *dst) } if (p >= lend) { + if ((p - dst + 1) > dstlen) + elog(ERROR, "overflow of destination buffer in base64 encoding"); *p++ = '\n'; lend = p + 76; } } if (pos != 2) { + if ((p - dst + 4) > dstlen) + elog(ERROR, "overflow of destination buffer in base64 encoding"); *p++ = _base64[(buf >> 18) & 0x3f]; *p++ = _base64[(buf >> 12) & 0x3f]; *p++ = (pos == 0) ? _base64[(buf >> 6) & 0x3f] : '='; *p++ = '='; } + Assert((p - dst) <= dstlen); return p - dst; } static uint64 -pg_base64_decode(const char *src, size_t len, char *dst) +pg_base64_decode(const char *src, size_t srclen, char *dst, size_t dstlen) { - const char *srcend = src + len, + const char *srcend = src + srclen, *s = src; char *p = dst; char c; @@ -289,11 +278,21 @@ pg_base64_decode(const char *src, size_t len, char *dst) pos++; if (pos == 4) { + if ((p - dst + 1) > dstlen) + elog(ERROR, "overflow of destination buffer in base64 decoding"); *p++ = (buf >> 16) & 255; if (end == 0 || end > 1) + { + if ((p - dst + 1) > dstlen) + elog(ERROR, "overflow of destination buffer in base64 decoding"); *p++ = (buf >> 8) & 255; + } if (end == 0 || end > 2) + { + if ((p - dst + 1) > dstlen) + elog(ERROR, "overflow of destination buffer in base64 decoding"); *p++ = buf & 255; + } buf = 0; pos = 0; } @@ -305,6 +304,7 @@ pg_base64_decode(const char *src, size_t len, char *dst) errmsg("invalid base64 end sequence"), errhint("Input data is missing padding, is truncated, or is otherwise corrupted."))); + Assert((p - dst) <= dstlen); return p - dst; } @@ -340,7 +340,7 @@ pg_base64_dec_len(const char *src, size_t srclen) #define DIG(VAL) ((VAL) + '0') static uint64 -esc_encode(const char *src, size_t srclen, char *dst) +esc_encode(const char *src, size_t srclen, char *dst, size_t dstlen) { const char *end = src + srclen; char *rp = dst; @@ -352,6 +352,8 @@ esc_encode(const char *src, size_t srclen, char *dst) if (c == '\0' || IS_HIGHBIT_SET(c)) { + if ((rp - dst + 4) > dstlen) + elog(ERROR, "overflow of destination buffer in escape encoding"); rp[0] = '\\'; rp[1] = DIG(c >> 6); rp[2] = DIG((c >> 3) & 7); @@ -361,6 +363,8 @@ esc_encode(const char *src, size_t srclen, char *dst) } else if (c == '\\') { + if ((rp - dst + 2) > dstlen) + elog(ERROR, "overflow of destination buffer in escape encoding"); rp[0] = '\\'; rp[1] = '\\'; rp += 2; @@ -368,6 +372,8 @@ esc_encode(const char *src, size_t srclen, char *dst) } else { + if ((rp - dst + 1) > dstlen) + elog(ERROR, "overflow of destination buffer in escape encoding"); *rp++ = c; len++; } @@ -375,11 +381,12 @@ esc_encode(const char *src, size_t srclen, char *dst) src++; } + Assert((rp - dst) <= dstlen); return len; } static uint64 -esc_decode(const char *src, size_t srclen, char *dst) +esc_decode(const char *src, size_t srclen, char *dst, size_t dstlen) { const char *end = src + srclen; char *rp = dst; @@ -388,7 +395,11 @@ esc_decode(const char *src, size_t srclen, char *dst) while (src < end) { if (src[0] != '\\') + { + if ((rp - dst + 1) > dstlen) + elog(ERROR, "overflow of destination buffer in escape decoding"); *rp++ = *src++; + } else if (src + 3 < end && (src[1] >= '0' && src[1] <= '3') && (src[2] >= '0' && src[2] <= '7') && @@ -400,12 +411,16 @@ esc_decode(const char *src, size_t srclen, char *dst) val <<= 3; val += VAL(src[2]); val <<= 3; + if ((rp - dst + 1) > dstlen) + elog(ERROR, "overflow of destination buffer in escape decoding"); *rp++ = val + VAL(src[3]); src += 4; } else if (src + 1 < end && (src[1] == '\\')) { + if ((rp - dst + 1) > dstlen) + elog(ERROR, "overflow of destination buffer in escape decoding"); *rp++ = '\\'; src += 2; } @@ -423,6 +438,7 @@ esc_decode(const char *src, size_t srclen, char *dst) len++; } + Assert((rp - dst) <= dstlen); return len; } @@ -504,7 +520,7 @@ static const struct { "hex", { - hex_enc_len, hex_dec_len, hex_encode, hex_decode + hex_enc_len, hex_dec_len, pg_hex_encode, pg_hex_decode } }, { diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index 4838bfb4ff0c6..479ed9ae54cd9 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -21,8 +21,8 @@ #include "catalog/pg_collation.h" #include "catalog/pg_type.h" #include "common/hashfn.h" +#include "common/hex.h" #include "common/int.h" -#include "common/hex_decode.h" #include "common/unicode_norm.h" #include "lib/hyperloglog.h" #include "libpq/pqformat.h" @@ -304,10 +304,12 @@ byteain(PG_FUNCTION_ARGS) if (inputText[0] == '\\' && inputText[1] == 'x') { size_t len = strlen(inputText); + uint64 dstlen = pg_hex_dec_len(len - 2); - bc = (len - 2) / 2 + VARHDRSZ; /* maximum possible length */ + bc = dstlen + VARHDRSZ; /* maximum possible length */ result = palloc(bc); - bc = hex_decode(inputText + 2, len - 2, VARDATA(result)); + + bc = pg_hex_decode(inputText + 2, len - 2, VARDATA(result), dstlen); SET_VARSIZE(result, bc + VARHDRSZ); /* actual length */ PG_RETURN_BYTEA_P(result); @@ -396,11 +398,15 @@ byteaout(PG_FUNCTION_ARGS) if (bytea_output == BYTEA_OUTPUT_HEX) { + uint64 dstlen = pg_hex_enc_len(VARSIZE_ANY_EXHDR(vlena)); + /* Print hex format */ - rp = result = palloc(VARSIZE_ANY_EXHDR(vlena) * 2 + 2 + 1); + rp = result = palloc(dstlen + 2 + 1); *rp++ = '\\'; *rp++ = 'x'; - rp += hex_encode(VARDATA_ANY(vlena), VARSIZE_ANY_EXHDR(vlena), rp); + + rp += pg_hex_encode(VARDATA_ANY(vlena), VARSIZE_ANY_EXHDR(vlena), rp, + dstlen); } else if (bytea_output == BYTEA_OUTPUT_ESCAPE) { diff --git a/src/common/Makefile b/src/common/Makefile index f62497793956f..93eb27a2aa4e0 100644 --- a/src/common/Makefile +++ b/src/common/Makefile @@ -58,7 +58,7 @@ OBJS_COMMON = \ file_perm.o \ file_utils.o \ hashfn.o \ - hex_decode.o \ + hex.o \ ip.o \ jsonapi.o \ keywords.o \ diff --git a/src/common/hex.c b/src/common/hex.c new file mode 100644 index 0000000000000..e4878ba253dc7 --- /dev/null +++ b/src/common/hex.c @@ -0,0 +1,192 @@ +/*------------------------------------------------------------------------- + * + * hex.c + * Encoding and decoding routines for hex. + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/common/hex.c + * + *------------------------------------------------------------------------- + */ + + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include "common/hex.h" +#ifdef FRONTEND +#include "common/logging.h" +#endif +#include "mb/pg_wchar.h" + + +static const int8 hexlookup[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +}; + +static const char hextbl[] = "0123456789abcdef"; + +static inline char +get_hex(const char *cp) +{ + unsigned char c = (unsigned char) *cp; + int res = -1; + + if (c < 127) + res = hexlookup[c]; + + if (res < 0) + { +#ifdef FRONTEND + pg_log_fatal("invalid hexadecimal digit"); + exit(EXIT_FAILURE); +#else + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid hexadecimal digit: \"%.*s\"", + pg_mblen(cp), cp))); +#endif + } + + return (char) res; +} + +/* + * pg_hex_encode + * + * Encode into hex the given string. Returns the length of the encoded + * string. + */ +uint64 +pg_hex_encode(const char *src, size_t srclen, char *dst, size_t dstlen) +{ + const char *end = src + srclen; + char *p; + + p = dst; + + while (src < end) + { + /* + * Leave if there is an overflow in the area allocated for the encoded + * string. + */ + if ((p - dst + 2) > dstlen) + { +#ifdef FRONTEND + pg_log_fatal("overflow of destination buffer in hex encoding"); + exit(EXIT_FAILURE); +#else + elog(ERROR, "overflow of destination buffer in hex encoding"); +#endif + } + + *p++ = hextbl[(*src >> 4) & 0xF]; + *p++ = hextbl[*src & 0xF]; + src++; + } + + Assert((p - dst) <= dstlen); + return p - dst; +} + +/* + * pg_hex_decode + * + * Decode the given hex string. Returns the length of the decoded string. + */ +uint64 +pg_hex_decode(const char *src, size_t srclen, char *dst, size_t dstlen) +{ + const char *s, + *srcend; + char v1, + v2, + *p; + + srcend = src + srclen; + s = src; + p = dst; + while (s < srcend) + { + if (*s == ' ' || *s == '\n' || *s == '\t' || *s == '\r') + { + s++; + continue; + } + v1 = get_hex(s) << 4; + s++; + + if (s >= srcend) + { +#ifdef FRONTEND + pg_log_fatal("invalid hexadecimal data: odd number of digits"); + exit(EXIT_FAILURE); +#else + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid hexadecimal data: odd number of digits"))); +#endif + } + + v2 = get_hex(s); + s++; + + /* overflow check */ + if ((p - dst + 1) > dstlen) + { +#ifdef FRONTEND + pg_log_fatal("overflow of destination buffer in hex decoding"); + exit(EXIT_FAILURE); +#else + elog(ERROR, "overflow of destination buffer in hex decoding"); +#endif + } + + *p++ = v1 | v2; + } + + Assert((p - dst) <= dstlen); + return p - dst; +} + +/* + * pg_hex_enc_len + * + * Returns to caller the length of the string if it were encoded with + * hex based on the length provided by caller. This is useful to estimate + * how large a buffer allocation needs to be done before doing the actual + * encoding. + */ +uint64 +pg_hex_enc_len(size_t srclen) +{ + return (uint64) srclen << 1; +} + +/* + * pg_hex_dec_len + * + * Returns to caller the length of the string if it were to be decoded + * with hex, based on the length given by caller. This is useful to + * estimate how large a buffer allocation needs to be done before doing + * the actual decoding. + */ +uint64 +pg_hex_dec_len(size_t srclen) +{ + return (uint64) srclen >> 1; +} diff --git a/src/common/hex_decode.c b/src/common/hex_decode.c deleted file mode 100644 index dbc0e1c30aa6a..0000000000000 --- a/src/common/hex_decode.c +++ /dev/null @@ -1,106 +0,0 @@ -/*------------------------------------------------------------------------- - * - * hex_decode.c - * hex decoding - * - * - * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * src/common/hex_decode.c - * - *------------------------------------------------------------------------- - */ - - -#ifndef FRONTEND -#include "postgres.h" -#else -#include "postgres_fe.h" -#endif - -#ifdef FRONTEND -#include "common/logging.h" -#else -#include "mb/pg_wchar.h" -#endif -#include "common/hex_decode.h" - - -static const int8 hexlookup[128] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -}; - -static inline char -get_hex(const char *cp) -{ - unsigned char c = (unsigned char) *cp; - int res = -1; - - if (c < 127) - res = hexlookup[c]; - - if (res < 0) - { -#ifdef FRONTEND - pg_log_fatal("invalid hexadecimal digit"); - exit(EXIT_FAILURE); -#else - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid hexadecimal digit: \"%.*s\"", - pg_mblen(cp), cp))); -#endif - } - - return (char) res; -} - -uint64 -hex_decode(const char *src, size_t len, char *dst) -{ - const char *s, - *srcend; - char v1, - v2, - *p; - - srcend = src + len; - s = src; - p = dst; - while (s < srcend) - { - if (*s == ' ' || *s == '\n' || *s == '\t' || *s == '\r') - { - s++; - continue; - } - v1 = get_hex(s) << 4; - s++; - if (s >= srcend) - { -#ifdef FRONTEND - pg_log_fatal("invalid hexadecimal data: odd number of digits"); - exit(EXIT_FAILURE); -#else - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid hexadecimal data: odd number of digits"))); -#endif - } - v2 = get_hex(s); - s++; - *p++ = v1 | v2; - } - - return p - dst; -} diff --git a/src/include/common/hex.h b/src/include/common/hex.h new file mode 100644 index 0000000000000..3c3c956bb66cd --- /dev/null +++ b/src/include/common/hex.h @@ -0,0 +1,25 @@ +/*------------------------------------------------------------------------ + * + * hex.h + * Encoding and decoding routines for hex strings. + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/common/hex.h + * + *------------------------------------------------------------------------ + */ + +#ifndef COMMON_HEX_H +#define COMMON_HEX_H + +extern uint64 pg_hex_decode(const char *src, size_t srclen, + char *dst, size_t dstlen); +extern uint64 pg_hex_encode(const char *src, size_t srclen, + char *dst, size_t dstlen); +extern uint64 pg_hex_enc_len(size_t srclen); +extern uint64 pg_hex_dec_len(size_t srclen); + +#endif /* COMMON_HEX_H */ diff --git a/src/include/common/hex_decode.h b/src/include/common/hex_decode.h deleted file mode 100644 index 29ab2484585d4..0000000000000 --- a/src/include/common/hex_decode.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * hex_decode.h - * hex decoding - * - * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * src/include/common/hex_decode.h - */ -#ifndef COMMON_HEX_DECODE_H -#define COMMON_HEX_DECODE_H - -extern uint64 hex_decode(const char *src, size_t len, char *dst); - - -#endif /* COMMON_HEX_DECODE_H */ diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 6f739a882204c..27d2f2ffb3465 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -31,9 +31,6 @@ extern void domain_check(Datum value, bool isnull, Oid domainType, extern int errdatatype(Oid datatypeOid); extern int errdomainconstraint(Oid datatypeOid, const char *conname); -/* encode.c */ -extern uint64 hex_encode(const char *src, size_t len, char *dst); - /* int.c */ extern int2vector *buildint2vector(const int16 *int2s, int n); diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm index 535b67e668cb0..5634b2d40c02f 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -121,7 +121,7 @@ sub mkvcbuild our @pgcommonallfiles = qw( archive.c base64.c checksum_helper.c config_info.c controldata_utils.c d2s.c encnames.c exec.c - f2s.c file_perm.c file_utils.c hashfn.c hex_decode.c ip.c jsonapi.c + f2s.c file_perm.c file_utils.c hashfn.c hex.c ip.c jsonapi.c keywords.c kwlookup.c link-canary.c md5_common.c pg_get_line.c pg_lzcompress.c pgfnames.c psprintf.c relpath.c rmtree.c saslprep.c scram-common.c string.c stringinfo.c unicode_norm.c username.c From fef5b47f6bfc9bfec619bb2e6e66b027e7ff21a3 Mon Sep 17 00:00:00 2001 From: Fujii Masao Date: Thu, 14 Jan 2021 12:27:11 +0900 Subject: [PATCH 100/240] Ensure that a standby is able to follow a primary on a newer timeline. Commit 709d003fbd refactored WAL-reading code, but accidentally caused WalSndSegmentOpen() to fail to follow a timeline switch while reading from a historic timeline. This issue caused a standby to fail to follow a primary on a newer timeline when WAL archiving is enabled. If there is a timeline switch within the segment, WalSndSegmentOpen() should read from the WAL segment belonging to the new timeline. But previously since it failed to follow a timeline switch, it tried to read the WAL segment with old timeline. When WAL archiving is enabled, that WAL segment with old timeline doesn't exist because it's renamed to .partial. This leads a primary to have tried to read non-existent WAL segment, and which caused replication to faill with the error "ERROR: requested WAL segment ... has already been removed". This commit fixes WalSndSegmentOpen() so that it's able to follow a timeline switch, to ensure that a standby is able to follow a primary on a newer timeline even when WAL archiving is enabled. This commit also adds the regression test to check whether a standby is able to follow a primary on a newer timeline when WAL archiving is enabled. Back-patch to v13 where the bug was introduced. Reported-by: Kyotaro Horiguchi Author: Kyotaro Horiguchi, tweaked by Fujii Masao Reviewed-by: Alvaro Herrera, Fujii Masao Discussion: https://postgr.es/m/20201209.174314.282492377848029776.horikyota.ntt@gmail.com --- src/backend/replication/walsender.c | 2 +- src/test/recovery/t/004_timeline_switch.pl | 42 ++++++++++++++++++++-- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c index fe0d368a35b01..8545c6c423170 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -2491,7 +2491,7 @@ WalSndSegmentOpen(XLogReaderState *state, XLogSegNo nextSegNo, XLogSegNo endSegNo; XLByteToSeg(sendTimeLineValidUpto, endSegNo, state->segcxt.ws_segsize); - if (state->seg.ws_segno == endSegNo) + if (nextSegNo == endSegNo) *tli_p = sendTimeLineNextTLI; } diff --git a/src/test/recovery/t/004_timeline_switch.pl b/src/test/recovery/t/004_timeline_switch.pl index 1ecdb0eba0d13..8dad044db4b01 100644 --- a/src/test/recovery/t/004_timeline_switch.pl +++ b/src/test/recovery/t/004_timeline_switch.pl @@ -1,15 +1,16 @@ # Test for timeline switch -# Ensure that a cascading standby is able to follow a newly-promoted standby -# on a new timeline. use strict; use warnings; use File::Path qw(rmtree); use PostgresNode; use TestLib; -use Test::More tests => 2; +use Test::More tests => 3; $ENV{PGDATABASE} = 'postgres'; +# Ensure that a cascading standby is able to follow a newly-promoted standby +# on a new timeline. + # Initialize primary node my $node_primary = get_new_node('primary'); $node_primary->init(allows_streaming => 1); @@ -66,3 +67,38 @@ my $result = $node_standby_2->safe_psql('postgres', "SELECT count(*) FROM tab_int"); is($result, qq(2000), 'check content of standby 2'); + + +# Ensure that a standby is able to follow a primary on a newer timeline +# when WAL archiving is enabled. + +# Initialize primary node +my $node_primary_2 = get_new_node('primary_2'); +$node_primary_2->init(allows_streaming => 1, has_archiving => 1); +$node_primary_2->start; + +# Take backup +$node_primary_2->backup($backup_name); + +# Create standby node +my $node_standby_3 = get_new_node('standby_3'); +$node_standby_3->init_from_backup($node_primary_2, $backup_name, + has_streaming => 1); + +# Restart primary node in standby mode and promote it, switching it +# to a new timeline. +$node_primary_2->set_standby_mode; +$node_primary_2->restart; +$node_primary_2->promote; + +# Start standby node, create some content on primary and check its presence +# in standby, to ensure that the timeline switch has been done. +$node_standby_3->start; +$node_primary_2->safe_psql('postgres', + "CREATE TABLE tab_int AS SELECT 1 AS a"); +$node_primary_2->wait_for_catchup($node_standby_3, 'replay', + $node_primary_2->lsn('write')); + +my $result_2 = + $node_standby_3->safe_psql('postgres', "SELECT count(*) FROM tab_int"); +is($result_2, qq(1), 'check content of standby 3'); From fb29ab26b38f1647423bf6aa2991e5fdf9060f08 Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Thu, 14 Jan 2021 18:09:32 +1300 Subject: [PATCH 101/240] Minor header cleanup for the new iovec code. Remove redundant function declaration and improve header comment in pg_iovec.h. Move the new declaration in fd.h next to a group of more similar functions. --- src/include/port/pg_iovec.h | 7 +------ src/include/storage/fd.h | 8 ++++---- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/include/port/pg_iovec.h b/src/include/port/pg_iovec.h index 335f35bf0ebb0..365d605a9b3dc 100644 --- a/src/include/port/pg_iovec.h +++ b/src/include/port/pg_iovec.h @@ -1,7 +1,7 @@ /*------------------------------------------------------------------------- * * pg_iovec.h - * Header for the vectored I/O functions in src/port/p{read,write}.c. + * Header for vectored I/O functions, to use in place of . * * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California @@ -51,9 +51,4 @@ extern ssize_t pg_preadv(int fd, const struct iovec *iov, int iovcnt, off_t offs extern ssize_t pg_pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset); #endif -extern ssize_t pg_pwritev_with_retry(int fd, - const struct iovec *iov, - int iovcnt, - off_t offset); - #endif /* PG_IOVEC_H */ diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h index c430072af61d8..30bf7d2193ffd 100644 --- a/src/include/storage/fd.h +++ b/src/include/storage/fd.h @@ -154,6 +154,10 @@ extern int pg_fsync_no_writethrough(int fd); extern int pg_fsync_writethrough(int fd); extern int pg_fdatasync(int fd); extern void pg_flush_data(int fd, off_t offset, off_t amount); +extern ssize_t pg_pwritev_with_retry(int fd, + const struct iovec *iov, + int iovcnt, + off_t offset); extern int pg_truncate(const char *path, off_t length); extern void fsync_fname(const char *fname, bool isdir); extern int fsync_fname_ext(const char *fname, bool isdir, bool ignore_perm, int elevel); @@ -162,10 +166,6 @@ extern int durable_unlink(const char *fname, int loglevel); extern int durable_rename_excl(const char *oldfile, const char *newfile, int loglevel); extern void SyncDataDirectory(void); extern int data_sync_elevel(int elevel); -extern ssize_t pg_pwritev_with_retry(int fd, - const struct iovec *iov, - int iovcnt, - off_t offset); /* Filename components */ #define PG_TEMP_FILES_DIR "pgsql_tmp" From 3f238b882c276a59f5d98224850e5aee2a3fec8c Mon Sep 17 00:00:00 2001 From: Fujii Masao Date: Thu, 14 Jan 2021 15:41:22 +0900 Subject: [PATCH 102/240] Improve tab-completion for CLOSE, DECLARE, FETCH and MOVE. This commit makes CLOSE, FETCH and MOVE commands tab-complete the list of cursors. Also this commit makes DECLARE command tab-complete the options. Author: Shinya Kato, Sawada Masahiko, tweaked by Fujii Masao Reviewed-by: Shinya Kato, Sawada Masahiko, Fujii Masao Discussion: https://postgr.es/m/b0e4c5c53ef84c5395524f5056fc71f0@MP-MSGSS-MBX001.msg.nttdata.co.jp --- src/bin/psql/tab-complete.c | 76 ++++++++++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 6 deletions(-) diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 9dcab0d2fa415..6abcbea96349a 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -976,6 +976,11 @@ static const SchemaQuery Query_for_list_of_statistics = { " and pg_catalog.pg_table_is_visible(c2.oid)"\ " and c2.relispartition = 'true'" +#define Query_for_list_of_cursors \ +" SELECT pg_catalog.quote_ident(name) "\ +" FROM pg_catalog.pg_cursors "\ +" WHERE substring(pg_catalog.quote_ident(name),1,%d)='%s'" + /* * These object types were introduced later than our support cutoff of * server version 7.4. We use the VersionedQuery infrastructure so that @@ -2284,6 +2289,10 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_VERSIONED_SCHEMA_QUERY(Query_for_list_of_procedures, NULL); else if (Matches("CALL", MatchAny)) COMPLETE_WITH("("); +/* CLOSE */ + else if (Matches("CLOSE")) + COMPLETE_WITH_QUERY(Query_for_list_of_cursors + " UNION SELECT 'ALL'"); /* CLUSTER */ else if (Matches("CLUSTER")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_clusterables, "UNION SELECT 'VERBOSE'"); @@ -3002,11 +3011,44 @@ psql_completion(const char *text, int start, int end) " UNION SELECT 'ALL'"); /* DECLARE */ + + /* + * Complete DECLARE with one of BINARY, INSENSITIVE, SCROLL, NO + * SCROLL, and CURSOR. + */ else if (Matches("DECLARE", MatchAny)) COMPLETE_WITH("BINARY", "INSENSITIVE", "SCROLL", "NO SCROLL", "CURSOR"); + + /* + * Complete DECLARE ... + + + SHARED_DEPENDENCY_TABLESPACE (t) + + + The referenced object (which must be a tablespace) is mentioned as + the tablespace for a relation that doesn't have storage. + + + Other dependency flavors might be needed in future. Note in particular - that the current definition only supports roles as referenced objects. + that the current definition only supports roles and tablespaces as referenced + objects. diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 21f2240ade842..9abc4a1f5563d 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -440,6 +440,15 @@ heap_create(const char *relname, } } + /* + * If a tablespace is specified, removal of that tablespace is normally + * protected by the existence of a physical file; but for relations with + * no files, add a pg_shdepend entry to account for that. + */ + if (!create_storage && reltablespace != InvalidOid) + recordDependencyOnTablespace(RelationRelationId, relid, + reltablespace); + return rel; } diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c index 86c3be107fffc..90b7a5de29962 100644 --- a/src/backend/catalog/pg_shdepend.c +++ b/src/backend/catalog/pg_shdepend.c @@ -59,6 +59,7 @@ #include "commands/schemacmds.h" #include "commands/subscriptioncmds.h" #include "commands/tablecmds.h" +#include "commands/tablespace.h" #include "commands/typecmds.h" #include "miscadmin.h" #include "storage/lmgr.h" @@ -186,11 +187,14 @@ recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner) * * There must be no more than one existing entry for the given dependent * object and dependency type! So in practice this can only be used for - * updating SHARED_DEPENDENCY_OWNER entries, which should have that property. + * updating SHARED_DEPENDENCY_OWNER and SHARED_DEPENDENCY_TABLESPACE + * entries, which should have that property. * * If there is no previous entry, we assume it was referencing a PINned * object, so we create a new entry. If the new referenced object is * PINned, we don't create an entry (and drop the old one, if any). + * (For tablespaces, we don't record dependencies in certain cases, so + * there are other possible reasons for entries to be missing.) * * sdepRel must be the pg_shdepend relation, already opened and suitably * locked. @@ -344,6 +348,58 @@ changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId) table_close(sdepRel, RowExclusiveLock); } +/* + * recordDependencyOnTablespace + * + * A convenient wrapper of recordSharedDependencyOn -- register the specified + * tablespace as default for the given object. + * + * Note: it's the caller's responsibility to ensure that there isn't a + * tablespace entry for the object already. + */ +void +recordDependencyOnTablespace(Oid classId, Oid objectId, Oid tablespace) +{ + ObjectAddress myself, + referenced; + + ObjectAddressSet(myself, classId, objectId); + ObjectAddressSet(referenced, TableSpaceRelationId, tablespace); + + recordSharedDependencyOn(&myself, &referenced, + SHARED_DEPENDENCY_TABLESPACE); +} + +/* + * changeDependencyOnTablespace + * + * Update the shared dependencies to account for the new tablespace. + * + * Note: we don't need an objsubid argument because only whole objects + * have tablespaces. + */ +void +changeDependencyOnTablespace(Oid classId, Oid objectId, Oid newTablespaceId) +{ + Relation sdepRel; + + sdepRel = table_open(SharedDependRelationId, RowExclusiveLock); + + if (newTablespaceId != DEFAULTTABLESPACE_OID && + newTablespaceId != InvalidOid) + shdepChangeDep(sdepRel, + classId, objectId, 0, + TableSpaceRelationId, newTablespaceId, + SHARED_DEPENDENCY_TABLESPACE); + else + shdepDropDependency(sdepRel, + classId, objectId, 0, true, + InvalidOid, InvalidOid, + SHARED_DEPENDENCY_INVALID); + + table_close(sdepRel, RowExclusiveLock); +} + /* * getOidListDiff * Helper for updateAclDependencies. @@ -1121,13 +1177,6 @@ shdepLockAndCheckObject(Oid classId, Oid objectId) objectId))); break; - /* - * Currently, this routine need not support any other shared - * object types besides roles. If we wanted to record explicit - * dependencies on databases or tablespaces, we'd need code along - * these lines: - */ -#ifdef NOT_USED case TableSpaceRelationId: { /* For lack of a syscache on pg_tablespace, do this: */ @@ -1141,7 +1190,6 @@ shdepLockAndCheckObject(Oid classId, Oid objectId) pfree(tablespace); break; } -#endif case DatabaseRelationId: { @@ -1201,6 +1249,8 @@ storeObjectDescription(StringInfo descs, appendStringInfo(descs, _("privileges for %s"), objdesc); else if (deptype == SHARED_DEPENDENCY_POLICY) appendStringInfo(descs, _("target of %s"), objdesc); + else if (deptype == SHARED_DEPENDENCY_TABLESPACE) + appendStringInfo(descs, _("tablespace for %s"), objdesc); else elog(ERROR, "unrecognized dependency type: %d", (int) deptype); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 993da56d437c9..fd55bf4ac7dd9 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -13340,6 +13340,10 @@ ATExecSetTableSpaceNoStorage(Relation rel, Oid newTableSpace) rd_rel->reltablespace = (newTableSpace == MyDatabaseTableSpace) ? InvalidOid : newTableSpace; CatalogTupleUpdate(pg_class, &tuple->t_self, tuple); + /* Record dependency on tablespace */ + changeDependencyOnTablespace(RelationRelationId, + reloid, rd_rel->reltablespace); + InvokeObjectPostAlterHook(RelationRelationId, reloid, 0); heap_freetuple(tuple); diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c index a9a2db2834555..69ea155d50278 100644 --- a/src/backend/commands/tablespace.c +++ b/src/backend/commands/tablespace.c @@ -420,6 +420,8 @@ DropTableSpace(DropTableSpaceStmt *stmt) Form_pg_tablespace spcform; ScanKeyData entry[1]; Oid tablespaceoid; + char *detail; + char *detail_log; /* * Find the target tuple @@ -468,6 +470,16 @@ DropTableSpace(DropTableSpaceStmt *stmt) aclcheck_error(ACLCHECK_NO_PRIV, OBJECT_TABLESPACE, tablespacename); + /* Check for pg_shdepend entries depending on this tablespace */ + if (checkSharedDependencies(TableSpaceRelationId, tablespaceoid, + &detail, &detail_log)) + ereport(ERROR, + (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), + errmsg("tablespace \"%s\" cannot be dropped because some objects depend on it", + tablespacename), + errdetail_internal("%s", detail), + errdetail_log("%s", detail_log))); + /* DROP hook for the tablespace being removed */ InvokeObjectDropHook(TableSpaceRelationId, tablespaceoid, 0); diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index c8d07f48dea12..f272e2c99f874 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -67,6 +67,12 @@ typedef enum DependencyType * a role mentioned in a policy object. The referenced object must be a * pg_authid entry. * + * (e) a SHARED_DEPENDENCY_TABLESPACE entry means that the referenced + * object is a tablespace mentioned in a relation without storage. The + * referenced object must be a pg_tablespace entry. (Relations that have + * storage don't need this: they are protected by the existence of a physical + * file in the tablespace.) + * * SHARED_DEPENDENCY_INVALID is a value used as a parameter in internal * routines, and is not valid in the catalog itself. */ @@ -76,6 +82,7 @@ typedef enum SharedDependencyType SHARED_DEPENDENCY_OWNER = 'o', SHARED_DEPENDENCY_ACL = 'a', SHARED_DEPENDENCY_POLICY = 'r', + SHARED_DEPENDENCY_TABLESPACE = 't', SHARED_DEPENDENCY_INVALID = 0 } SharedDependencyType; @@ -253,6 +260,12 @@ extern void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner); extern void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId); +extern void recordDependencyOnTablespace(Oid classId, Oid objectId, + Oid tablespace); + +extern void changeDependencyOnTablespace(Oid classId, Oid objectId, + Oid newTablespaceId); + extern void updateAclDependencies(Oid classId, Oid objectId, int32 objectSubId, Oid ownerId, int noldmembers, Oid *oldmembers, diff --git a/src/test/regress/input/tablespace.source b/src/test/regress/input/tablespace.source index a5f61a35dc59f..1a181016d716a 100644 --- a/src/test/regress/input/tablespace.source +++ b/src/test/regress/input/tablespace.source @@ -249,6 +249,9 @@ CREATE TABLESPACE regress_badspace LOCATION '/no/such/location'; -- No such tablespace CREATE TABLE bar (i int) TABLESPACE regress_nosuchspace; +-- Fail, in use for some partitioned object +DROP TABLESPACE regress_tblspace; +ALTER INDEX testschema.part_a_idx SET TABLESPACE pg_default; -- Fail, not empty DROP TABLESPACE regress_tblspace; diff --git a/src/test/regress/output/tablespace.source b/src/test/regress/output/tablespace.source index 162b591b315f3..94c5f023c68d4 100644 --- a/src/test/regress/output/tablespace.source +++ b/src/test/regress/output/tablespace.source @@ -712,6 +712,11 @@ ERROR: directory "/no/such/location" does not exist -- No such tablespace CREATE TABLE bar (i int) TABLESPACE regress_nosuchspace; ERROR: tablespace "regress_nosuchspace" does not exist +-- Fail, in use for some partitioned object +DROP TABLESPACE regress_tblspace; +ERROR: tablespace "regress_tblspace" cannot be dropped because some objects depend on it +DETAIL: tablespace for index testschema.part_a_idx +ALTER INDEX testschema.part_a_idx SET TABLESPACE pg_default; -- Fail, not empty DROP TABLESPACE regress_tblspace; ERROR: tablespace "regress_tblspace" is not empty From 8e396a773b80c72e5d5a0ca9755dffe043c97a05 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 14 Jan 2021 16:19:38 -0500 Subject: [PATCH 105/240] pg_dump: label PUBLICATION TABLE ArchiveEntries with an owner. This is the same fix as commit 9eabfe300 applied to INDEX ATTACH entries, but for table-to-publication attachments. As in that case, even though the backend doesn't record "ownership" of the attachment, we still ought to label it in the dump archive with the role name that should run the ALTER PUBLICATION command. The existing behavior causes the ALTER to be done by the original role that started the restore; that will usually work fine, but there may be corner cases where it fails. The bulk of the patch is concerned with changing struct PublicationRelInfo to include a pointer to the associated PublicationInfo object, so that we can get the owner's name out of that when the time comes. While at it, I rewrote getPublicationTables() to do just one query of pg_publication_rel, not one per table. Back-patch to v10 where this code was introduced. Discussion: https://postgr.es/m/1165710.1610473242@sss.pgh.pa.us --- src/bin/pg_dump/common.c | 18 +++++- src/bin/pg_dump/pg_dump.c | 123 ++++++++++++++++++++------------------ src/bin/pg_dump/pg_dump.h | 6 +- 3 files changed, 85 insertions(+), 62 deletions(-) diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c index 255f891432631..b0f02bc1f6e51 100644 --- a/src/bin/pg_dump/common.c +++ b/src/bin/pg_dump/common.c @@ -52,6 +52,7 @@ static DumpableObject **oprinfoindex; static DumpableObject **collinfoindex; static DumpableObject **nspinfoindex; static DumpableObject **extinfoindex; +static DumpableObject **pubinfoindex; static int numTables; static int numTypes; static int numFuncs; @@ -59,6 +60,7 @@ static int numOperators; static int numCollations; static int numNamespaces; static int numExtensions; +static int numPublications; /* This is an array of object identities, not actual DumpableObjects */ static ExtensionMemberId *extmembers; @@ -93,6 +95,7 @@ getSchemaData(Archive *fout, int *numTablesPtr) CollInfo *collinfo; NamespaceInfo *nspinfo; ExtensionInfo *extinfo; + PublicationInfo *pubinfo; InhInfo *inhinfo; int numAggregates; int numInherits; @@ -247,7 +250,9 @@ getSchemaData(Archive *fout, int *numTablesPtr) getPolicies(fout, tblinfo, numTables); pg_log_info("reading publications"); - getPublications(fout); + pubinfo = getPublications(fout, &numPublications); + pubinfoindex = buildIndexArray(pubinfo, numPublications, + sizeof(PublicationInfo)); pg_log_info("reading publication membership"); getPublicationTables(fout, tblinfo, numTables); @@ -937,6 +942,17 @@ findExtensionByOid(Oid oid) return (ExtensionInfo *) findObjectByOid(oid, extinfoindex, numExtensions); } +/* + * findPublicationByOid + * finds the entry (in pubinfo) of the publication with the given oid + * returns NULL if not found + */ +PublicationInfo * +findPublicationByOid(Oid oid) +{ + return (PublicationInfo *) findObjectByOid(oid, pubinfoindex, numPublications); +} + /* * findIndexByOid * find the entry of the index with the given oid diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 3bcbd4bdc3f60..798d14580e6d1 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -3865,8 +3865,8 @@ dumpPolicy(Archive *fout, PolicyInfo *polinfo) * getPublications * get information about publications */ -void -getPublications(Archive *fout) +PublicationInfo * +getPublications(Archive *fout, int *numPublications) { DumpOptions *dopt = fout->dopt; PQExpBuffer query; @@ -3886,7 +3886,10 @@ getPublications(Archive *fout) ntups; if (dopt->no_publications || fout->remoteVersion < 100000) - return; + { + *numPublications = 0; + return NULL; + } query = createPQExpBuffer(); @@ -3964,6 +3967,9 @@ getPublications(Archive *fout) PQclear(res); destroyPQExpBuffer(query); + + *numPublications = ntups; + return pubinfo; } /* @@ -4072,7 +4078,8 @@ getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables) DumpOptions *dopt = fout->dopt; int i_tableoid; int i_oid; - int i_pubname; + int i_prpubid; + int i_prrelid; int i, j, ntups; @@ -4082,15 +4089,39 @@ getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables) query = createPQExpBuffer(); - for (i = 0; i < numTables; i++) + /* Collect all publication membership info. */ + appendPQExpBufferStr(query, + "SELECT tableoid, oid, prpubid, prrelid " + "FROM pg_catalog.pg_publication_rel"); + res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); + + ntups = PQntuples(res); + + i_tableoid = PQfnumber(res, "tableoid"); + i_oid = PQfnumber(res, "oid"); + i_prpubid = PQfnumber(res, "prpubid"); + i_prrelid = PQfnumber(res, "prrelid"); + + /* this allocation may be more than we need */ + pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo)); + j = 0; + + for (i = 0; i < ntups; i++) { - TableInfo *tbinfo = &tblinfo[i]; + Oid prpubid = atooid(PQgetvalue(res, i, i_prpubid)); + Oid prrelid = atooid(PQgetvalue(res, i, i_prrelid)); + PublicationInfo *pubinfo; + TableInfo *tbinfo; /* - * Only regular and partitioned tables can be added to publications. + * Ignore any entries for which we aren't interested in either the + * publication or the rel. */ - if (tbinfo->relkind != RELKIND_RELATION && - tbinfo->relkind != RELKIND_PARTITIONED_TABLE) + pubinfo = findPublicationByOid(prpubid); + if (pubinfo == NULL) + continue; + tbinfo = findTableByOid(prrelid); + if (tbinfo == NULL) continue; /* @@ -4100,55 +4131,24 @@ getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables) if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)) continue; - pg_log_info("reading publication membership for table \"%s.%s\"", - tbinfo->dobj.namespace->dobj.name, - tbinfo->dobj.name); - - resetPQExpBuffer(query); - - /* Get the publication membership for the table. */ - appendPQExpBuffer(query, - "SELECT pr.tableoid, pr.oid, p.pubname " - "FROM pg_publication_rel pr, pg_publication p " - "WHERE pr.prrelid = '%u'" - " AND p.oid = pr.prpubid", - tbinfo->dobj.catId.oid); - res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); - - ntups = PQntuples(res); - - if (ntups == 0) - { - /* - * Table is not member of any publications. Clean up and return. - */ - PQclear(res); - continue; - } - - i_tableoid = PQfnumber(res, "tableoid"); - i_oid = PQfnumber(res, "oid"); - i_pubname = PQfnumber(res, "pubname"); + /* OK, make a DumpableObject for this relationship */ + pubrinfo[j].dobj.objType = DO_PUBLICATION_REL; + pubrinfo[j].dobj.catId.tableoid = + atooid(PQgetvalue(res, i, i_tableoid)); + pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid)); + AssignDumpId(&pubrinfo[j].dobj); + pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace; + pubrinfo[j].dobj.name = tbinfo->dobj.name; + pubrinfo[j].publication = pubinfo; + pubrinfo[j].pubtable = tbinfo; - pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo)); + /* Decide whether we want to dump it */ + selectDumpablePublicationTable(&(pubrinfo[j].dobj), fout); - for (j = 0; j < ntups; j++) - { - pubrinfo[j].dobj.objType = DO_PUBLICATION_REL; - pubrinfo[j].dobj.catId.tableoid = - atooid(PQgetvalue(res, j, i_tableoid)); - pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid)); - AssignDumpId(&pubrinfo[j].dobj); - pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace; - pubrinfo[j].dobj.name = tbinfo->dobj.name; - pubrinfo[j].pubname = pg_strdup(PQgetvalue(res, j, i_pubname)); - pubrinfo[j].pubtable = tbinfo; - - /* Decide whether we want to dump it */ - selectDumpablePublicationTable(&(pubrinfo[j].dobj), fout); - } - PQclear(res); + j++; } + + PQclear(res); destroyPQExpBuffer(query); } @@ -4159,6 +4159,7 @@ getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables) static void dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo) { + PublicationInfo *pubinfo = pubrinfo->publication; TableInfo *tbinfo = pubrinfo->pubtable; PQExpBuffer query; char *tag; @@ -4166,22 +4167,26 @@ dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo) if (!(pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)) return; - tag = psprintf("%s %s", pubrinfo->pubname, tbinfo->dobj.name); + tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name); query = createPQExpBuffer(); appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY", - fmtId(pubrinfo->pubname)); + fmtId(pubinfo->dobj.name)); appendPQExpBuffer(query, " %s;\n", fmtQualifiedDumpable(tbinfo)); /* - * There is no point in creating drop query as the drop is done by table - * drop. + * There is no point in creating a drop query as the drop is done by table + * drop. (If you think to change this, see also _printTocEntry().) + * Although this object doesn't really have ownership as such, set the + * owner field anyway to ensure that the command is run by the correct + * role at restore time. */ ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId, ARCHIVE_OPTS(.tag = tag, .namespace = tbinfo->dobj.namespace->dobj.name, + .owner = pubinfo->rolname, .description = "PUBLICATION TABLE", .section = SECTION_POST_DATA, .createStmt = query->data)); diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index 731d0fe7ba849..1290f9659b853 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -623,8 +623,8 @@ typedef struct _PublicationInfo typedef struct _PublicationRelInfo { DumpableObject dobj; + PublicationInfo *publication; TableInfo *pubtable; - char *pubname; } PublicationRelInfo; /* @@ -675,6 +675,7 @@ extern OprInfo *findOprByOid(Oid oid); extern CollInfo *findCollationByOid(Oid oid); extern NamespaceInfo *findNamespaceByOid(Oid oid); extern ExtensionInfo *findExtensionByOid(Oid oid); +extern PublicationInfo *findPublicationByOid(Oid oid); extern void setExtensionMembership(ExtensionMemberId *extmems, int nextmems); extern ExtensionInfo *findOwningExtension(CatalogId catalogId); @@ -727,7 +728,8 @@ extern void processExtensionTables(Archive *fout, ExtensionInfo extinfo[], int numExtensions); extern EventTriggerInfo *getEventTriggers(Archive *fout, int *numEventTriggers); extern void getPolicies(Archive *fout, TableInfo tblinfo[], int numTables); -extern void getPublications(Archive *fout); +extern PublicationInfo *getPublications(Archive *fout, + int *numPublications); extern void getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables); extern void getSubscriptions(Archive *fout); From 5e5f4fcd89c082bba0239e8db1552834b4905c34 Mon Sep 17 00:00:00 2001 From: Fujii Masao Date: Fri, 15 Jan 2021 10:30:19 +0900 Subject: [PATCH 106/240] postgres_fdw: Save foreign server OID in connection cache entry. The foreign server OID stored in the connection cache entry is used as a lookup key to directly get the server name. Previously since the connection cache entry did not have the server OID, postgres_fdw had to get the server OID at first from user mapping before getting the server name. So if the corresponding user mapping was dropped, postgres_fdw could raise the error "cache lookup failed for user mapping" while looking up user mapping and fail to get the server name even though the server had not been dropped yet. Author: Bharath Rupireddy Reviewed-by: Fujii Masao Discussion: https://postgr.es/m/CALj2ACVRZPUB7ZwqLn-6DY8C_UmPs6084gSpHA92YBv++1AJXA@mail.gmail.com --- contrib/postgres_fdw/connection.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c index 266f66cc62ce1..eaedfea9f248e 100644 --- a/contrib/postgres_fdw/connection.c +++ b/contrib/postgres_fdw/connection.c @@ -57,6 +57,7 @@ typedef struct ConnCacheEntry bool have_error; /* have any subxacts aborted in this xact? */ bool changing_xact_state; /* xact state change in process */ bool invalidated; /* true if reconnect is pending */ + Oid serverid; /* foreign server OID used to get server name */ uint32 server_hashvalue; /* hash value of foreign server OID */ uint32 mapping_hashvalue; /* hash value of user mapping OID */ } ConnCacheEntry; @@ -273,6 +274,7 @@ make_new_connection(ConnCacheEntry *entry, UserMapping *user) entry->have_error = false; entry->changing_xact_state = false; entry->invalidated = false; + entry->serverid = server->serverid; entry->server_hashvalue = GetSysCacheHashValue1(FOREIGNSERVEROID, ObjectIdGetDatum(server->serverid)); @@ -1138,8 +1140,6 @@ pgfdw_inval_callback(Datum arg, int cacheid, uint32 hashvalue) static void pgfdw_reject_incomplete_xact_state_change(ConnCacheEntry *entry) { - HeapTuple tup; - Form_pg_user_mapping umform; ForeignServer *server; /* nothing to do for inactive entries and entries of sane state */ @@ -1150,13 +1150,7 @@ pgfdw_reject_incomplete_xact_state_change(ConnCacheEntry *entry) disconnect_pg_server(entry); /* find server name to be shown in the message below */ - tup = SearchSysCache1(USERMAPPINGOID, - ObjectIdGetDatum(entry->key)); - if (!HeapTupleIsValid(tup)) - elog(ERROR, "cache lookup failed for user mapping %u", entry->key); - umform = (Form_pg_user_mapping) GETSTRUCT(tup); - server = GetForeignServer(umform->umserver); - ReleaseSysCache(tup); + server = GetForeignServer(entry->serverid); ereport(ERROR, (errcode(ERRCODE_CONNECTION_EXCEPTION), From 5ae1572993ae8bf1f6c33a933915c07cc9bc0add Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Fri, 15 Jan 2021 10:33:13 +0900 Subject: [PATCH 107/240] Fix O(N^2) stat() calls when recycling WAL segments The counter tracking the last segment number recycled was getting initialized when recycling one single segment, while it should be used across a full cycle of segments recycled to prevent useless checks related to entries already recycled. This performance issue has been introduced by b2a5545, and it was first implemented in 61b86142. No backpatch is done per the lack of field complaints. Reported-by: Andres Freund, Thomas Munro Author: Michael Paquier Reviewed-By: Andres Freund Discussion: https://postgr.es/m/20170621211016.eln6cxxp3jrv7m4m@alap3.anarazel.de Discussion: https://postgr.es/m/CA+hUKG+DRiF9z1_MU4fWq+RfJMxP7zjoptfcmuCFPeO4JM2iVg@mail.gmail.com --- src/backend/access/transam/xlog.c | 61 ++++++++++++++++--------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index b18257c198078..199d911be76be 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -930,7 +930,8 @@ static void XLogFileClose(void); static void PreallocXlogFiles(XLogRecPtr endptr); static void RemoveTempXlogFiles(void); static void RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr lastredoptr, XLogRecPtr endptr); -static void RemoveXlogFile(const char *segname, XLogRecPtr lastredoptr, XLogRecPtr endptr); +static void RemoveXlogFile(const char *segname, XLogSegNo recycleSegNo, + XLogSegNo *endlogSegNo); static void UpdateLastRemovedPtr(char *filename); static void ValidateXLOGDirectoryStructure(void); static void CleanupBackupHistory(void); @@ -4055,6 +4056,12 @@ RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr lastredoptr, XLogRecPtr endptr) DIR *xldir; struct dirent *xlde; char lastoff[MAXFNAMELEN]; + XLogSegNo endlogSegNo; + XLogSegNo recycleSegNo; + + /* Initialize info about where to try to recycle to */ + XLByteToSeg(endptr, endlogSegNo, wal_segment_size); + recycleSegNo = XLOGfileslop(lastredoptr); /* * Construct a filename of the last segment to be kept. The timeline ID @@ -4093,7 +4100,7 @@ RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr lastredoptr, XLogRecPtr endptr) /* Update the last removed location in shared memory first */ UpdateLastRemovedPtr(xlde->d_name); - RemoveXlogFile(xlde->d_name, lastredoptr, endptr); + RemoveXlogFile(xlde->d_name, recycleSegNo, &endlogSegNo); } } } @@ -4123,13 +4130,21 @@ RemoveNonParentXlogFiles(XLogRecPtr switchpoint, TimeLineID newTLI) struct dirent *xlde; char switchseg[MAXFNAMELEN]; XLogSegNo endLogSegNo; + XLogSegNo switchLogSegNo; + XLogSegNo recycleSegNo; - XLByteToPrevSeg(switchpoint, endLogSegNo, wal_segment_size); + /* + * Initialize info about where to begin the work. This will recycle, + * somewhat arbitrarily, 10 future segments. + */ + XLByteToPrevSeg(switchpoint, switchLogSegNo, wal_segment_size); + XLByteToSeg(switchpoint, endLogSegNo, wal_segment_size); + recycleSegNo = endLogSegNo + 10; /* * Construct a filename of the last segment to be kept. */ - XLogFileName(switchseg, newTLI, endLogSegNo, wal_segment_size); + XLogFileName(switchseg, newTLI, switchLogSegNo, wal_segment_size); elog(DEBUG2, "attempting to remove WAL segments newer than log file %s", switchseg); @@ -4157,7 +4172,7 @@ RemoveNonParentXlogFiles(XLogRecPtr switchpoint, TimeLineID newTLI) * - but seems safer to let them be archived and removed later. */ if (!XLogArchiveIsReady(xlde->d_name)) - RemoveXlogFile(xlde->d_name, InvalidXLogRecPtr, switchpoint); + RemoveXlogFile(xlde->d_name, recycleSegNo, &endLogSegNo); } } @@ -4167,36 +4182,22 @@ RemoveNonParentXlogFiles(XLogRecPtr switchpoint, TimeLineID newTLI) /* * Recycle or remove a log file that's no longer needed. * - * endptr is current (or recent) end of xlog, and lastredoptr is the - * redo pointer of the last checkpoint. These are used to determine - * whether we want to recycle rather than delete no-longer-wanted log files. - * If lastredoptr is not known, pass invalid, and the function will recycle, - * somewhat arbitrarily, 10 future segments. + * segname is the name of the segment to recycle or remove. recycleSegNo + * is the segment number to recycle up to. endlogSegNo is the segment + * number of the current (or recent) end of WAL. + * + * endlogSegNo gets incremented if the segment is recycled so as it is not + * checked again with future callers of this function. */ static void -RemoveXlogFile(const char *segname, XLogRecPtr lastredoptr, XLogRecPtr endptr) +RemoveXlogFile(const char *segname, XLogSegNo recycleSegNo, + XLogSegNo *endlogSegNo) { char path[MAXPGPATH]; #ifdef WIN32 char newpath[MAXPGPATH]; #endif struct stat statbuf; - XLogSegNo endlogSegNo; - XLogSegNo recycleSegNo; - - if (wal_recycle) - { - /* - * Initialize info about where to try to recycle to. - */ - XLByteToSeg(endptr, endlogSegNo, wal_segment_size); - if (lastredoptr == InvalidXLogRecPtr) - recycleSegNo = endlogSegNo + 10; - else - recycleSegNo = XLOGfileslop(lastredoptr); - } - else - recycleSegNo = 0; /* keep compiler quiet */ snprintf(path, MAXPGPATH, XLOGDIR "/%s", segname); @@ -4206,9 +4207,9 @@ RemoveXlogFile(const char *segname, XLogRecPtr lastredoptr, XLogRecPtr endptr) * symbolic links pointing to a separate archive directory. */ if (wal_recycle && - endlogSegNo <= recycleSegNo && + *endlogSegNo <= recycleSegNo && lstat(path, &statbuf) == 0 && S_ISREG(statbuf.st_mode) && - InstallXLogFileSegment(&endlogSegNo, path, + InstallXLogFileSegment(endlogSegNo, path, true, recycleSegNo, true)) { ereport(DEBUG2, @@ -4216,7 +4217,7 @@ RemoveXlogFile(const char *segname, XLogRecPtr lastredoptr, XLogRecPtr endptr) segname))); CheckpointStats.ckpt_segs_recycled++; /* Needn't recheck that slot on future iterations */ - endlogSegNo++; + (*endlogSegNo)++; } else { From ccf4e277a4de120a2f08db7e45399d87e1176bda Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Fri, 15 Jan 2021 11:46:34 +0900 Subject: [PATCH 108/240] Remove PG_SHA*_DIGEST_STRING_LENGTH from sha2.h The last reference to those variables has been removed in aef8948, so this cleans up a bit the code. Discussion: https://postgr.es/m/X//ggAqmTtt+3t7X@paquier.xyz --- src/include/common/sha2.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/include/common/sha2.h b/src/include/common/sha2.h index f4bae35af10c2..dfeee6bceba1e 100644 --- a/src/include/common/sha2.h +++ b/src/include/common/sha2.h @@ -18,15 +18,11 @@ /*** SHA224/256/384/512 Various Length Definitions ***********************/ #define PG_SHA224_BLOCK_LENGTH 64 #define PG_SHA224_DIGEST_LENGTH 28 -#define PG_SHA224_DIGEST_STRING_LENGTH (PG_SHA224_DIGEST_LENGTH * 2 + 1) #define PG_SHA256_BLOCK_LENGTH 64 #define PG_SHA256_DIGEST_LENGTH 32 -#define PG_SHA256_DIGEST_STRING_LENGTH (PG_SHA256_DIGEST_LENGTH * 2 + 1) #define PG_SHA384_BLOCK_LENGTH 128 #define PG_SHA384_DIGEST_LENGTH 48 -#define PG_SHA384_DIGEST_STRING_LENGTH (PG_SHA384_DIGEST_LENGTH * 2 + 1) #define PG_SHA512_BLOCK_LENGTH 128 #define PG_SHA512_DIGEST_LENGTH 64 -#define PG_SHA512_DIGEST_STRING_LENGTH (PG_SHA512_DIGEST_LENGTH * 2 + 1) #endif /* _PG_SHA2_H_ */ From 2ad78a87f018260d4474eee63187e1cc73c9b976 Mon Sep 17 00:00:00 2001 From: Fujii Masao Date: Fri, 15 Jan 2021 12:44:17 +0900 Subject: [PATCH 109/240] Fix calculation of how much shared memory is required to store a TOC. Commit ac883ac453 refactored shm_toc_estimate() but changed its calculation of shared memory size for TOC incorrectly. Previously this could cause too large memory to be allocated. Back-patch to v11 where the bug was introduced. Author: Takayuki Tsunakawa Discussion: https://postgr.es/m/TYAPR01MB2990BFB73170E2C4921E2C4DFEA80@TYAPR01MB2990.jpnprd01.prod.outlook.com --- src/backend/storage/ipc/shm_toc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c index 83c7928d88217..863b98bf0545d 100644 --- a/src/backend/storage/ipc/shm_toc.c +++ b/src/backend/storage/ipc/shm_toc.c @@ -265,8 +265,8 @@ shm_toc_estimate(shm_toc_estimator *e) Size sz; sz = offsetof(shm_toc, toc_entry); - sz += add_size(sz, mul_size(e->number_of_keys, sizeof(shm_toc_entry))); - sz += add_size(sz, e->space_for_chunks); + sz = add_size(sz, mul_size(e->number_of_keys, sizeof(shm_toc_entry))); + sz = add_size(sz, e->space_for_chunks); return BUFFERALIGN(sz); } From f9900df5f94936067e6fa24a9df609863eb08da2 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Fri, 15 Jan 2021 10:31:42 -0300 Subject: [PATCH 110/240] Avoid spurious wait in concurrent reindex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is like commit c98763bf51bf, but for REINDEX CONCURRENTLY. To wit: this flags indicates that the current process is safe to ignore for the purposes of waiting for other snapshots, when doing CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY. This helps two processes doing either of those things not deadlock, and also avoids spurious waits. Author: Álvaro Herrera Reviewed-by: Dmitry Dolgov <9erthalion6@gmail.com> Reviewed-by: Hamid Akhtar Reviewed-by: Masahiko Sawada Discussion: https://postgr.es/m/20201130195439.GA24598@alvherre.pgsql --- src/backend/commands/indexcmds.c | 48 +++++++++++++++++++++++++++++++- src/include/storage/proc.h | 1 + 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 8c9c39a467533..1b71859020c8f 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -385,7 +385,7 @@ CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts) * lazy VACUUMs, because they won't be fazed by missing index entries * either. (Manual ANALYZEs, however, can't be excluded because they * might be within transactions that are going to do arbitrary operations - * later.) Processes running CREATE INDEX CONCURRENTLY + * later.) Processes running CREATE INDEX CONCURRENTLY or REINDEX CONCURRENTLY * on indexes that are neither expressional nor partial are also safe to * ignore, since we know that those processes won't examine any data * outside the table they're indexing. @@ -3066,6 +3066,7 @@ ReindexRelationConcurrently(Oid relationOid, int options) Oid indexId; Oid tableId; Oid amId; + bool safe; /* for set_indexsafe_procflags */ } ReindexIndexInfo; List *heapRelationIds = NIL; List *indexIds = NIL; @@ -3377,6 +3378,9 @@ ReindexRelationConcurrently(Oid relationOid, int options) heapRel = table_open(indexRel->rd_index->indrelid, ShareUpdateExclusiveLock); + /* determine safety of this index for set_indexsafe_procflags */ + idx->safe = (indexRel->rd_indexprs == NIL && + indexRel->rd_indpred == NIL); idx->tableId = RelationGetRelid(heapRel); idx->amId = indexRel->rd_rel->relam; @@ -3418,6 +3422,7 @@ ReindexRelationConcurrently(Oid relationOid, int options) newidx = palloc(sizeof(ReindexIndexInfo)); newidx->indexId = newIndexId; + newidx->safe = idx->safe; newidx->tableId = idx->tableId; newidx->amId = idx->amId; @@ -3485,6 +3490,11 @@ ReindexRelationConcurrently(Oid relationOid, int options) CommitTransactionCommand(); StartTransactionCommand(); + /* + * Because we don't take a snapshot in this transaction, there's no need + * to set the PROC_IN_SAFE_IC flag here. + */ + /* * Phase 2 of REINDEX CONCURRENTLY * @@ -3514,6 +3524,10 @@ ReindexRelationConcurrently(Oid relationOid, int options) */ CHECK_FOR_INTERRUPTS(); + /* Tell concurrent indexing to ignore us, if index qualifies */ + if (newidx->safe) + set_indexsafe_procflags(); + /* Set ActiveSnapshot since functions in the indexes may need it */ PushActiveSnapshot(GetTransactionSnapshot()); @@ -3534,8 +3548,14 @@ ReindexRelationConcurrently(Oid relationOid, int options) PopActiveSnapshot(); CommitTransactionCommand(); } + StartTransactionCommand(); + /* + * Because we don't take a snapshot or Xid in this transaction, there's no + * need to set the PROC_IN_SAFE_IC flag here. + */ + /* * Phase 3 of REINDEX CONCURRENTLY * @@ -3564,6 +3584,10 @@ ReindexRelationConcurrently(Oid relationOid, int options) */ CHECK_FOR_INTERRUPTS(); + /* Tell concurrent indexing to ignore us, if index qualifies */ + if (newidx->safe) + set_indexsafe_procflags(); + /* * Take the "reference snapshot" that will be used by validate_index() * to filter candidate tuples. @@ -3607,6 +3631,9 @@ ReindexRelationConcurrently(Oid relationOid, int options) * interesting tuples. But since it might not contain tuples deleted * just before the reference snap was taken, we have to wait out any * transactions that might have older snapshots. + * + * Because we don't take a snapshot or Xid in this transaction, + * there's no need to set the PROC_IN_SAFE_IC flag here. */ pgstat_progress_update_param(PROGRESS_CREATEIDX_PHASE, PROGRESS_CREATEIDX_PHASE_WAIT_3); @@ -3628,6 +3655,13 @@ ReindexRelationConcurrently(Oid relationOid, int options) StartTransactionCommand(); + /* + * Because this transaction only does catalog manipulations and doesn't do + * any index operations, we can set the PROC_IN_SAFE_IC flag here + * unconditionally. + */ + set_indexsafe_procflags(); + forboth(lc, indexIds, lc2, newIndexIds) { ReindexIndexInfo *oldidx = lfirst(lc); @@ -3675,6 +3709,12 @@ ReindexRelationConcurrently(Oid relationOid, int options) CommitTransactionCommand(); StartTransactionCommand(); + /* + * While we could set PROC_IN_SAFE_IC if all indexes qualified, there's no + * real need for that, because we only acquire an Xid after the wait is + * done, and that lasts for a very short period. + */ + /* * Phase 5 of REINDEX CONCURRENTLY * @@ -3705,6 +3745,12 @@ ReindexRelationConcurrently(Oid relationOid, int options) CommitTransactionCommand(); StartTransactionCommand(); + /* + * While we could set PROC_IN_SAFE_IC if all indexes qualified, there's no + * real need for that, because we only acquire an Xid after the wait is + * done, and that lasts for a very short period. + */ + /* * Phase 6 of REINDEX CONCURRENTLY * diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 0786fcf103a70..683ab64f76b8d 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -54,6 +54,7 @@ struct XidCache #define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ #define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ #define PROC_IN_SAFE_IC 0x04 /* currently running CREATE INDEX + * CONCURRENTLY or REINDEX * CONCURRENTLY on non-expressional, * non-partial index */ #define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */ From 4823621db312a0597c40686c4c94d47428889fef Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 15 Jan 2021 11:28:51 -0500 Subject: [PATCH 111/240] Improve our heuristic for selecting PG_SYSROOT on macOS. In cases where Xcode is newer than the underlying macOS version, asking xcodebuild for the SDK path will produce a pointer to the SDK shipped with Xcode, which may end up building code that does not work on the underlying macOS version. It appears that in such cases, xcodebuild's answer also fails to match the default behavior of Apple's compiler: assuming one has installed Xcode's "command line tools", there will be an SDK for the OS's own version in /Library/Developer/CommandLineTools, and the compiler will default to using that. This is all pretty poorly documented, but experimentation suggests that "xcrun --show-sdk-path" gives the sysroot path that the compiler is actually using, at least in some cases. Hence, try that first, but revert to xcodebuild if xcrun fails (in very old Xcode, it is missing or lacks the --show-sdk-path switch). Also, "xcrun --show-sdk-path" may give a path that is valid but lacks any OS version identifier. We don't really want that, since most of the motivation for wiring -isysroot into the build flags at all is to ensure that all parts of a PG installation are built against the same SDK, even when considering extensions built later and/or on a different machine. Insist on finding "N.N" in the directory name before accepting the result. (Adding "--sdk macosx" to the xcrun call seems to produce the same answer as xcodebuild, but usually more quickly because it's cached, so we also try that as a fallback.) The core reason why we don't want to use Xcode's default SDK in cases like this is that Apple's technology for introducing new syscalls does not play nice with Autoconf: for example, configure will think that preadv/pwritev exist when using a Big Sur SDK, even when building on an older macOS version where they don't exist. It'd be nice to have a better solution to that problem, but this patch doesn't attempt to fix that. Per report from Sergey Shinderuk. Back-patch to all supported versions. Discussion: https://postgr.es/m/ed3b8e5d-0da8-6ebd-fd1c-e0ac80a4b204@postgrespro.ru --- src/template/darwin | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/template/darwin b/src/template/darwin index 32414d21a98a2..1868c147cbf11 100644 --- a/src/template/darwin +++ b/src/template/darwin @@ -3,11 +3,27 @@ # Note: Darwin is the original code name for macOS, also known as OS X. # We still use "darwin" as the port name, partly because config.guess does. -# Select where system include files should be sought. +# Select where system include files should be sought, if user didn't say. if test x"$PG_SYSROOT" = x"" ; then - PG_SYSROOT=`xcodebuild -version -sdk macosx Path 2>/dev/null` + # This is far more complicated than it ought to be. We first ask + # "xcrun --show-sdk-path", which seems to match the default -isysroot + # setting of Apple's compilers. However, that may produce no result or + # a result that is not version-specific (i.e., just ".../SDKs/MacOSX.sdk"). + # Using a version-specific sysroot seems desirable, so if there are not + # digits in the directory name, try "xcrun --sdk macosx --show-sdk-path"; + # and if that still doesn't work, fall back to asking xcodebuild, + # which is often a good deal slower. + PG_SYSROOT=`xcrun --show-sdk-path 2>/dev/null` + if expr x"$PG_SYSROOT" : '.*[0-9]\.[0-9][^/]*$' >/dev/null ; then : okay + else + PG_SYSROOT=`xcrun --sdk macosx --show-sdk-path 2>/dev/null` + if expr x"$PG_SYSROOT" : '.*[0-9]\.[0-9][^/]*$' >/dev/null ; then : okay + else + PG_SYSROOT=`xcodebuild -version -sdk macosx Path 2>/dev/null` + fi + fi fi -# Old xcodebuild versions may produce garbage, so validate the result. +# Validate the result: if it doesn't point at a directory, ignore it. if test x"$PG_SYSROOT" != x"" ; then if test -d "$PG_SYSROOT" ; then CPPFLAGS="-isysroot $PG_SYSROOT $CPPFLAGS" From c9a0dc34865f2f82d8e186f534d9b605afaa4d11 Mon Sep 17 00:00:00 2001 From: Tomas Vondra Date: Fri, 15 Jan 2021 23:24:19 +0100 Subject: [PATCH 112/240] Disallow CREATE STATISTICS on system catalogs Add a check that CREATE STATISTICS does not add extended statistics on system catalogs, similarly to indexes etc. It can be overriden using the allow_system_table_mods GUC. This bug exists since 7b504eb282c, adding the extended statistics, so backpatch all the way back to PostgreSQL 10. Author: Tomas Vondra Reported-by: Dean Rasheed Backpatch-through: 10 Discussion: https://postgr.es/m/CAEZATCXAPrrOKwEsyZKQ4uzzJQWBCt6QAvOcgqRGdWwT1zb%2BrQ%40mail.gmail.com --- src/backend/commands/statscmds.c | 7 +++++++ src/test/regress/expected/stats_ext.out | 12 +++++++----- src/test/regress/sql/stats_ext.sql | 12 +++++++----- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c index 114ad77142cf3..2bae205845992 100644 --- a/src/backend/commands/statscmds.c +++ b/src/backend/commands/statscmds.c @@ -135,6 +135,13 @@ CreateStatistics(CreateStatsStmt *stmt) if (!pg_class_ownercheck(RelationGetRelid(rel), stxowner)) aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(rel->rd_rel->relkind), RelationGetRelationName(rel)); + + /* Creating statistics on system catalogs is not allowed */ + if (!allowSystemTableMods && IsSystemRelation(rel)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied: \"%s\" is a system catalog", + RelationGetRelationName(rel)))); } Assert(rel); diff --git a/src/test/regress/expected/stats_ext.out b/src/test/regress/expected/stats_ext.out index 7bfeaf85f0e06..f094731e328ca 100644 --- a/src/test/regress/expected/stats_ext.out +++ b/src/test/regress/expected/stats_ext.out @@ -25,6 +25,7 @@ begin end; $$; -- Verify failures +CREATE TABLE ext_stats_test (x int, y int, z int); CREATE STATISTICS tst; ERROR: syntax error at or near ";" LINE 1: CREATE STATISTICS tst; @@ -39,16 +40,17 @@ LINE 1: CREATE STATISTICS tst FROM sometab; ^ CREATE STATISTICS tst ON a, b FROM nonexistent; ERROR: relation "nonexistent" does not exist -CREATE STATISTICS tst ON a, b FROM pg_class; +CREATE STATISTICS tst ON a, b FROM ext_stats_test; ERROR: column "a" does not exist -CREATE STATISTICS tst ON relname, relname, relnatts FROM pg_class; +CREATE STATISTICS tst ON x, x, y FROM ext_stats_test; ERROR: duplicate column name in statistics definition -CREATE STATISTICS tst ON relnatts + relpages FROM pg_class; +CREATE STATISTICS tst ON x + y FROM ext_stats_test; ERROR: only simple column references are allowed in CREATE STATISTICS -CREATE STATISTICS tst ON (relpages, reltuples) FROM pg_class; +CREATE STATISTICS tst ON (x, y) FROM ext_stats_test; ERROR: only simple column references are allowed in CREATE STATISTICS -CREATE STATISTICS tst (unrecognized) ON relname, relnatts FROM pg_class; +CREATE STATISTICS tst (unrecognized) ON x, y FROM ext_stats_test; ERROR: unrecognized statistics kind "unrecognized" +DROP TABLE ext_stats_test; -- Ensure stats are dropped sanely, and test IF NOT EXISTS while at it CREATE TABLE ab1 (a INTEGER, b INTEGER, c INTEGER); CREATE STATISTICS IF NOT EXISTS ab1_a_b_stats ON a, b FROM ab1; diff --git a/src/test/regress/sql/stats_ext.sql b/src/test/regress/sql/stats_ext.sql index 7912e733ae635..cb08b478a42b6 100644 --- a/src/test/regress/sql/stats_ext.sql +++ b/src/test/regress/sql/stats_ext.sql @@ -28,15 +28,17 @@ end; $$; -- Verify failures +CREATE TABLE ext_stats_test (x int, y int, z int); CREATE STATISTICS tst; CREATE STATISTICS tst ON a, b; CREATE STATISTICS tst FROM sometab; CREATE STATISTICS tst ON a, b FROM nonexistent; -CREATE STATISTICS tst ON a, b FROM pg_class; -CREATE STATISTICS tst ON relname, relname, relnatts FROM pg_class; -CREATE STATISTICS tst ON relnatts + relpages FROM pg_class; -CREATE STATISTICS tst ON (relpages, reltuples) FROM pg_class; -CREATE STATISTICS tst (unrecognized) ON relname, relnatts FROM pg_class; +CREATE STATISTICS tst ON a, b FROM ext_stats_test; +CREATE STATISTICS tst ON x, x, y FROM ext_stats_test; +CREATE STATISTICS tst ON x + y FROM ext_stats_test; +CREATE STATISTICS tst ON (x, y) FROM ext_stats_test; +CREATE STATISTICS tst (unrecognized) ON x, y FROM ext_stats_test; +DROP TABLE ext_stats_test; -- Ensure stats are dropped sanely, and test IF NOT EXISTS while at it CREATE TABLE ab1 (a INTEGER, b INTEGER, c INTEGER); From c95765f47673b16ed36acbfe98e1242e3c3822a3 Mon Sep 17 00:00:00 2001 From: Amit Kapila Date: Sat, 16 Jan 2021 10:15:32 +0530 Subject: [PATCH 113/240] Remove unnecessary pstrdup in fetch_table_list. The result of TextDatumGetCString is already palloc'ed so we don't need to allocate memory for it again. We decide not to backpatch it as there doesn't seem to be any case where it can create a meaningful leak. Author: Zhijie Hou Reviewed-by: Daniel Gustafsson Discussion: https://postgr.es/m/229fed2eb8c54c71a96ccb99e516eb12@G08CNEXMBPEKD05.g08.fujitsu.local --- src/backend/commands/subscriptioncmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c index 490e93554135e..082f7855b89c1 100644 --- a/src/backend/commands/subscriptioncmds.c +++ b/src/backend/commands/subscriptioncmds.c @@ -1267,7 +1267,7 @@ fetch_table_list(WalReceiverConn *wrconn, List *publications) relname = TextDatumGetCString(slot_getattr(slot, 2, &isnull)); Assert(!isnull); - rv = makeRangeVar(pstrdup(nspname), pstrdup(relname), -1); + rv = makeRangeVar(nspname, relname, -1); tablelist = lappend(tablelist, rv); ExecClearTuple(slot); From 6db992833c04c0322f7f34a486adece01651f929 Mon Sep 17 00:00:00 2001 From: Noah Misch Date: Sat, 16 Jan 2021 12:21:35 -0800 Subject: [PATCH 114/240] Prevent excess SimpleLruTruncate() deletion. Every core SLRU wraps around. With the exception of pg_notify, the wrap point can fall in the middle of a page. Account for this in the PagePrecedes callback specification and in SimpleLruTruncate()'s use of said callback. Update each callback implementation to fit the new specification. This changes SerialPagePrecedesLogically() from the style of asyncQueuePagePrecedes() to the style of CLOGPagePrecedes(). (Whereas pg_clog and pg_serial share a key space, pg_serial is nothing like pg_notify.) The bug fixed here has the same symptoms and user followup steps as 592a589a04bd456410b853d86bd05faa9432cbbb. Back-patch to 9.5 (all supported versions). Reviewed by Andrey Borodin and (in earlier versions) by Tom Lane. Discussion: https://postgr.es/m/20190202083822.GC32531@gust.leadboat.com --- src/backend/access/transam/clog.c | 27 +++-- src/backend/access/transam/commit_ts.c | 35 ++++-- src/backend/access/transam/multixact.c | 36 ++++--- src/backend/access/transam/slru.c | 143 ++++++++++++++++++++++--- src/backend/access/transam/subtrans.c | 17 ++- src/backend/commands/async.c | 11 +- src/backend/storage/lmgr/predicate.c | 109 ++++++++++++++++--- src/include/access/slru.h | 16 ++- 8 files changed, 314 insertions(+), 80 deletions(-) diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c index 69a81f3246949..410d02a3943da 100644 --- a/src/backend/access/transam/clog.c +++ b/src/backend/access/transam/clog.c @@ -694,6 +694,7 @@ CLOGShmemInit(void) SimpleLruInit(XactCtl, "Xact", CLOGShmemBuffers(), CLOG_LSNS_PER_PAGE, XactSLRULock, "pg_xact", LWTRANCHE_XACT_BUFFER, SYNC_HANDLER_CLOG); + SlruPagePrecedesUnitTests(XactCtl, CLOG_XACTS_PER_PAGE); } /* @@ -912,13 +913,22 @@ TruncateCLOG(TransactionId oldestXact, Oid oldestxid_datoid) /* - * Decide which of two CLOG page numbers is "older" for truncation purposes. + * Decide whether a CLOG page number is "older" for truncation purposes. * * We need to use comparison of TransactionIds here in order to do the right - * thing with wraparound XID arithmetic. However, if we are asked about - * page number zero, we don't want to hand InvalidTransactionId to - * TransactionIdPrecedes: it'll get weird about permanent xact IDs. So, - * offset both xids by FirstNormalTransactionId to avoid that. + * thing with wraparound XID arithmetic. However, TransactionIdPrecedes() + * would get weird about permanent xact IDs. So, offset both such that xid1, + * xid2, and xid2 + CLOG_XACTS_PER_PAGE - 1 are all normal XIDs; this offset + * is relevant to page 0 and to the page preceding page 0. + * + * The page containing oldestXact-2^31 is the important edge case. The + * portion of that page equaling or following oldestXact-2^31 is expendable, + * but the portion preceding oldestXact-2^31 is not. When oldestXact-2^31 is + * the first XID of a page and segment, the entire page and segment is + * expendable, and we could truncate the segment. Recognizing that case would + * require making oldestXact, not just the page containing oldestXact, + * available to this callback. The benefit would be rare and small, so we + * don't optimize that edge case. */ static bool CLOGPagePrecedes(int page1, int page2) @@ -927,11 +937,12 @@ CLOGPagePrecedes(int page1, int page2) TransactionId xid2; xid1 = ((TransactionId) page1) * CLOG_XACTS_PER_PAGE; - xid1 += FirstNormalTransactionId; + xid1 += FirstNormalTransactionId + 1; xid2 = ((TransactionId) page2) * CLOG_XACTS_PER_PAGE; - xid2 += FirstNormalTransactionId; + xid2 += FirstNormalTransactionId + 1; - return TransactionIdPrecedes(xid1, xid2); + return (TransactionIdPrecedes(xid1, xid2) && + TransactionIdPrecedes(xid1, xid2 + CLOG_XACTS_PER_PAGE - 1)); } diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c index b786eeff7a18a..9f42461e12c2c 100644 --- a/src/backend/access/transam/commit_ts.c +++ b/src/backend/access/transam/commit_ts.c @@ -557,6 +557,7 @@ CommitTsShmemInit(void) CommitTsSLRULock, "pg_commit_ts", LWTRANCHE_COMMITTS_BUFFER, SYNC_HANDLER_COMMIT_TS); + SlruPagePrecedesUnitTests(CommitTsCtl, COMMIT_TS_XACTS_PER_PAGE); commitTsShared = ShmemInitStruct("CommitTs shared", sizeof(CommitTimestampShared), @@ -927,14 +928,27 @@ AdvanceOldestCommitTsXid(TransactionId oldestXact) /* - * Decide which of two commitTS page numbers is "older" for truncation - * purposes. + * Decide whether a commitTS page number is "older" for truncation purposes. + * Analogous to CLOGPagePrecedes(). * - * We need to use comparison of TransactionIds here in order to do the right - * thing with wraparound XID arithmetic. However, if we are asked about - * page number zero, we don't want to hand InvalidTransactionId to - * TransactionIdPrecedes: it'll get weird about permanent xact IDs. So, - * offset both xids by FirstNormalTransactionId to avoid that. + * At default BLCKSZ, (1 << 31) % COMMIT_TS_XACTS_PER_PAGE == 128. This + * introduces differences compared to CLOG and the other SLRUs having (1 << + * 31) % per_page == 0. This function never tests exactly + * TransactionIdPrecedes(x-2^31, x). When the system reaches xidStopLimit, + * there are two possible counts of page boundaries between oldestXact and the + * latest XID assigned, depending on whether oldestXact is within the first + * 128 entries of its page. Since this function doesn't know the location of + * oldestXact within page2, it returns false for one page that actually is + * expendable. This is a wider (yet still negligible) version of the + * truncation opportunity that CLOGPagePrecedes() cannot recognize. + * + * For the sake of a worked example, number entries with decimal values such + * that page1==1 entries range from 1.0 to 1.999. Let N+0.15 be the number of + * pages that 2^31 entries will span (N is an integer). If oldestXact=N+2.1, + * then the final safe XID assignment leaves newestXact=1.95. We keep page 2, + * because entry=2.85 is the border that toggles whether entries precede the + * last entry of the oldestXact page. While page 2 is expendable at + * oldestXact=N+2.1, it would be precious at oldestXact=N+2.9. */ static bool CommitTsPagePrecedes(int page1, int page2) @@ -943,11 +957,12 @@ CommitTsPagePrecedes(int page1, int page2) TransactionId xid2; xid1 = ((TransactionId) page1) * COMMIT_TS_XACTS_PER_PAGE; - xid1 += FirstNormalTransactionId; + xid1 += FirstNormalTransactionId + 1; xid2 = ((TransactionId) page2) * COMMIT_TS_XACTS_PER_PAGE; - xid2 += FirstNormalTransactionId; + xid2 += FirstNormalTransactionId + 1; - return TransactionIdPrecedes(xid1, xid2); + return (TransactionIdPrecedes(xid1, xid2) && + TransactionIdPrecedes(xid1, xid2 + COMMIT_TS_XACTS_PER_PAGE - 1)); } diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c index 1233448481ae5..7dcfa02323698 100644 --- a/src/backend/access/transam/multixact.c +++ b/src/backend/access/transam/multixact.c @@ -1852,11 +1852,13 @@ MultiXactShmemInit(void) MultiXactOffsetSLRULock, "pg_multixact/offsets", LWTRANCHE_MULTIXACTOFFSET_BUFFER, SYNC_HANDLER_MULTIXACT_OFFSET); + SlruPagePrecedesUnitTests(MultiXactOffsetCtl, MULTIXACT_OFFSETS_PER_PAGE); SimpleLruInit(MultiXactMemberCtl, "MultiXactMember", NUM_MULTIXACTMEMBER_BUFFERS, 0, MultiXactMemberSLRULock, "pg_multixact/members", LWTRANCHE_MULTIXACTMEMBER_BUFFER, SYNC_HANDLER_MULTIXACT_MEMBER); + /* doesn't call SimpleLruTruncate() or meet criteria for unit tests */ /* Initialize our shared state struct */ MultiXactState = ShmemInitStruct("Shared MultiXact State", @@ -2982,6 +2984,14 @@ TruncateMultiXact(MultiXactId newOldestMulti, Oid newOldestMultiDB) * truncate the members SLRU. So we first scan the directory to determine * the earliest offsets page number that we can read without error. * + * When nextMXact is less than one segment away from multiWrapLimit, + * SlruScanDirCbFindEarliest can find some early segment other than the + * actual earliest. (MultiXactOffsetPagePrecedes(EARLIEST, LATEST) + * returns false, because not all pairs of entries have the same answer.) + * That can also arise when an earlier truncation attempt failed unlink() + * or returned early from this function. The only consequence is + * returning early, which wastes space that we could have liberated. + * * NB: It's also possible that the page that oldestMulti is on has already * been truncated away, and we crashed before updating oldestMulti. */ @@ -3096,15 +3106,11 @@ TruncateMultiXact(MultiXactId newOldestMulti, Oid newOldestMultiDB) } /* - * Decide which of two MultiXactOffset page numbers is "older" for truncation - * purposes. + * Decide whether a MultiXactOffset page number is "older" for truncation + * purposes. Analogous to CLOGPagePrecedes(). * - * We need to use comparison of MultiXactId here in order to do the right - * thing with wraparound. However, if we are asked about page number zero, we - * don't want to hand InvalidMultiXactId to MultiXactIdPrecedes: it'll get - * weird. So, offset both multis by FirstMultiXactId to avoid that. - * (Actually, the current implementation doesn't do anything weird with - * InvalidMultiXactId, but there's no harm in leaving this code like this.) + * Offsetting the values is optional, because MultiXactIdPrecedes() has + * translational symmetry. */ static bool MultiXactOffsetPagePrecedes(int page1, int page2) @@ -3113,15 +3119,17 @@ MultiXactOffsetPagePrecedes(int page1, int page2) MultiXactId multi2; multi1 = ((MultiXactId) page1) * MULTIXACT_OFFSETS_PER_PAGE; - multi1 += FirstMultiXactId; + multi1 += FirstMultiXactId + 1; multi2 = ((MultiXactId) page2) * MULTIXACT_OFFSETS_PER_PAGE; - multi2 += FirstMultiXactId; + multi2 += FirstMultiXactId + 1; - return MultiXactIdPrecedes(multi1, multi2); + return (MultiXactIdPrecedes(multi1, multi2) && + MultiXactIdPrecedes(multi1, + multi2 + MULTIXACT_OFFSETS_PER_PAGE - 1)); } /* - * Decide which of two MultiXactMember page numbers is "older" for truncation + * Decide whether a MultiXactMember page number is "older" for truncation * purposes. There is no "invalid offset number" so use the numbers verbatim. */ static bool @@ -3133,7 +3141,9 @@ MultiXactMemberPagePrecedes(int page1, int page2) offset1 = ((MultiXactOffset) page1) * MULTIXACT_MEMBERS_PER_PAGE; offset2 = ((MultiXactOffset) page2) * MULTIXACT_MEMBERS_PER_PAGE; - return MultiXactOffsetPrecedes(offset1, offset2); + return (MultiXactOffsetPrecedes(offset1, offset2) && + MultiXactOffsetPrecedes(offset1, + offset2 + MULTIXACT_MEMBERS_PER_PAGE - 1)); } /* diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c index 244e518e46638..e49e06e896414 100644 --- a/src/backend/access/transam/slru.c +++ b/src/backend/access/transam/slru.c @@ -1230,11 +1230,6 @@ SimpleLruTruncate(SlruCtl ctl, int cutoffPage) /* update the stats counter of truncates */ pgstat_count_slru_truncate(shared->slru_stats_idx); - /* - * The cutoff point is the start of the segment containing cutoffPage. - */ - cutoffPage -= cutoffPage % SLRU_PAGES_PER_SEGMENT; - /* * Scan shared memory and remove any pages preceding the cutoff page, to * ensure we won't rewrite them later. (Since this is normally called in @@ -1247,9 +1242,7 @@ restart:; /* * While we are holding the lock, make an important safety check: the - * planned cutoff point must be <= the current endpoint page. Otherwise we - * have already wrapped around, and proceeding with the truncation would - * risk removing the current segment. + * current endpoint page must not be eligible for removal. */ if (ctl->PagePrecedes(shared->latest_page_number, cutoffPage)) { @@ -1281,8 +1274,11 @@ restart:; * Hmm, we have (or may have) I/O operations acting on the page, so * we've got to wait for them to finish and then start again. This is * the same logic as in SlruSelectLRUPage. (XXX if page is dirty, - * wouldn't it be OK to just discard it without writing it? For now, - * keep the logic the same as it was.) + * wouldn't it be OK to just discard it without writing it? + * SlruMayDeleteSegment() uses a stricter qualification, so we might + * not delete this page in the end; even if we don't delete it, we + * won't have cause to read its data again. For now, keep the logic + * the same as it was.) */ if (shared->page_status[slotno] == SLRU_PAGE_VALID) SlruInternalWritePage(ctl, slotno, NULL); @@ -1377,19 +1373,134 @@ SlruDeleteSegment(SlruCtl ctl, int segno) LWLockRelease(shared->ControlLock); } +/* + * Determine whether a segment is okay to delete. + * + * segpage is the first page of the segment, and cutoffPage is the oldest (in + * PagePrecedes order) page in the SLRU containing still-useful data. Since + * every core PagePrecedes callback implements "wrap around", check the + * segment's first and last pages: + * + * first=cutoff: no; cutoff falls inside this segment + * first>=cutoff && last=cutoff && last>=cutoff: no; every page of this segment is too young + */ +static bool +SlruMayDeleteSegment(SlruCtl ctl, int segpage, int cutoffPage) +{ + int seg_last_page = segpage + SLRU_PAGES_PER_SEGMENT - 1; + + Assert(segpage % SLRU_PAGES_PER_SEGMENT == 0); + + return (ctl->PagePrecedes(segpage, cutoffPage) && + ctl->PagePrecedes(seg_last_page, cutoffPage)); +} + +#ifdef USE_ASSERT_CHECKING +static void +SlruPagePrecedesTestOffset(SlruCtl ctl, int per_page, uint32 offset) +{ + TransactionId lhs, + rhs; + int newestPage, + oldestPage; + TransactionId newestXact, + oldestXact; + + /* + * Compare an XID pair having undefined order (see RFC 1982), a pair at + * "opposite ends" of the XID space. TransactionIdPrecedes() treats each + * as preceding the other. If RHS is oldestXact, LHS is the first XID we + * must not assign. + */ + lhs = per_page + offset; /* skip first page to avoid non-normal XIDs */ + rhs = lhs + (1U << 31); + Assert(TransactionIdPrecedes(lhs, rhs)); + Assert(TransactionIdPrecedes(rhs, lhs)); + Assert(!TransactionIdPrecedes(lhs - 1, rhs)); + Assert(TransactionIdPrecedes(rhs, lhs - 1)); + Assert(TransactionIdPrecedes(lhs + 1, rhs)); + Assert(!TransactionIdPrecedes(rhs, lhs + 1)); + Assert(!TransactionIdFollowsOrEquals(lhs, rhs)); + Assert(!TransactionIdFollowsOrEquals(rhs, lhs)); + Assert(!ctl->PagePrecedes(lhs / per_page, lhs / per_page)); + Assert(!ctl->PagePrecedes(lhs / per_page, rhs / per_page)); + Assert(!ctl->PagePrecedes(rhs / per_page, lhs / per_page)); + Assert(!ctl->PagePrecedes((lhs - per_page) / per_page, rhs / per_page)); + Assert(ctl->PagePrecedes(rhs / per_page, (lhs - 3 * per_page) / per_page)); + Assert(ctl->PagePrecedes(rhs / per_page, (lhs - 2 * per_page) / per_page)); + Assert(ctl->PagePrecedes(rhs / per_page, (lhs - 1 * per_page) / per_page) + || (1U << 31) % per_page != 0); /* See CommitTsPagePrecedes() */ + Assert(ctl->PagePrecedes((lhs + 1 * per_page) / per_page, rhs / per_page) + || (1U << 31) % per_page != 0); + Assert(ctl->PagePrecedes((lhs + 2 * per_page) / per_page, rhs / per_page)); + Assert(ctl->PagePrecedes((lhs + 3 * per_page) / per_page, rhs / per_page)); + Assert(!ctl->PagePrecedes(rhs / per_page, (lhs + per_page) / per_page)); + + /* + * GetNewTransactionId() has assigned the last XID it can safely use, and + * that XID is in the *LAST* page of the second segment. We must not + * delete that segment. + */ + newestPage = 2 * SLRU_PAGES_PER_SEGMENT - 1; + newestXact = newestPage * per_page + offset; + Assert(newestXact / per_page == newestPage); + oldestXact = newestXact + 1; + oldestXact -= 1U << 31; + oldestPage = oldestXact / per_page; + Assert(!SlruMayDeleteSegment(ctl, + (newestPage - + newestPage % SLRU_PAGES_PER_SEGMENT), + oldestPage)); + + /* + * GetNewTransactionId() has assigned the last XID it can safely use, and + * that XID is in the *FIRST* page of the second segment. We must not + * delete that segment. + */ + newestPage = SLRU_PAGES_PER_SEGMENT; + newestXact = newestPage * per_page + offset; + Assert(newestXact / per_page == newestPage); + oldestXact = newestXact + 1; + oldestXact -= 1U << 31; + oldestPage = oldestXact / per_page; + Assert(!SlruMayDeleteSegment(ctl, + (newestPage - + newestPage % SLRU_PAGES_PER_SEGMENT), + oldestPage)); +} + +/* + * Unit-test a PagePrecedes function. + * + * This assumes every uint32 >= FirstNormalTransactionId is a valid key. It + * assumes each value occupies a contiguous, fixed-size region of SLRU bytes. + * (MultiXactMemberCtl separates flags from XIDs. AsyncCtl has + * variable-length entries, no keys, and no random access. These unit tests + * do not apply to them.) + */ +void +SlruPagePrecedesUnitTests(SlruCtl ctl, int per_page) +{ + /* Test first, middle and last entries of a page. */ + SlruPagePrecedesTestOffset(ctl, per_page, 0); + SlruPagePrecedesTestOffset(ctl, per_page, per_page / 2); + SlruPagePrecedesTestOffset(ctl, per_page, per_page - 1); +} +#endif + /* * SlruScanDirectory callback - * This callback reports true if there's any segment prior to the one - * containing the page passed as "data". + * This callback reports true if there's any segment wholly prior to the + * one containing the page passed as "data". */ bool SlruScanDirCbReportPresence(SlruCtl ctl, char *filename, int segpage, void *data) { int cutoffPage = *(int *) data; - cutoffPage -= cutoffPage % SLRU_PAGES_PER_SEGMENT; - - if (ctl->PagePrecedes(segpage, cutoffPage)) + if (SlruMayDeleteSegment(ctl, segpage, cutoffPage)) return true; /* found one; don't iterate any more */ return false; /* keep going */ @@ -1404,7 +1515,7 @@ SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename, int segpage, void *data) { int cutoffPage = *(int *) data; - if (ctl->PagePrecedes(segpage, cutoffPage)) + if (SlruMayDeleteSegment(ctl, segpage, cutoffPage)) SlruInternalDeleteSegment(ctl, segpage / SLRU_PAGES_PER_SEGMENT); return false; /* keep going */ diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c index 8cdc9e0ab7916..6a8e521f89405 100644 --- a/src/backend/access/transam/subtrans.c +++ b/src/backend/access/transam/subtrans.c @@ -194,6 +194,7 @@ SUBTRANSShmemInit(void) SimpleLruInit(SubTransCtl, "Subtrans", NUM_SUBTRANS_BUFFERS, 0, SubtransSLRULock, "pg_subtrans", LWTRANCHE_SUBTRANS_BUFFER, SYNC_HANDLER_NONE); + SlruPagePrecedesUnitTests(SubTransCtl, SUBTRANS_XACTS_PER_PAGE); } /* @@ -354,13 +355,8 @@ TruncateSUBTRANS(TransactionId oldestXact) /* - * Decide which of two SUBTRANS page numbers is "older" for truncation purposes. - * - * We need to use comparison of TransactionIds here in order to do the right - * thing with wraparound XID arithmetic. However, if we are asked about - * page number zero, we don't want to hand InvalidTransactionId to - * TransactionIdPrecedes: it'll get weird about permanent xact IDs. So, - * offset both xids by FirstNormalTransactionId to avoid that. + * Decide whether a SUBTRANS page number is "older" for truncation purposes. + * Analogous to CLOGPagePrecedes(). */ static bool SubTransPagePrecedes(int page1, int page2) @@ -369,9 +365,10 @@ SubTransPagePrecedes(int page1, int page2) TransactionId xid2; xid1 = ((TransactionId) page1) * SUBTRANS_XACTS_PER_PAGE; - xid1 += FirstNormalTransactionId; + xid1 += FirstNormalTransactionId + 1; xid2 = ((TransactionId) page2) * SUBTRANS_XACTS_PER_PAGE; - xid2 += FirstNormalTransactionId; + xid2 += FirstNormalTransactionId + 1; - return TransactionIdPrecedes(xid1, xid2); + return (TransactionIdPrecedes(xid1, xid2) && + TransactionIdPrecedes(xid1, xid2 + SUBTRANS_XACTS_PER_PAGE - 1)); } diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c index 7c133ec8d3301..42b232d98b179 100644 --- a/src/backend/commands/async.c +++ b/src/backend/commands/async.c @@ -490,7 +490,12 @@ asyncQueuePageDiff(int p, int q) return diff; } -/* Is p < q, accounting for wraparound? */ +/* + * Is p < q, accounting for wraparound? + * + * Since asyncQueueIsFull() blocks creation of a page that could precede any + * extant page, we need not assess entries within a page. + */ static bool asyncQueuePagePrecedes(int p, int q) { @@ -1352,8 +1357,8 @@ asyncQueueIsFull(void) * logically precedes the current global tail pointer, ie, the head * pointer would wrap around compared to the tail. We cannot create such * a head page for fear of confusing slru.c. For safety we round the tail - * pointer back to a segment boundary (compare the truncation logic in - * asyncQueueAdvanceTail). + * pointer back to a segment boundary (truncation logic in + * asyncQueueAdvanceTail does not do this, so doing it here is optional). * * Note that this test is *not* dependent on how much space there is on * the current head page. This is necessary because asyncQueueAddEntries diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c index 1b262d645b2d1..074df5b38c59c 100644 --- a/src/backend/storage/lmgr/predicate.c +++ b/src/backend/storage/lmgr/predicate.c @@ -438,7 +438,7 @@ static void SetPossibleUnsafeConflict(SERIALIZABLEXACT *roXact, SERIALIZABLEXACT static void ReleaseRWConflict(RWConflict conflict); static void FlagSxactUnsafe(SERIALIZABLEXACT *sxact); -static bool SerialPagePrecedesLogically(int p, int q); +static bool SerialPagePrecedesLogically(int page1, int page2); static void SerialInit(void); static void SerialAdd(TransactionId xid, SerCommitSeqNo minConflictCommitSeqNo); static SerCommitSeqNo SerialGetMinConflictCommitSeqNo(TransactionId xid); @@ -784,28 +784,80 @@ FlagSxactUnsafe(SERIALIZABLEXACT *sxact) /*------------------------------------------------------------------------*/ /* - * We will work on the page range of 0..SERIAL_MAX_PAGE. - * Compares using wraparound logic, as is required by slru.c. + * Decide whether a Serial page number is "older" for truncation purposes. + * Analogous to CLOGPagePrecedes(). */ static bool -SerialPagePrecedesLogically(int p, int q) +SerialPagePrecedesLogically(int page1, int page2) { - int diff; + TransactionId xid1; + TransactionId xid2; + + xid1 = ((TransactionId) page1) * SERIAL_ENTRIESPERPAGE; + xid1 += FirstNormalTransactionId + 1; + xid2 = ((TransactionId) page2) * SERIAL_ENTRIESPERPAGE; + xid2 += FirstNormalTransactionId + 1; + + return (TransactionIdPrecedes(xid1, xid2) && + TransactionIdPrecedes(xid1, xid2 + SERIAL_ENTRIESPERPAGE - 1)); +} + +#ifdef USE_ASSERT_CHECKING +static void +SerialPagePrecedesLogicallyUnitTests(void) +{ + int per_page = SERIAL_ENTRIESPERPAGE, + offset = per_page / 2; + int newestPage, + oldestPage, + headPage, + targetPage; + TransactionId newestXact, + oldestXact; + + /* GetNewTransactionId() has assigned the last XID it can safely use. */ + newestPage = 2 * SLRU_PAGES_PER_SEGMENT - 1; /* nothing special */ + newestXact = newestPage * per_page + offset; + Assert(newestXact / per_page == newestPage); + oldestXact = newestXact + 1; + oldestXact -= 1U << 31; + oldestPage = oldestXact / per_page; /* - * We have to compare modulo (SERIAL_MAX_PAGE+1)/2. Both inputs should be - * in the range 0..SERIAL_MAX_PAGE. + * In this scenario, the SLRU headPage pertains to the last ~1000 XIDs + * assigned. oldestXact finishes, ~2B XIDs having elapsed since it + * started. Further transactions cause us to summarize oldestXact to + * tailPage. Function must return false so SerialAdd() doesn't zero + * tailPage (which may contain entries for other old, recently-finished + * XIDs) and half the SLRU. Reaching this requires burning ~2B XIDs in + * single-user mode, a negligible possibility. */ - Assert(p >= 0 && p <= SERIAL_MAX_PAGE); - Assert(q >= 0 && q <= SERIAL_MAX_PAGE); - - diff = p - q; - if (diff >= ((SERIAL_MAX_PAGE + 1) / 2)) - diff -= SERIAL_MAX_PAGE + 1; - else if (diff < -((int) (SERIAL_MAX_PAGE + 1) / 2)) - diff += SERIAL_MAX_PAGE + 1; - return diff < 0; + headPage = newestPage; + targetPage = oldestPage; + Assert(!SerialPagePrecedesLogically(headPage, targetPage)); + + /* + * In this scenario, the SLRU headPage pertains to oldestXact. We're + * summarizing an XID near newestXact. (Assume few other XIDs used + * SERIALIZABLE, hence the minimal headPage advancement. Assume + * oldestXact was long-running and only recently reached the SLRU.) + * Function must return true to make SerialAdd() create targetPage. + * + * Today's implementation mishandles this case, but it doesn't matter + * enough to fix. Verify that the defect affects just one page by + * asserting correct treatment of its prior page. Reaching this case + * requires burning ~2B XIDs in single-user mode, a negligible + * possibility. Moreover, if it does happen, the consequence would be + * mild, namely a new transaction failing in SimpleLruReadPage(). + */ + headPage = oldestPage; + targetPage = newestPage; + Assert(SerialPagePrecedesLogically(headPage, targetPage - 1)); +#if 0 + Assert(SerialPagePrecedesLogically(headPage, targetPage)); +#endif } +#endif /* * Initialize for the tracking of old serializable committed xids. @@ -822,6 +874,10 @@ SerialInit(void) SimpleLruInit(SerialSlruCtl, "Serial", NUM_SERIAL_BUFFERS, 0, SerialSLRULock, "pg_serial", LWTRANCHE_SERIAL_BUFFER, SYNC_HANDLER_NONE); +#ifdef USE_ASSERT_CHECKING + SerialPagePrecedesLogicallyUnitTests(); +#endif + SlruPagePrecedesUnitTests(SerialSlruCtl, SERIAL_ENTRIESPERPAGE); /* * Create or attach to the SerialControl structure. @@ -1030,7 +1086,7 @@ CheckPointPredicate(void) } else { - /* + /*---------- * The SLRU is no longer needed. Truncate to head before we set head * invalid. * @@ -1039,6 +1095,25 @@ CheckPointPredicate(void) * that we leave behind will appear to be new again. In that case it * won't be removed until XID horizon advances enough to make it * current again. + * + * XXX: This should happen in vac_truncate_clog(), not in checkpoints. + * Consider this scenario, starting from a system with no in-progress + * transactions and VACUUM FREEZE having maximized oldestXact: + * - Start a SERIALIZABLE transaction. + * - Start, finish, and summarize a SERIALIZABLE transaction, creating + * one SLRU page. + * - Consume XIDs to reach xidStopLimit. + * - Finish all transactions. Due to the long-running SERIALIZABLE + * transaction, earlier checkpoints did not touch headPage. The + * next checkpoint will change it, but that checkpoint happens after + * the end of the scenario. + * - VACUUM to advance XID limits. + * - Consume ~2M XIDs, crossing the former xidWrapLimit. + * - Start, finish, and summarize a SERIALIZABLE transaction. + * SerialAdd() declines to create the targetPage, because headPage + * is not regarded as in the past relative to that targetPage. The + * transaction instigating the summarize fails in + * SimpleLruReadPage(). */ tailPage = serialControl->headPage; serialControl->headPage = -1; diff --git a/src/include/access/slru.h b/src/include/access/slru.h index 34964675d20f6..dd52e8cec7ea9 100644 --- a/src/include/access/slru.h +++ b/src/include/access/slru.h @@ -118,9 +118,14 @@ typedef struct SlruCtlData SyncRequestHandler sync_handler; /* - * Decide which of two page numbers is "older" for truncation purposes. We - * need to use comparison of TransactionIds here in order to do the right - * thing with wraparound XID arithmetic. + * Decide whether a page is "older" for truncation and as a hint for + * evicting pages in LRU order. Return true if every entry of the first + * argument is older than every entry of the second argument. Note that + * !PagePrecedes(a,b) && !PagePrecedes(b,a) need not imply a==b; it also + * arises when some entries are older and some are not. For SLRUs using + * SimpleLruTruncate(), this must use modular arithmetic. (For others, + * the behavior of this callback has no functional implications.) Use + * SlruPagePrecedesUnitTests() in SLRUs meeting its criteria. */ bool (*PagePrecedes) (int, int); @@ -145,6 +150,11 @@ extern int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid); extern void SimpleLruWritePage(SlruCtl ctl, int slotno); extern void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied); +#ifdef USE_ASSERT_CHECKING +extern void SlruPagePrecedesUnitTests(SlruCtl ctl, int per_page); +#else +#define SlruPagePrecedesUnitTests(ctl, per_page) do {} while (0) +#endif extern void SimpleLruTruncate(SlruCtl ctl, int cutoffPage); extern bool SimpleLruDoesPhysicalPageExist(SlruCtl ctl, int pageno); From f713ff7c646e5912e08089de74dacdfaaac3d03b Mon Sep 17 00:00:00 2001 From: Noah Misch Date: Sat, 16 Jan 2021 12:21:35 -0800 Subject: [PATCH 115/240] Fix pg_dump for GRANT OPTION among initial privileges. The context is an object that no longer bears some aclitem that it bore initially. (A user issued REVOKE or GRANT statements upon the object.) pg_dump is forming SQL to reproduce the object ACL. Since initdb creates no ACL bearing GRANT OPTION, reaching this bug requires an extension where the creation script establishes such an ACL. No PGXN extension does that. If an installation did reach the bug, pg_dump would have omitted a semicolon, causing a REVOKE and the next SQL statement to fail. Separately, since the affected code exists to eliminate an entire aclitem, it wants plain REVOKE, not REVOKE GRANT OPTION FOR. Back-patch to 9.6, where commit 23f34fa4ba358671adab16773e79c17c92cbc870 first appeared. Discussion: https://postgr.es/m/20210109102423.GA160022@rfd.leadboat.com --- src/bin/pg_dump/dumputils.c | 61 +++++++------------ src/test/modules/test_pg_dump/t/001_base.pl | 39 ++++++++++++ .../test_pg_dump/test_pg_dump--1.0.sql | 9 +++ 3 files changed, 70 insertions(+), 39 deletions(-) diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c index d6aa048d4204b..60d306e7c3a32 100644 --- a/src/bin/pg_dump/dumputils.c +++ b/src/bin/pg_dump/dumputils.c @@ -168,48 +168,28 @@ buildACLCommands(const char *name, const char *subname, const char *nspname, for (i = 0; i < nraclitems; i++) { if (!parseAclItem(raclitems[i], type, name, subname, remoteVersion, - grantee, grantor, privs, privswgo)) + grantee, grantor, privs, NULL)) { ok = false; break; } - if (privs->len > 0 || privswgo->len > 0) + if (privs->len > 0) { - if (privs->len > 0) - { - appendPQExpBuffer(firstsql, "%sREVOKE %s ON %s ", - prefix, privs->data, type); - if (nspname && *nspname) - appendPQExpBuffer(firstsql, "%s.", fmtId(nspname)); - appendPQExpBuffer(firstsql, "%s FROM ", name); - if (grantee->len == 0) - appendPQExpBufferStr(firstsql, "PUBLIC;\n"); - else if (strncmp(grantee->data, "group ", - strlen("group ")) == 0) - appendPQExpBuffer(firstsql, "GROUP %s;\n", - fmtId(grantee->data + strlen("group "))); - else - appendPQExpBuffer(firstsql, "%s;\n", - fmtId(grantee->data)); - } - if (privswgo->len > 0) - { - appendPQExpBuffer(firstsql, - "%sREVOKE GRANT OPTION FOR %s ON %s ", - prefix, privswgo->data, type); - if (nspname && *nspname) - appendPQExpBuffer(firstsql, "%s.", fmtId(nspname)); - appendPQExpBuffer(firstsql, "%s FROM ", name); - if (grantee->len == 0) - appendPQExpBufferStr(firstsql, "PUBLIC"); - else if (strncmp(grantee->data, "group ", - strlen("group ")) == 0) - appendPQExpBuffer(firstsql, "GROUP %s", - fmtId(grantee->data + strlen("group "))); - else - appendPQExpBufferStr(firstsql, fmtId(grantee->data)); - } + appendPQExpBuffer(firstsql, "%sREVOKE %s ON %s ", + prefix, privs->data, type); + if (nspname && *nspname) + appendPQExpBuffer(firstsql, "%s.", fmtId(nspname)); + appendPQExpBuffer(firstsql, "%s FROM ", name); + if (grantee->len == 0) + appendPQExpBufferStr(firstsql, "PUBLIC;\n"); + else if (strncmp(grantee->data, "group ", + strlen("group ")) == 0) + appendPQExpBuffer(firstsql, "GROUP %s;\n", + fmtId(grantee->data + strlen("group "))); + else + appendPQExpBuffer(firstsql, "%s;\n", + fmtId(grantee->data)); } } } @@ -462,8 +442,11 @@ buildDefaultACLCommands(const char *type, const char *nspname, * The returned grantee string will be the dequoted username or groupname * (preceded with "group " in the latter case). Note that a grant to PUBLIC * is represented by an empty grantee string. The returned grantor is the - * dequoted grantor name. Privilege characters are decoded and split between - * privileges with grant option (privswgo) and without (privs). + * dequoted grantor name. Privilege characters are translated to GRANT/REVOKE + * comma-separated privileges lists. If "privswgo" is non-NULL, the result is + * separate lists for privileges with grant option ("privswgo") and without + * ("privs"). Otherwise, "privs" bears every relevant privilege, ignoring the + * grant option distinction. * * Note: for cross-version compatibility, it's important to use ALL to * represent the privilege sets whenever appropriate. @@ -514,7 +497,7 @@ parseAclItem(const char *item, const char *type, do { \ if ((pos = strchr(eqpos + 1, code))) \ { \ - if (*(pos + 1) == '*') \ + if (*(pos + 1) == '*' && privswgo != NULL) \ { \ AddAcl(privswgo, keywd, subname); \ all_without_go = false; \ diff --git a/src/test/modules/test_pg_dump/t/001_base.pl b/src/test/modules/test_pg_dump/t/001_base.pl index b3227b855c0a9..501aff09201a4 100644 --- a/src/test/modules/test_pg_dump/t/001_base.pl +++ b/src/test/modules/test_pg_dump/t/001_base.pl @@ -348,6 +348,45 @@ }, }, + 'REVOKE ALL ON FUNCTION wgo_then_no_access' => { + create_order => 3, + create_sql => q{ + DO $$BEGIN EXECUTE format( + 'REVOKE ALL ON FUNCTION wgo_then_no_access() + FROM pg_signal_backend, public, %I', + (SELECT usename + FROM pg_user JOIN pg_proc ON proowner = usesysid + WHERE proname = 'wgo_then_no_access')); END$$;}, + regexp => qr/^ + \QREVOKE ALL ON FUNCTION public.wgo_then_no_access() FROM PUBLIC;\E + \n\QREVOKE ALL ON FUNCTION public.wgo_then_no_access() FROM \E.*; + \n\QREVOKE ALL ON FUNCTION public.wgo_then_no_access() FROM pg_signal_backend;\E + /xm, + like => { + %full_runs, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { no_privs => 1, }, + }, + + 'REVOKE GRANT OPTION FOR UPDATE ON SEQUENCE wgo_then_regular' => { + create_order => 3, + create_sql => 'REVOKE GRANT OPTION FOR UPDATE ON SEQUENCE + wgo_then_regular FROM pg_signal_backend;', + regexp => qr/^ + \QREVOKE ALL ON SEQUENCE public.wgo_then_regular FROM pg_signal_backend;\E + \n\QGRANT SELECT,UPDATE ON SEQUENCE public.wgo_then_regular TO pg_signal_backend;\E + \n\QGRANT USAGE ON SEQUENCE public.wgo_then_regular TO pg_signal_backend WITH GRANT OPTION;\E + /xm, + like => { + %full_runs, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { no_privs => 1, }, + }, + 'CREATE ACCESS METHOD regress_test_am' => { regexp => qr/^ \QCREATE ACCESS METHOD regress_test_am TYPE INDEX HANDLER bthandler;\E diff --git a/src/test/modules/test_pg_dump/test_pg_dump--1.0.sql b/src/test/modules/test_pg_dump/test_pg_dump--1.0.sql index c7a35c3afa0f9..110f7eef66c56 100644 --- a/src/test/modules/test_pg_dump/test_pg_dump--1.0.sql +++ b/src/test/modules/test_pg_dump/test_pg_dump--1.0.sql @@ -28,6 +28,15 @@ GRANT SELECT(col1) ON regress_pg_dump_table TO public; GRANT SELECT(col2) ON regress_pg_dump_table TO regress_dump_test_role; REVOKE SELECT(col2) ON regress_pg_dump_table FROM regress_dump_test_role; +CREATE FUNCTION wgo_then_no_access() RETURNS int LANGUAGE SQL AS 'SELECT 1'; +GRANT ALL ON FUNCTION wgo_then_no_access() + TO pg_signal_backend WITH GRANT OPTION; + +CREATE SEQUENCE wgo_then_regular; +GRANT ALL ON SEQUENCE wgo_then_regular TO pg_signal_backend WITH GRANT OPTION; +REVOKE GRANT OPTION FOR SELECT ON SEQUENCE wgo_then_regular + FROM pg_signal_backend; + CREATE ACCESS METHOD regress_test_am TYPE INDEX HANDLER bthandler; -- Create a set of objects that are part of the schema created by From a32d98351e1ff33c5a65db4ed8e2def70a807bfa Mon Sep 17 00:00:00 2001 From: Jeff Davis Date: Sat, 16 Jan 2021 14:40:12 -0800 Subject: [PATCH 116/240] Documenation fixups for replication protocol. There is no CopyResponse message; it should be CopyOutResponse. Also, if there is no WAL to stream, the server does not immediately send a CommandComplete; it's a historical timeline, so it will send a response tuple first. Discussion: https://postgr.es/m/0a2c985ebcaa1acd385350aeba561b6509187394.camel@j-davis.com --- doc/src/sgml/protocol.sgml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml index 24f7b21ecbd45..3763b4b995ff5 100644 --- a/doc/src/sgml/protocol.sgml +++ b/doc/src/sgml/protocol.sgml @@ -2065,8 +2065,8 @@ The commands accepted in replication mode are: the history of the server, the server will stream all the WAL on that timeline starting from the requested start point up to the point where the server switched to another timeline. If the client requests - streaming at exactly the end of an old timeline, the server responds - immediately with CommandComplete without entering COPY mode. + streaming at exactly the end of an old timeline, the server skips COPY + mode entirely. @@ -2638,7 +2638,7 @@ The commands accepted in replication mode are: When the backup is started, the server will first send two - ordinary result sets, followed by one or more CopyResponse + ordinary result sets, followed by one or more CopyOutResponse results. @@ -2681,15 +2681,15 @@ The commands accepted in replication mode are: - After the second regular result set, one or more CopyResponse results + After the second regular result set, one or more CopyOutResponse results will be sent, one for the main data directory and one for each additional tablespace other than pg_default and pg_global. The data in - the CopyResponse results will be a tar format (following the + the CopyOutResponse results will be a tar format (following the ustar interchange format specified in the POSIX 1003.1-2008 standard) dump of the tablespace contents, except that the two trailing blocks of zeroes specified in the standard are omitted. After the tar data is complete, and if a backup manifest was requested, - another CopyResponse result is sent, containing the manifest data for the + another CopyOutResponse result is sent, containing the manifest data for the current base backup. In any case, a final ordinary result set will be sent, containing the WAL end position of the backup, in the same format as the start position. From 891a1d0bca262ca78564e0fea1eaa5ae544ea5ee Mon Sep 17 00:00:00 2001 From: Tomas Vondra Date: Sun, 17 Jan 2021 00:16:25 +0100 Subject: [PATCH 117/240] psql \dX: list extended statistics objects The new command lists extended statistics objects, possibly with their sizes. All past releases with extended statistics are supported. Author: Tatsuro Yamada Reviewed-by: Julien Rouhaud, Alvaro Herrera, Tomas Vondra Discussion: https://postgr.es/m/c027a541-5856-75a5-0868-341301e1624b%40nttcom.co.jp_1 --- doc/src/sgml/ref/psql-ref.sgml | 22 ++++ src/bin/psql/command.c | 3 + src/bin/psql/describe.c | 150 ++++++++++++++++++++++++ src/bin/psql/describe.h | 3 + src/bin/psql/help.c | 1 + src/bin/psql/tab-complete.c | 4 +- src/test/regress/expected/stats_ext.out | 94 +++++++++++++++ src/test/regress/sql/stats_ext.sql | 31 +++++ 8 files changed, 307 insertions(+), 1 deletion(-) diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index 221a967bfe664..aaf55df9215d2 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -1918,6 +1918,28 @@ testdb=> + + + \dX [ pattern ] + + + Lists extended statistics. + If pattern + is specified, only those extended statistics whose names match the + pattern are listed. + If + is appended to the command name, each extended + statistics is listed with its size. + + + + The column of the kind of extended stats (e.g. Ndistinct) shows some statuses. + "requested" means that it needs to collect statistics by ANALYZE. + "built" means ANALYZE was + finished, and the planner can use it. NULL means that it doesn't exists. + + + \dy[+] [ pattern ] diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 303e7c3ad8b38..c5ebc1c3f41d6 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -928,6 +928,9 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd) else success = listExtensions(pattern); break; + case 'X': /* Extended Statistics */ + success = listExtendedStats(pattern, show_verbose); + break; case 'y': /* Event Triggers */ success = listEventTriggers(pattern, show_verbose); break; diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index caf97563f4871..c2051ee82073f 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -4392,6 +4392,156 @@ listEventTriggers(const char *pattern, bool verbose) return true; } +/* + * \dX + * + * Describes extended statistics. + */ +bool +listExtendedStats(const char *pattern, bool verbose) +{ + PQExpBufferData buf; + PGresult *res; + printQueryOpt myopt = pset.popt; + + if (pset.sversion < 100000) + { + char sverbuf[32]; + + pg_log_error("The server (version %s) does not support extended statistics.", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); + return true; + } + + initPQExpBuffer(&buf); + printfPQExpBuffer(&buf, + "SELECT \n" + "es.stxnamespace::pg_catalog.regnamespace::text AS \"%s\", \n" + "es.stxname AS \"%s\", \n" + "pg_catalog.format('%%s FROM %%s', \n" + " (SELECT pg_catalog.string_agg(pg_catalog.quote_ident(a.attname),', ') \n" + " FROM pg_catalog.unnest(es.stxkeys) s(attnum) \n" + " JOIN pg_catalog.pg_attribute a \n" + " ON (es.stxrelid = a.attrelid \n" + " AND a.attnum = s.attnum \n" + " AND NOT a.attisdropped)), \n" + "es.stxrelid::regclass) AS \"%s\"", + gettext_noop("Schema"), + gettext_noop("Name"), + gettext_noop("Definition")); + + /* + * Since 12 there are two catalogs - one for the definition, one for the + * data built by ANALYZE. Older releases use a single catalog. Also, 12 + * adds the MCV statistics kind. + */ + if (pset.sversion < 120000) + { + appendPQExpBuffer(&buf, + ",\nCASE WHEN es.stxndistinct IS NOT NULL THEN 'built' \n" + " WHEN 'd' = any(es.stxkind) THEN 'requested' \n" + "END AS \"%s\", \n" + "CASE WHEN es.stxdependencies IS NOT NULL THEN 'built' \n" + " WHEN 'f' = any(es.stxkind) THEN 'requested' \n" + "END AS \"%s\"", + gettext_noop("Ndistinct"), + gettext_noop("Dependencies")); + } + else + { + appendPQExpBuffer(&buf, + ",\nCASE WHEN esd.stxdndistinct IS NOT NULL THEN 'built' \n" + " WHEN 'd' = any(es.stxkind) THEN 'requested' \n" + "END AS \"%s\", \n" + "CASE WHEN esd.stxddependencies IS NOT NULL THEN 'built' \n" + " WHEN 'f' = any(es.stxkind) THEN 'requested' \n" + "END AS \"%s\", \n" + "CASE WHEN esd.stxdmcv IS NOT NULL THEN 'built' \n" + " WHEN 'm' = any(es.stxkind) THEN 'requested' \n" + "END AS \"%s\"", + gettext_noop("Ndistinct"), + gettext_noop("Dependencies"), + gettext_noop("MCV")); + } + + /* In verbose mode, print sizes of the extended statistics objects. */ + if (verbose) + { + if (pset.sversion < 120000) + { + appendPQExpBuffer(&buf, + ",\nCASE WHEN es.stxndistinct IS NOT NULL THEN \n" + " pg_catalog.pg_size_pretty(pg_catalog.length(es.stxndistinct)::bigint) \n" + " WHEN 'd' = any(es.stxkind) THEN '0 bytes' \n" + "END AS \"%s\", \n" + "CASE WHEN es.stxdependencies IS NOT NULL THEN \n" + " pg_catalog.pg_size_pretty(pg_catalog.length(es.stxdependencies)::bigint) \n" + " WHEN 'f' = any(es.stxkind) THEN '0 bytes' \n" + "END AS \"%s\"", + gettext_noop("Ndistinct_size"), + gettext_noop("Dependencies_size")); + } + else + { + appendPQExpBuffer(&buf, + ",\nCASE WHEN esd.stxdndistinct IS NOT NULL THEN \n" + " pg_catalog.pg_size_pretty(pg_catalog.length(esd.stxdndistinct)::bigint) \n" + " WHEN 'd' = any(es.stxkind) THEN '0 bytes' \n" + "END AS \"%s\", \n" + "CASE WHEN esd.stxddependencies IS NOT NULL THEN \n" + " pg_catalog.pg_size_pretty(pg_catalog.length(esd.stxddependencies)::bigint) \n" + " WHEN 'f' = any(es.stxkind) THEN '0 bytes' \n" + "END AS \"%s\", \n" + "CASE WHEN esd.stxdmcv IS NOT NULL THEN \n" + " pg_catalog.pg_size_pretty(pg_catalog.length(esd.stxdmcv)::bigint) \n" + " WHEN 'm' = any(es.stxkind) THEN '0 bytes' \n" + "END AS \"%s\"", + gettext_noop("Ndistinct_size"), + gettext_noop("Dependencies_size"), + gettext_noop("MCV_size")); + } + } + + if (pset.sversion < 120000) + { + appendPQExpBufferStr(&buf, + " \nFROM pg_catalog.pg_statistic_ext es \n" + "INNER JOIN pg_catalog.pg_class c \n" + "ON es.stxrelid = c.oid \n"); + } + else + { + appendPQExpBufferStr(&buf, + " \nFROM pg_catalog.pg_statistic_ext es \n" + "LEFT JOIN pg_catalog.pg_statistic_ext_data esd \n" + "ON es.oid = esd.stxoid \n" + "INNER JOIN pg_catalog.pg_class c \n" + "ON es.stxrelid = c.oid \n"); + } + + processSQLNamePattern(pset.db, &buf, pattern, false, + false, NULL, + "es.stxname", NULL, + NULL); + + appendPQExpBufferStr(&buf, "ORDER BY 1, 2;"); + + res = PSQLexec(buf.data); + termPQExpBuffer(&buf); + if (!res) + return false; + + myopt.nullPrint = NULL; + myopt.title = _("List of extended statistics"); + myopt.translate_header = true; + + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); + + PQclear(res); + return true; +} + /* * \dC * diff --git a/src/bin/psql/describe.h b/src/bin/psql/describe.h index 6044e3a08284a..867e57d851e98 100644 --- a/src/bin/psql/describe.h +++ b/src/bin/psql/describe.h @@ -102,6 +102,9 @@ extern bool listExtensions(const char *pattern); /* \dx+ */ extern bool listExtensionContents(const char *pattern); +/* \dX */ +extern bool listExtendedStats(const char *pattern, bool verbose); + /* \dy */ extern bool listEventTriggers(const char *pattern, bool verbose); diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index 9ec1c4e810c74..e42bc8c54e06a 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -267,6 +267,7 @@ slashUsage(unsigned short int pager) fprintf(output, _(" \\du[S+] [PATTERN] list roles\n")); fprintf(output, _(" \\dv[S+] [PATTERN] list views\n")); fprintf(output, _(" \\dx[+] [PATTERN] list extensions\n")); + fprintf(output, _(" \\dX[+] [PATTERN] list extended statistics\n")); fprintf(output, _(" \\dy [PATTERN] list event triggers\n")); fprintf(output, _(" \\l[+] [PATTERN] list databases\n")); fprintf(output, _(" \\sf[+] FUNCNAME show a function's definition\n")); diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 6abcbea96349a..17f726503888d 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -1505,7 +1505,7 @@ psql_completion(const char *text, int start, int end) "\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dL", "\\dm", "\\dn", "\\do", "\\dO", "\\dp", "\\dP", "\\dPi", "\\dPt", "\\drds", "\\dRs", "\\dRp", "\\ds", "\\dS", - "\\dt", "\\dT", "\\dv", "\\du", "\\dx", "\\dy", + "\\dt", "\\dT", "\\dv", "\\du", "\\dx", "\\dX", "\\dy", "\\e", "\\echo", "\\ef", "\\elif", "\\else", "\\encoding", "\\endif", "\\errverbose", "\\ev", "\\f", @@ -3974,6 +3974,8 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL); else if (TailMatchesCS("\\dx*")) COMPLETE_WITH_QUERY(Query_for_list_of_extensions); + else if (TailMatchesCS("\\dX*")) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_statistics, NULL); else if (TailMatchesCS("\\dm*")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL); else if (TailMatchesCS("\\dE*")) diff --git a/src/test/regress/expected/stats_ext.out b/src/test/regress/expected/stats_ext.out index f094731e328ca..1531d062957d6 100644 --- a/src/test/regress/expected/stats_ext.out +++ b/src/test/regress/expected/stats_ext.out @@ -1727,6 +1727,100 @@ INSERT INTO tststats.priv_test_tbl CREATE STATISTICS tststats.priv_test_stats (mcv) ON a, b FROM tststats.priv_test_tbl; ANALYZE tststats.priv_test_tbl; +-- Check printing info about extended statistics by \dX +create table stts_t1 (a int, b int); +create statistics stts_1 (ndistinct) on a, b from stts_t1; +create statistics stts_2 (ndistinct, dependencies) on a, b from stts_t1; +create statistics stts_3 (ndistinct, dependencies, mcv) on a, b from stts_t1; +create table stts_t2 (a int, b int, c int); +create statistics stts_4 on b, c from stts_t2; +create table stts_t3 (col1 int, col2 int, col3 int); +create statistics stts_hoge on col1, col2, col3 from stts_t3; +create schema stts_s1; +create schema stts_s2; +create statistics stts_s1.stts_foo on col1, col2 from stts_t3; +create statistics stts_s2.stts_yama (dependencies, mcv) on col1, col3 from stts_t3; +insert into stts_t1 select i,i from generate_series(1,100) i; +analyze stts_t1; +\dX + List of extended statistics + Schema | Name | Definition | Ndistinct | Dependencies | MCV +----------+------------------------+--------------------------------------+-----------+--------------+----------- + public | func_deps_stat | a, b, c FROM functional_dependencies | | built | + public | mcv_lists_arrays_stats | a, b, c FROM mcv_lists_arrays | | | built + public | mcv_lists_bool_stats | a, b, c FROM mcv_lists_bool | | | built + public | mcv_lists_stats | a, b, d FROM mcv_lists | | | built + public | stts_1 | a, b FROM stts_t1 | built | | + public | stts_2 | a, b FROM stts_t1 | built | built | + public | stts_3 | a, b FROM stts_t1 | built | built | built + public | stts_4 | b, c FROM stts_t2 | requested | requested | requested + public | stts_hoge | col1, col2, col3 FROM stts_t3 | requested | requested | requested + stts_s1 | stts_foo | col1, col2 FROM stts_t3 | requested | requested | requested + stts_s2 | stts_yama | col1, col3 FROM stts_t3 | | requested | requested + tststats | priv_test_stats | a, b FROM tststats.priv_test_tbl | | | built +(12 rows) + +\dX stts_? + List of extended statistics + Schema | Name | Definition | Ndistinct | Dependencies | MCV +--------+--------+-------------------+-----------+--------------+----------- + public | stts_1 | a, b FROM stts_t1 | built | | + public | stts_2 | a, b FROM stts_t1 | built | built | + public | stts_3 | a, b FROM stts_t1 | built | built | built + public | stts_4 | b, c FROM stts_t2 | requested | requested | requested +(4 rows) + +\dX *stts_hoge + List of extended statistics + Schema | Name | Definition | Ndistinct | Dependencies | MCV +--------+-----------+-------------------------------+-----------+--------------+----------- + public | stts_hoge | col1, col2, col3 FROM stts_t3 | requested | requested | requested +(1 row) + +\dX+ + List of extended statistics + Schema | Name | Definition | Ndistinct | Dependencies | MCV | Ndistinct_size | Dependencies_size | MCV_size +----------+------------------------+--------------------------------------+-----------+--------------+-----------+----------------+-------------------+------------ + public | func_deps_stat | a, b, c FROM functional_dependencies | | built | | | 106 bytes | + public | mcv_lists_arrays_stats | a, b, c FROM mcv_lists_arrays | | | built | | | 24 kB + public | mcv_lists_bool_stats | a, b, c FROM mcv_lists_bool | | | built | | | 386 bytes + public | mcv_lists_stats | a, b, d FROM mcv_lists | | | built | | | 294 bytes + public | stts_1 | a, b FROM stts_t1 | built | | | 13 bytes | | + public | stts_2 | a, b FROM stts_t1 | built | built | | 13 bytes | 40 bytes | + public | stts_3 | a, b FROM stts_t1 | built | built | built | 13 bytes | 40 bytes | 6126 bytes + public | stts_4 | b, c FROM stts_t2 | requested | requested | requested | 0 bytes | 0 bytes | 0 bytes + public | stts_hoge | col1, col2, col3 FROM stts_t3 | requested | requested | requested | 0 bytes | 0 bytes | 0 bytes + stts_s1 | stts_foo | col1, col2 FROM stts_t3 | requested | requested | requested | 0 bytes | 0 bytes | 0 bytes + stts_s2 | stts_yama | col1, col3 FROM stts_t3 | | requested | requested | | 0 bytes | 0 bytes + tststats | priv_test_stats | a, b FROM tststats.priv_test_tbl | | | built | | | 686 bytes +(12 rows) + +\dX+ stts_? + List of extended statistics + Schema | Name | Definition | Ndistinct | Dependencies | MCV | Ndistinct_size | Dependencies_size | MCV_size +--------+--------+-------------------+-----------+--------------+-----------+----------------+-------------------+------------ + public | stts_1 | a, b FROM stts_t1 | built | | | 13 bytes | | + public | stts_2 | a, b FROM stts_t1 | built | built | | 13 bytes | 40 bytes | + public | stts_3 | a, b FROM stts_t1 | built | built | built | 13 bytes | 40 bytes | 6126 bytes + public | stts_4 | b, c FROM stts_t2 | requested | requested | requested | 0 bytes | 0 bytes | 0 bytes +(4 rows) + +\dX+ *stts_hoge + List of extended statistics + Schema | Name | Definition | Ndistinct | Dependencies | MCV | Ndistinct_size | Dependencies_size | MCV_size +--------+-----------+-------------------------------+-----------+--------------+-----------+----------------+-------------------+---------- + public | stts_hoge | col1, col2, col3 FROM stts_t3 | requested | requested | requested | 0 bytes | 0 bytes | 0 bytes +(1 row) + +\dX+ stts_s2.stts_yama + List of extended statistics + Schema | Name | Definition | Ndistinct | Dependencies | MCV | Ndistinct_size | Dependencies_size | MCV_size +---------+-----------+-------------------------+-----------+--------------+-----------+----------------+-------------------+---------- + stts_s2 | stts_yama | col1, col3 FROM stts_t3 | | requested | requested | | 0 bytes | 0 bytes +(1 row) + +drop table stts_t1, stts_t2, stts_t3; +drop schema stts_s1, stts_s2 cascade; -- User with no access CREATE USER regress_stats_user1; GRANT USAGE ON SCHEMA tststats TO regress_stats_user1; diff --git a/src/test/regress/sql/stats_ext.sql b/src/test/regress/sql/stats_ext.sql index cb08b478a42b6..c83840298e8e8 100644 --- a/src/test/regress/sql/stats_ext.sql +++ b/src/test/regress/sql/stats_ext.sql @@ -914,6 +914,37 @@ CREATE STATISTICS tststats.priv_test_stats (mcv) ON a, b ANALYZE tststats.priv_test_tbl; +-- Check printing info about extended statistics by \dX +create table stts_t1 (a int, b int); +create statistics stts_1 (ndistinct) on a, b from stts_t1; +create statistics stts_2 (ndistinct, dependencies) on a, b from stts_t1; +create statistics stts_3 (ndistinct, dependencies, mcv) on a, b from stts_t1; + +create table stts_t2 (a int, b int, c int); +create statistics stts_4 on b, c from stts_t2; + +create table stts_t3 (col1 int, col2 int, col3 int); +create statistics stts_hoge on col1, col2, col3 from stts_t3; + +create schema stts_s1; +create schema stts_s2; +create statistics stts_s1.stts_foo on col1, col2 from stts_t3; +create statistics stts_s2.stts_yama (dependencies, mcv) on col1, col3 from stts_t3; + +insert into stts_t1 select i,i from generate_series(1,100) i; +analyze stts_t1; + +\dX +\dX stts_? +\dX *stts_hoge +\dX+ +\dX+ stts_? +\dX+ *stts_hoge +\dX+ stts_s2.stts_yama + +drop table stts_t1, stts_t2, stts_t3; +drop schema stts_s1, stts_s2 cascade; + -- User with no access CREATE USER regress_stats_user1; GRANT USAGE ON SCHEMA tststats TO regress_stats_user1; From 960869da0803427d14335bba24393f414b476e2c Mon Sep 17 00:00:00 2001 From: Magnus Hagander Date: Sun, 17 Jan 2021 13:34:09 +0100 Subject: [PATCH 118/240] Add pg_stat_database counters for sessions and session time This add counters for number of sessions, the different kind of session termination types, and timers for how much time is spent in active vs idle in a database to pg_stat_database. Internally this also renames the parameter "force" to disconnect. This was the only use-case for the parameter before, so repurposing it to this mroe narrow usecase makes things cleaner than inventing something new. Author: Laurenz Albe Reviewed-By: Magnus Hagander, Soumyadeep Chakraborty, Masahiro Ikeda Discussion: https://postgr.es/m/b07e1f9953701b90c66ed368656f2aef40cac4fb.camel@cybertec.at --- doc/src/sgml/monitoring.sgml | 77 +++++++++++++++ src/backend/catalog/system_views.sql | 7 ++ src/backend/postmaster/pgstat.c | 134 ++++++++++++++++++++++++++- src/backend/tcop/postgres.c | 11 ++- src/backend/utils/adt/pgstatfuncs.c | 94 +++++++++++++++++++ src/backend/utils/error/elog.c | 8 ++ src/include/catalog/catversion.h | 2 +- src/include/catalog/pg_proc.dat | 32 +++++++ src/include/pgstat.h | 39 ++++++++ src/test/regress/expected/rules.out | 7 ++ 10 files changed, 405 insertions(+), 6 deletions(-) diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index 3cdb1aff3c8fc..f05140dd42400 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -3737,6 +3737,83 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i + + + session_time double precision + + + Time spent by database sessions in this database, in milliseconds + (note that statistics are only updated when the state of a session + changes, so if sessions have been idle for a long time, this idle time + won't be included) + + + + + + active_time double precision + + + Time spent executing SQL statements in this database, in milliseconds + (this corresponds to the states active and + fastpath function call in + + pg_stat_activity) + + + + + + idle_in_transaction_time double precision + + + Time spent idling while in a transaction in this database, in milliseconds + (this corresponds to the states idle in transaction and + idle in transaction (aborted) in + + pg_stat_activity) + + + + + + sessions bigint + + + Total number of sessions established to this database + + + + + + sessions_abandoned bigint + + + Number of database sessions to this database that were terminated + because connection to the client was lost + + + + + + sessions_fatal bigint + + + Number of database sessions to this database that were terminated + by fatal errors + + + + + + sessions_killed bigint + + + Number of database sessions to this database that were terminated + by operator intervention + + + stats_reset timestamp with time zone diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 5d89e77dbe2f5..fa58afd9d7814 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -924,6 +924,13 @@ CREATE VIEW pg_stat_database AS pg_stat_get_db_checksum_last_failure(D.oid) AS checksum_last_failure, pg_stat_get_db_blk_read_time(D.oid) AS blk_read_time, pg_stat_get_db_blk_write_time(D.oid) AS blk_write_time, + pg_stat_get_db_session_time(D.oid) AS session_time, + pg_stat_get_db_active_time(D.oid) AS active_time, + pg_stat_get_db_idle_in_transaction_time(D.oid) AS idle_in_transaction_time, + pg_stat_get_db_sessions(D.oid) AS sessions, + pg_stat_get_db_sessions_abandoned(D.oid) AS sessions_abandoned, + pg_stat_get_db_sessions_fatal(D.oid) AS sessions_fatal, + pg_stat_get_db_sessions_killed(D.oid) AS sessions_killed, pg_stat_get_db_stat_reset_time(D.oid) AS stats_reset FROM ( SELECT 0 AS oid, NULL::name AS datname diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index 3f24a33ef1da4..f75b52719dddd 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -258,6 +258,9 @@ static int pgStatXactCommit = 0; static int pgStatXactRollback = 0; PgStat_Counter pgStatBlockReadTime = 0; PgStat_Counter pgStatBlockWriteTime = 0; +static PgStat_Counter pgStatActiveTime = 0; +static PgStat_Counter pgStatTransactionIdleTime = 0; +SessionEndType pgStatSessionEndCause = DISCONNECT_NORMAL; /* Record that's written to 2PC state file when pgstat state is persisted */ typedef struct TwoPhasePgStatRecord @@ -343,6 +346,7 @@ static void pgstat_send_tabstat(PgStat_MsgTabstat *tsmsg); static void pgstat_send_funcstats(void); static void pgstat_send_slru(void); static HTAB *pgstat_collect_oids(Oid catalogid, AttrNumber anum_oid); +static void pgstat_send_connstats(bool disconnect, TimestampTz last_report); static PgStat_TableStatus *get_tabstat_entry(Oid rel_id, bool isshared); @@ -378,6 +382,7 @@ static void pgstat_recv_funcpurge(PgStat_MsgFuncpurge *msg, int len); static void pgstat_recv_recoveryconflict(PgStat_MsgRecoveryConflict *msg, int len); static void pgstat_recv_deadlock(PgStat_MsgDeadlock *msg, int len); static void pgstat_recv_checksum_failure(PgStat_MsgChecksumFailure *msg, int len); +static void pgstat_recv_connstat(PgStat_MsgConn *msg, int len); static void pgstat_recv_replslot(PgStat_MsgReplSlot *msg, int len); static void pgstat_recv_tempfile(PgStat_MsgTempFile *msg, int len); @@ -855,10 +860,14 @@ allow_immediate_pgstat_restart(void) * per-table and function usage statistics to the collector. Note that this * is called only when not within a transaction, so it is fair to use * transaction stop time as an approximation of current time. + * + * "disconnect" is "true" only for the last call before the backend + * exits. This makes sure that no data is lost and that interrupted + * sessions are reported correctly. * ---------- */ void -pgstat_report_stat(bool force) +pgstat_report_stat(bool disconnect) { /* we assume this inits to all zeroes: */ static const PgStat_TableCounts all_zeroes; @@ -873,17 +882,22 @@ pgstat_report_stat(bool force) /* Don't expend a clock check if nothing to do */ if ((pgStatTabList == NULL || pgStatTabList->tsa_used == 0) && pgStatXactCommit == 0 && pgStatXactRollback == 0 && - !have_function_stats) + !have_function_stats && !disconnect) return; /* * Don't send a message unless it's been at least PGSTAT_STAT_INTERVAL - * msec since we last sent one, or the caller wants to force stats out. + * msec since we last sent one, or the backend is about to exit. */ now = GetCurrentTransactionStopTimestamp(); - if (!force && + if (!disconnect && !TimestampDifferenceExceeds(last_report, now, PGSTAT_STAT_INTERVAL)) return; + + /* for backends, send connection statistics */ + if (MyBackendType == B_BACKEND) + pgstat_send_connstats(disconnect, last_report); + last_report = now; /* @@ -1351,6 +1365,48 @@ pgstat_drop_relation(Oid relid) #endif /* NOT_USED */ +/* ---------- + * pgstat_send_connstats() - + * + * Tell the collector about session statistics. + * The parameter "disconnect" will be true when the backend exits. + * "last_report" is the last time we were called (0 if never). + * ---------- + */ +static void +pgstat_send_connstats(bool disconnect, TimestampTz last_report) +{ + PgStat_MsgConn msg; + long secs; + int usecs; + + if (pgStatSock == PGINVALID_SOCKET || !pgstat_track_counts) + return; + + pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_CONNECTION); + msg.m_databaseid = MyDatabaseId; + + /* session time since the last report */ + TimestampDifference(((last_report == 0) ? MyStartTimestamp : last_report), + GetCurrentTimestamp(), + &secs, &usecs); + msg.m_session_time = secs * 1000000 + usecs; + + msg.m_disconnect = disconnect ? pgStatSessionEndCause : DISCONNECT_NOT_YET; + + msg.m_active_time = pgStatActiveTime; + pgStatActiveTime = 0; + + msg.m_idle_in_xact_time = pgStatTransactionIdleTime; + pgStatTransactionIdleTime = 0; + + /* report a new session only the first time */ + msg.m_count = (last_report == 0) ? 1 : 0; + + pgstat_send(&msg, sizeof(PgStat_MsgConn)); +} + + /* ---------- * pgstat_reset_counters() - * @@ -3348,6 +3404,30 @@ pgstat_report_activity(BackendState state, const char *cmd_str) } current_timestamp = GetCurrentTimestamp(); + /* + * If the state has changed from "active" or "idle in transaction", + * calculate the duration. + */ + if ((beentry->st_state == STATE_RUNNING || + beentry->st_state == STATE_FASTPATH || + beentry->st_state == STATE_IDLEINTRANSACTION || + beentry->st_state == STATE_IDLEINTRANSACTION_ABORTED) && + state != beentry->st_state) + { + long secs; + int usecs; + + TimestampDifference(beentry->st_state_start_timestamp, + current_timestamp, + &secs, &usecs); + + if (beentry->st_state == STATE_RUNNING || + beentry->st_state == STATE_FASTPATH) + pgStatActiveTime += secs * 1000000 + usecs; + else + pgStatTransactionIdleTime += secs * 1000000 + usecs; + } + /* * Now update the status entry */ @@ -4919,6 +4999,10 @@ PgstatCollectorMain(int argc, char *argv[]) pgstat_recv_replslot(&msg.msg_replslot, len); break; + case PGSTAT_MTYPE_CONNECTION: + pgstat_recv_connstat(&msg.msg_conn, len); + break; + default: break; } @@ -4993,6 +5077,13 @@ reset_dbentry_counters(PgStat_StatDBEntry *dbentry) dbentry->last_checksum_failure = 0; dbentry->n_block_read_time = 0; dbentry->n_block_write_time = 0; + dbentry->n_sessions = 0; + dbentry->total_session_time = 0; + dbentry->total_active_time = 0; + dbentry->total_idle_in_xact_time = 0; + dbentry->n_sessions_abandoned = 0; + dbentry->n_sessions_fatal = 0; + dbentry->n_sessions_killed = 0; dbentry->stat_reset_timestamp = GetCurrentTimestamp(); dbentry->stats_timestamp = 0; @@ -6944,6 +7035,41 @@ pgstat_recv_replslot(PgStat_MsgReplSlot *msg, int len) } } +/* ---------- + * pgstat_recv_connstat() - + * + * Process connection information. + * ---------- + */ +static void +pgstat_recv_connstat(PgStat_MsgConn *msg, int len) +{ + PgStat_StatDBEntry *dbentry; + + dbentry = pgstat_get_db_entry(msg->m_databaseid, true); + + dbentry->n_sessions += msg->m_count; + dbentry->total_session_time += msg->m_session_time; + dbentry->total_active_time += msg->m_active_time; + dbentry->total_idle_in_xact_time += msg->m_idle_in_xact_time; + switch (msg->m_disconnect) + { + case DISCONNECT_NOT_YET: + case DISCONNECT_NORMAL: + /* we don't collect these */ + break; + case DISCONNECT_CLIENT_EOF: + dbentry->n_sessions_abandoned++; + break; + case DISCONNECT_FATAL: + dbentry->n_sessions_fatal++; + break; + case DISCONNECT_KILLED: + dbentry->n_sessions_killed++; + break; + } +} + /* ---------- * pgstat_recv_tempfile() - * diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 28055680aad73..8dab9fd578001 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -2865,6 +2865,9 @@ die(SIGNAL_ARGS) ProcDiePending = true; } + /* for the statistics collector */ + pgStatSessionEndCause = DISCONNECT_KILLED; + /* If we're still here, waken anything waiting on the process latch */ SetLatch(MyLatch); @@ -4579,9 +4582,15 @@ PostgresMain(int argc, char *argv[], * means unexpected loss of frontend connection. Either way, * perform normal shutdown. */ - case 'X': case EOF: + /* for the statistics collector */ + pgStatSessionEndCause = DISCONNECT_CLIENT_EOF; + + /* FALLTHROUGH */ + + case 'X': + /* * Reset whereToSendOutput to prevent ereport from attempting * to send any more messages to client. diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index 5c12a165a1535..62bff52638d11 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -1631,6 +1631,100 @@ pg_stat_get_db_blk_write_time(PG_FUNCTION_ARGS) PG_RETURN_FLOAT8(result); } +Datum +pg_stat_get_db_session_time(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + double result = 0.0; + PgStat_StatDBEntry *dbentry; + + /* convert counter from microsec to millisec for display */ + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) != NULL) + result = ((double) dbentry->total_session_time) / 1000.0; + + PG_RETURN_FLOAT8(result); +} + +Datum +pg_stat_get_db_active_time(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + double result = 0.0; + PgStat_StatDBEntry *dbentry; + + /* convert counter from microsec to millisec for display */ + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) != NULL) + result = ((double) dbentry->total_active_time) / 1000.0; + + PG_RETURN_FLOAT8(result); +} + +Datum +pg_stat_get_db_idle_in_transaction_time(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + double result = 0.0; + PgStat_StatDBEntry *dbentry; + + /* convert counter from microsec to millisec for display */ + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) != NULL) + result = ((double) dbentry->total_idle_in_xact_time) / 1000.0; + + PG_RETURN_FLOAT8(result); +} + +Datum +pg_stat_get_db_sessions(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result = 0; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) != NULL) + result = (int64) (dbentry->n_sessions); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_db_sessions_abandoned(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result = 0; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) != NULL) + result = (int64) (dbentry->n_sessions_abandoned); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_db_sessions_fatal(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result = 0; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) != NULL) + result = (int64) (dbentry->n_sessions_fatal); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_db_sessions_killed(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result = 0; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) != NULL) + result = (int64) (dbentry->n_sessions_killed); + + PG_RETURN_INT64(result); +} + Datum pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS) { diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index 7790f6ab25590..80c26724612cb 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -72,6 +72,7 @@ #include "libpq/pqformat.h" #include "mb/pg_wchar.h" #include "miscadmin.h" +#include "pgstat.h" #include "postmaster/bgworker.h" #include "postmaster/postmaster.h" #include "postmaster/syslogger.h" @@ -656,6 +657,13 @@ errfinish(const char *filename, int lineno, const char *funcname) fflush(stdout); fflush(stderr); + /* + * Let the statistics collector know. Only mark the session as + * terminated by fatal error if there is no other known cause. + */ + if (pgStatSessionEndCause == DISCONNECT_NORMAL) + pgStatSessionEndCause = DISCONNECT_FATAL; + /* * Do normal process-exit cleanup, then return exit code 1 to indicate * FATAL termination. The postmaster may or may not consider this diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 747135dab46f2..385d108c292b0 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202101131 +#define CATALOG_VERSION_NO 202101171 #endif diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index d27336adcd9f5..dd64c3bd60bd4 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -5440,6 +5440,38 @@ proname => 'pg_stat_get_db_blk_write_time', provolatile => 's', proparallel => 'r', prorettype => 'float8', proargtypes => 'oid', prosrc => 'pg_stat_get_db_blk_write_time' }, +{ oid => '9575', descr => 'statistics: session time, in milliseconds', + proname => 'pg_stat_get_db_session_time', provolatile => 's', + proparallel => 'r', prorettype => 'float8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_session_time' }, +{ oid => '9576', descr => 'statistics: session active time, in milliseconds', + proname => 'pg_stat_get_db_active_time', provolatile => 's', + proparallel => 'r', prorettype => 'float8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_active_time' }, +{ oid => '9577', + descr => 'statistics: session idle in transaction time, in milliseconds', + proname => 'pg_stat_get_db_idle_in_transaction_time', provolatile => 's', + proparallel => 'r', prorettype => 'float8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_idle_in_transaction_time' }, +{ oid => '9578', descr => 'statistics: total number of sessions', + proname => 'pg_stat_get_db_sessions', provolatile => 's', proparallel => 'r', + prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_sessions' }, +{ oid => '9579', + descr => 'statistics: number of sessions disconnected by the client closing the network connection', + proname => 'pg_stat_get_db_sessions_abandoned', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_sessions_abandoned' }, +{ oid => '9580', + descr => 'statistics: number of sessions disconnected by fatal errors', + proname => 'pg_stat_get_db_sessions_fatal', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_sessions_fatal' }, +{ oid => '9581', + descr => 'statistics: number of sessions killed by administrative action', + proname => 'pg_stat_get_db_sessions_killed', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_sessions_killed' }, { oid => '3195', descr => 'statistics: information about WAL archiver', proname => 'pg_stat_get_archiver', proisstrict => 'f', provolatile => 's', proparallel => 'r', prorettype => 'record', proargtypes => '', diff --git a/src/include/pgstat.h b/src/include/pgstat.h index c38b68971019c..a384f6eb56f05 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -41,6 +41,16 @@ typedef enum TrackFunctionsLevel TRACK_FUNC_ALL } TrackFunctionsLevel; +/* Values to track the cause of session termination */ +typedef enum SessionEndType +{ + DISCONNECT_NOT_YET, /* still active */ + DISCONNECT_NORMAL, + DISCONNECT_CLIENT_EOF, + DISCONNECT_FATAL, + DISCONNECT_KILLED +} SessionEndType; + /* ---------- * The types of backend -> collector messages * ---------- @@ -71,6 +81,7 @@ typedef enum StatMsgType PGSTAT_MTYPE_DEADLOCK, PGSTAT_MTYPE_CHECKSUMFAILURE, PGSTAT_MTYPE_REPLSLOT, + PGSTAT_MTYPE_CONNECTION, } StatMsgType; /* ---------- @@ -622,6 +633,21 @@ typedef struct PgStat_MsgChecksumFailure TimestampTz m_failure_time; } PgStat_MsgChecksumFailure; +/* ---------- + * PgStat_MsgConn Sent by the backend to update connection statistics. + * ---------- + */ +typedef struct PgStat_MsgConn +{ + PgStat_MsgHdr m_hdr; + Oid m_databaseid; + PgStat_Counter m_count; + PgStat_Counter m_session_time; + PgStat_Counter m_active_time; + PgStat_Counter m_idle_in_xact_time; + SessionEndType m_disconnect; +} PgStat_MsgConn; + /* ---------- * PgStat_Msg Union over all possible messages. @@ -654,6 +680,7 @@ typedef union PgStat_Msg PgStat_MsgTempFile msg_tempfile; PgStat_MsgChecksumFailure msg_checksumfailure; PgStat_MsgReplSlot msg_replslot; + PgStat_MsgConn msg_conn; } PgStat_Msg; @@ -696,6 +723,13 @@ typedef struct PgStat_StatDBEntry TimestampTz last_checksum_failure; PgStat_Counter n_block_read_time; /* times in microseconds */ PgStat_Counter n_block_write_time; + PgStat_Counter n_sessions; + PgStat_Counter total_session_time; + PgStat_Counter total_active_time; + PgStat_Counter total_idle_in_xact_time; + PgStat_Counter n_sessions_abandoned; + PgStat_Counter n_sessions_fatal; + PgStat_Counter n_sessions_killed; TimestampTz stat_reset_timestamp; TimestampTz stats_timestamp; /* time of db stats file update */ @@ -1354,6 +1388,11 @@ extern PgStat_MsgWal WalStats; extern PgStat_Counter pgStatBlockReadTime; extern PgStat_Counter pgStatBlockWriteTime; +/* + * Updated by the traffic cop and in errfinish() + */ +extern SessionEndType pgStatSessionEndCause; + /* ---------- * Functions called from postmaster * ---------- diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index a687e99d1e4fe..6173473de9d68 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1848,6 +1848,13 @@ pg_stat_database| SELECT d.oid AS datid, pg_stat_get_db_checksum_last_failure(d.oid) AS checksum_last_failure, pg_stat_get_db_blk_read_time(d.oid) AS blk_read_time, pg_stat_get_db_blk_write_time(d.oid) AS blk_write_time, + pg_stat_get_db_session_time(d.oid) AS session_time, + pg_stat_get_db_active_time(d.oid) AS active_time, + pg_stat_get_db_idle_in_transaction_time(d.oid) AS idle_in_transaction_time, + pg_stat_get_db_sessions(d.oid) AS sessions, + pg_stat_get_db_sessions_abandoned(d.oid) AS sessions_abandoned, + pg_stat_get_db_sessions_fatal(d.oid) AS sessions_fatal, + pg_stat_get_db_sessions_killed(d.oid) AS sessions_killed, pg_stat_get_db_stat_reset_time(d.oid) AS stats_reset FROM ( SELECT 0 AS oid, NULL::name AS datname From e09155bd62f0ac5817cb3d736eb35adf4200549e Mon Sep 17 00:00:00 2001 From: Magnus Hagander Date: Sun, 17 Jan 2021 14:28:17 +0100 Subject: [PATCH 119/240] Add --no-instructions parameter to initdb Specifying this parameter removes the informational messages about how to start the server. This is intended for use by wrappers in different packaging systems, where those instructions would most likely be wrong anyway, but the other output from initdb would still be useful (and thus just redirecting everything to /dev/null would be bad). Author: Magnus Hagander Reviewed-By: Peter Eisentraut Discusion: https://postgr.es/m/CABUevEzo4t5bmTXF0_B9WzmuWpVbMpkNZZiGvzV8NZa-=fPqeQ@mail.gmail.com --- doc/src/sgml/ref/initdb.sgml | 13 +++++++++ src/bin/initdb/initdb.c | 56 ++++++++++++++++++++++-------------- 2 files changed, 47 insertions(+), 22 deletions(-) diff --git a/doc/src/sgml/ref/initdb.sgml b/doc/src/sgml/ref/initdb.sgml index 385ac2515061c..995d78408e574 100644 --- a/doc/src/sgml/ref/initdb.sgml +++ b/doc/src/sgml/ref/initdb.sgml @@ -275,6 +275,19 @@ PostgreSQL documentation + + + + + By default, initdb will write instructions for how + to start the cluster at the end of its output. This option causes + those instructions to be left out. This is primarily intended for use + by tools that wrap initdb in platform specific + behavior, where those instructions are likely to be incorrect. + + + + diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index c854221a30602..e242a4a5b586a 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -139,6 +139,7 @@ static const char *authmethodhost = NULL; static const char *authmethodlocal = NULL; static bool debug = false; static bool noclean = false; +static bool noinstructions = false; static bool do_sync = true; static bool sync_only = false; static bool show_setting = false; @@ -2294,6 +2295,7 @@ usage(const char *progname) printf(_(" -L DIRECTORY where to find the input files\n")); printf(_(" -n, --no-clean do not clean up after errors\n")); printf(_(" -N, --no-sync do not wait for changes to be written safely to disk\n")); + printf(_(" --no-instructions do not print instructions for next steps\n")); printf(_(" -s, --show show internal settings\n")); printf(_(" -S, --sync-only only sync data directory\n")); printf(_("\nOther options:\n")); @@ -2955,6 +2957,7 @@ main(int argc, char *argv[]) {"no-clean", no_argument, NULL, 'n'}, {"nosync", no_argument, NULL, 'N'}, /* for backwards compatibility */ {"no-sync", no_argument, NULL, 'N'}, + {"no-instructions", no_argument, NULL, 13}, {"sync-only", no_argument, NULL, 'S'}, {"waldir", required_argument, NULL, 'X'}, {"wal-segsize", required_argument, NULL, 12}, @@ -3095,6 +3098,9 @@ main(int argc, char *argv[]) case 12: str_wal_segment_size_mb = pg_strdup(optarg); break; + case 13: + noinstructions = true; + break; case 'g': SetDataDirectoryCreatePerm(PG_DIR_MODE_GROUP); break; @@ -3245,34 +3251,40 @@ main(int argc, char *argv[]) "--auth-local and --auth-host, the next time you run initdb.\n")); } - /* - * Build up a shell command to tell the user how to start the server - */ - start_db_cmd = createPQExpBuffer(); + if (!noinstructions) + { + /* + * Build up a shell command to tell the user how to start the server + */ + start_db_cmd = createPQExpBuffer(); + + /* Get directory specification used to start initdb ... */ + strlcpy(pg_ctl_path, argv[0], sizeof(pg_ctl_path)); + canonicalize_path(pg_ctl_path); + get_parent_directory(pg_ctl_path); + /* ... and tag on pg_ctl instead */ + join_path_components(pg_ctl_path, pg_ctl_path, "pg_ctl"); - /* Get directory specification used to start initdb ... */ - strlcpy(pg_ctl_path, argv[0], sizeof(pg_ctl_path)); - canonicalize_path(pg_ctl_path); - get_parent_directory(pg_ctl_path); - /* ... and tag on pg_ctl instead */ - join_path_components(pg_ctl_path, pg_ctl_path, "pg_ctl"); + /* path to pg_ctl, properly quoted */ + appendShellString(start_db_cmd, pg_ctl_path); - /* path to pg_ctl, properly quoted */ - appendShellString(start_db_cmd, pg_ctl_path); + /* add -D switch, with properly quoted data directory */ + appendPQExpBufferStr(start_db_cmd, " -D "); + appendShellString(start_db_cmd, pgdata_native); - /* add -D switch, with properly quoted data directory */ - appendPQExpBufferStr(start_db_cmd, " -D "); - appendShellString(start_db_cmd, pgdata_native); + /* add suggested -l switch and "start" command */ + /* translator: This is a placeholder in a shell command. */ + appendPQExpBuffer(start_db_cmd, " -l %s start", _("logfile")); - /* add suggested -l switch and "start" command */ - /* translator: This is a placeholder in a shell command. */ - appendPQExpBuffer(start_db_cmd, " -l %s start", _("logfile")); + printf(_("\nSuccess. You can now start the database server using:\n\n" + " %s\n\n"), + start_db_cmd->data); - printf(_("\nSuccess. You can now start the database server using:\n\n" - " %s\n\n"), - start_db_cmd->data); + destroyPQExpBuffer(start_db_cmd); + + printf(_("\nSuccess.\n")); + } - destroyPQExpBuffer(start_db_cmd); success = true; return 0; From 1db0d173a2201119f297ea35edfb41579893dd8c Mon Sep 17 00:00:00 2001 From: Tomas Vondra Date: Sun, 17 Jan 2021 15:11:14 +0100 Subject: [PATCH 120/240] Revert "psql \dX: list extended statistics objects" Reverts 891a1d0bca, because the new psql command \dX only worked for users users who can read pg_statistic_ext_data catalog, and most regular users lack that privilege (the catalog may contain sensitive user data). Reported-by: Noriyoshi Shinoda Discussion: https://postgr.es/m/c027a541-5856-75a5-0868-341301e1624b%40nttcom.co.jp_1 --- doc/src/sgml/ref/psql-ref.sgml | 22 ---- src/bin/psql/command.c | 3 - src/bin/psql/describe.c | 150 ------------------------ src/bin/psql/describe.h | 3 - src/bin/psql/help.c | 1 - src/bin/psql/tab-complete.c | 4 +- src/test/regress/expected/stats_ext.out | 94 --------------- src/test/regress/sql/stats_ext.sql | 31 ----- 8 files changed, 1 insertion(+), 307 deletions(-) diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index aaf55df9215d2..221a967bfe664 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -1918,28 +1918,6 @@ testdb=> - - - \dX [ pattern ] - - - Lists extended statistics. - If pattern - is specified, only those extended statistics whose names match the - pattern are listed. - If + is appended to the command name, each extended - statistics is listed with its size. - - - - The column of the kind of extended stats (e.g. Ndistinct) shows some statuses. - "requested" means that it needs to collect statistics by ANALYZE. - "built" means ANALYZE was - finished, and the planner can use it. NULL means that it doesn't exists. - - - \dy[+] [ pattern ] diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index c5ebc1c3f41d6..303e7c3ad8b38 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -928,9 +928,6 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd) else success = listExtensions(pattern); break; - case 'X': /* Extended Statistics */ - success = listExtendedStats(pattern, show_verbose); - break; case 'y': /* Event Triggers */ success = listEventTriggers(pattern, show_verbose); break; diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index c2051ee82073f..caf97563f4871 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -4392,156 +4392,6 @@ listEventTriggers(const char *pattern, bool verbose) return true; } -/* - * \dX - * - * Describes extended statistics. - */ -bool -listExtendedStats(const char *pattern, bool verbose) -{ - PQExpBufferData buf; - PGresult *res; - printQueryOpt myopt = pset.popt; - - if (pset.sversion < 100000) - { - char sverbuf[32]; - - pg_log_error("The server (version %s) does not support extended statistics.", - formatPGVersionNumber(pset.sversion, false, - sverbuf, sizeof(sverbuf))); - return true; - } - - initPQExpBuffer(&buf); - printfPQExpBuffer(&buf, - "SELECT \n" - "es.stxnamespace::pg_catalog.regnamespace::text AS \"%s\", \n" - "es.stxname AS \"%s\", \n" - "pg_catalog.format('%%s FROM %%s', \n" - " (SELECT pg_catalog.string_agg(pg_catalog.quote_ident(a.attname),', ') \n" - " FROM pg_catalog.unnest(es.stxkeys) s(attnum) \n" - " JOIN pg_catalog.pg_attribute a \n" - " ON (es.stxrelid = a.attrelid \n" - " AND a.attnum = s.attnum \n" - " AND NOT a.attisdropped)), \n" - "es.stxrelid::regclass) AS \"%s\"", - gettext_noop("Schema"), - gettext_noop("Name"), - gettext_noop("Definition")); - - /* - * Since 12 there are two catalogs - one for the definition, one for the - * data built by ANALYZE. Older releases use a single catalog. Also, 12 - * adds the MCV statistics kind. - */ - if (pset.sversion < 120000) - { - appendPQExpBuffer(&buf, - ",\nCASE WHEN es.stxndistinct IS NOT NULL THEN 'built' \n" - " WHEN 'd' = any(es.stxkind) THEN 'requested' \n" - "END AS \"%s\", \n" - "CASE WHEN es.stxdependencies IS NOT NULL THEN 'built' \n" - " WHEN 'f' = any(es.stxkind) THEN 'requested' \n" - "END AS \"%s\"", - gettext_noop("Ndistinct"), - gettext_noop("Dependencies")); - } - else - { - appendPQExpBuffer(&buf, - ",\nCASE WHEN esd.stxdndistinct IS NOT NULL THEN 'built' \n" - " WHEN 'd' = any(es.stxkind) THEN 'requested' \n" - "END AS \"%s\", \n" - "CASE WHEN esd.stxddependencies IS NOT NULL THEN 'built' \n" - " WHEN 'f' = any(es.stxkind) THEN 'requested' \n" - "END AS \"%s\", \n" - "CASE WHEN esd.stxdmcv IS NOT NULL THEN 'built' \n" - " WHEN 'm' = any(es.stxkind) THEN 'requested' \n" - "END AS \"%s\"", - gettext_noop("Ndistinct"), - gettext_noop("Dependencies"), - gettext_noop("MCV")); - } - - /* In verbose mode, print sizes of the extended statistics objects. */ - if (verbose) - { - if (pset.sversion < 120000) - { - appendPQExpBuffer(&buf, - ",\nCASE WHEN es.stxndistinct IS NOT NULL THEN \n" - " pg_catalog.pg_size_pretty(pg_catalog.length(es.stxndistinct)::bigint) \n" - " WHEN 'd' = any(es.stxkind) THEN '0 bytes' \n" - "END AS \"%s\", \n" - "CASE WHEN es.stxdependencies IS NOT NULL THEN \n" - " pg_catalog.pg_size_pretty(pg_catalog.length(es.stxdependencies)::bigint) \n" - " WHEN 'f' = any(es.stxkind) THEN '0 bytes' \n" - "END AS \"%s\"", - gettext_noop("Ndistinct_size"), - gettext_noop("Dependencies_size")); - } - else - { - appendPQExpBuffer(&buf, - ",\nCASE WHEN esd.stxdndistinct IS NOT NULL THEN \n" - " pg_catalog.pg_size_pretty(pg_catalog.length(esd.stxdndistinct)::bigint) \n" - " WHEN 'd' = any(es.stxkind) THEN '0 bytes' \n" - "END AS \"%s\", \n" - "CASE WHEN esd.stxddependencies IS NOT NULL THEN \n" - " pg_catalog.pg_size_pretty(pg_catalog.length(esd.stxddependencies)::bigint) \n" - " WHEN 'f' = any(es.stxkind) THEN '0 bytes' \n" - "END AS \"%s\", \n" - "CASE WHEN esd.stxdmcv IS NOT NULL THEN \n" - " pg_catalog.pg_size_pretty(pg_catalog.length(esd.stxdmcv)::bigint) \n" - " WHEN 'm' = any(es.stxkind) THEN '0 bytes' \n" - "END AS \"%s\"", - gettext_noop("Ndistinct_size"), - gettext_noop("Dependencies_size"), - gettext_noop("MCV_size")); - } - } - - if (pset.sversion < 120000) - { - appendPQExpBufferStr(&buf, - " \nFROM pg_catalog.pg_statistic_ext es \n" - "INNER JOIN pg_catalog.pg_class c \n" - "ON es.stxrelid = c.oid \n"); - } - else - { - appendPQExpBufferStr(&buf, - " \nFROM pg_catalog.pg_statistic_ext es \n" - "LEFT JOIN pg_catalog.pg_statistic_ext_data esd \n" - "ON es.oid = esd.stxoid \n" - "INNER JOIN pg_catalog.pg_class c \n" - "ON es.stxrelid = c.oid \n"); - } - - processSQLNamePattern(pset.db, &buf, pattern, false, - false, NULL, - "es.stxname", NULL, - NULL); - - appendPQExpBufferStr(&buf, "ORDER BY 1, 2;"); - - res = PSQLexec(buf.data); - termPQExpBuffer(&buf); - if (!res) - return false; - - myopt.nullPrint = NULL; - myopt.title = _("List of extended statistics"); - myopt.translate_header = true; - - printQuery(res, &myopt, pset.queryFout, false, pset.logfile); - - PQclear(res); - return true; -} - /* * \dC * diff --git a/src/bin/psql/describe.h b/src/bin/psql/describe.h index 867e57d851e98..6044e3a08284a 100644 --- a/src/bin/psql/describe.h +++ b/src/bin/psql/describe.h @@ -102,9 +102,6 @@ extern bool listExtensions(const char *pattern); /* \dx+ */ extern bool listExtensionContents(const char *pattern); -/* \dX */ -extern bool listExtendedStats(const char *pattern, bool verbose); - /* \dy */ extern bool listEventTriggers(const char *pattern, bool verbose); diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index e42bc8c54e06a..9ec1c4e810c74 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -267,7 +267,6 @@ slashUsage(unsigned short int pager) fprintf(output, _(" \\du[S+] [PATTERN] list roles\n")); fprintf(output, _(" \\dv[S+] [PATTERN] list views\n")); fprintf(output, _(" \\dx[+] [PATTERN] list extensions\n")); - fprintf(output, _(" \\dX[+] [PATTERN] list extended statistics\n")); fprintf(output, _(" \\dy [PATTERN] list event triggers\n")); fprintf(output, _(" \\l[+] [PATTERN] list databases\n")); fprintf(output, _(" \\sf[+] FUNCNAME show a function's definition\n")); diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 17f726503888d..6abcbea96349a 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -1505,7 +1505,7 @@ psql_completion(const char *text, int start, int end) "\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dL", "\\dm", "\\dn", "\\do", "\\dO", "\\dp", "\\dP", "\\dPi", "\\dPt", "\\drds", "\\dRs", "\\dRp", "\\ds", "\\dS", - "\\dt", "\\dT", "\\dv", "\\du", "\\dx", "\\dX", "\\dy", + "\\dt", "\\dT", "\\dv", "\\du", "\\dx", "\\dy", "\\e", "\\echo", "\\ef", "\\elif", "\\else", "\\encoding", "\\endif", "\\errverbose", "\\ev", "\\f", @@ -3974,8 +3974,6 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL); else if (TailMatchesCS("\\dx*")) COMPLETE_WITH_QUERY(Query_for_list_of_extensions); - else if (TailMatchesCS("\\dX*")) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_statistics, NULL); else if (TailMatchesCS("\\dm*")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL); else if (TailMatchesCS("\\dE*")) diff --git a/src/test/regress/expected/stats_ext.out b/src/test/regress/expected/stats_ext.out index 1531d062957d6..f094731e328ca 100644 --- a/src/test/regress/expected/stats_ext.out +++ b/src/test/regress/expected/stats_ext.out @@ -1727,100 +1727,6 @@ INSERT INTO tststats.priv_test_tbl CREATE STATISTICS tststats.priv_test_stats (mcv) ON a, b FROM tststats.priv_test_tbl; ANALYZE tststats.priv_test_tbl; --- Check printing info about extended statistics by \dX -create table stts_t1 (a int, b int); -create statistics stts_1 (ndistinct) on a, b from stts_t1; -create statistics stts_2 (ndistinct, dependencies) on a, b from stts_t1; -create statistics stts_3 (ndistinct, dependencies, mcv) on a, b from stts_t1; -create table stts_t2 (a int, b int, c int); -create statistics stts_4 on b, c from stts_t2; -create table stts_t3 (col1 int, col2 int, col3 int); -create statistics stts_hoge on col1, col2, col3 from stts_t3; -create schema stts_s1; -create schema stts_s2; -create statistics stts_s1.stts_foo on col1, col2 from stts_t3; -create statistics stts_s2.stts_yama (dependencies, mcv) on col1, col3 from stts_t3; -insert into stts_t1 select i,i from generate_series(1,100) i; -analyze stts_t1; -\dX - List of extended statistics - Schema | Name | Definition | Ndistinct | Dependencies | MCV -----------+------------------------+--------------------------------------+-----------+--------------+----------- - public | func_deps_stat | a, b, c FROM functional_dependencies | | built | - public | mcv_lists_arrays_stats | a, b, c FROM mcv_lists_arrays | | | built - public | mcv_lists_bool_stats | a, b, c FROM mcv_lists_bool | | | built - public | mcv_lists_stats | a, b, d FROM mcv_lists | | | built - public | stts_1 | a, b FROM stts_t1 | built | | - public | stts_2 | a, b FROM stts_t1 | built | built | - public | stts_3 | a, b FROM stts_t1 | built | built | built - public | stts_4 | b, c FROM stts_t2 | requested | requested | requested - public | stts_hoge | col1, col2, col3 FROM stts_t3 | requested | requested | requested - stts_s1 | stts_foo | col1, col2 FROM stts_t3 | requested | requested | requested - stts_s2 | stts_yama | col1, col3 FROM stts_t3 | | requested | requested - tststats | priv_test_stats | a, b FROM tststats.priv_test_tbl | | | built -(12 rows) - -\dX stts_? - List of extended statistics - Schema | Name | Definition | Ndistinct | Dependencies | MCV ---------+--------+-------------------+-----------+--------------+----------- - public | stts_1 | a, b FROM stts_t1 | built | | - public | stts_2 | a, b FROM stts_t1 | built | built | - public | stts_3 | a, b FROM stts_t1 | built | built | built - public | stts_4 | b, c FROM stts_t2 | requested | requested | requested -(4 rows) - -\dX *stts_hoge - List of extended statistics - Schema | Name | Definition | Ndistinct | Dependencies | MCV ---------+-----------+-------------------------------+-----------+--------------+----------- - public | stts_hoge | col1, col2, col3 FROM stts_t3 | requested | requested | requested -(1 row) - -\dX+ - List of extended statistics - Schema | Name | Definition | Ndistinct | Dependencies | MCV | Ndistinct_size | Dependencies_size | MCV_size -----------+------------------------+--------------------------------------+-----------+--------------+-----------+----------------+-------------------+------------ - public | func_deps_stat | a, b, c FROM functional_dependencies | | built | | | 106 bytes | - public | mcv_lists_arrays_stats | a, b, c FROM mcv_lists_arrays | | | built | | | 24 kB - public | mcv_lists_bool_stats | a, b, c FROM mcv_lists_bool | | | built | | | 386 bytes - public | mcv_lists_stats | a, b, d FROM mcv_lists | | | built | | | 294 bytes - public | stts_1 | a, b FROM stts_t1 | built | | | 13 bytes | | - public | stts_2 | a, b FROM stts_t1 | built | built | | 13 bytes | 40 bytes | - public | stts_3 | a, b FROM stts_t1 | built | built | built | 13 bytes | 40 bytes | 6126 bytes - public | stts_4 | b, c FROM stts_t2 | requested | requested | requested | 0 bytes | 0 bytes | 0 bytes - public | stts_hoge | col1, col2, col3 FROM stts_t3 | requested | requested | requested | 0 bytes | 0 bytes | 0 bytes - stts_s1 | stts_foo | col1, col2 FROM stts_t3 | requested | requested | requested | 0 bytes | 0 bytes | 0 bytes - stts_s2 | stts_yama | col1, col3 FROM stts_t3 | | requested | requested | | 0 bytes | 0 bytes - tststats | priv_test_stats | a, b FROM tststats.priv_test_tbl | | | built | | | 686 bytes -(12 rows) - -\dX+ stts_? - List of extended statistics - Schema | Name | Definition | Ndistinct | Dependencies | MCV | Ndistinct_size | Dependencies_size | MCV_size ---------+--------+-------------------+-----------+--------------+-----------+----------------+-------------------+------------ - public | stts_1 | a, b FROM stts_t1 | built | | | 13 bytes | | - public | stts_2 | a, b FROM stts_t1 | built | built | | 13 bytes | 40 bytes | - public | stts_3 | a, b FROM stts_t1 | built | built | built | 13 bytes | 40 bytes | 6126 bytes - public | stts_4 | b, c FROM stts_t2 | requested | requested | requested | 0 bytes | 0 bytes | 0 bytes -(4 rows) - -\dX+ *stts_hoge - List of extended statistics - Schema | Name | Definition | Ndistinct | Dependencies | MCV | Ndistinct_size | Dependencies_size | MCV_size ---------+-----------+-------------------------------+-----------+--------------+-----------+----------------+-------------------+---------- - public | stts_hoge | col1, col2, col3 FROM stts_t3 | requested | requested | requested | 0 bytes | 0 bytes | 0 bytes -(1 row) - -\dX+ stts_s2.stts_yama - List of extended statistics - Schema | Name | Definition | Ndistinct | Dependencies | MCV | Ndistinct_size | Dependencies_size | MCV_size ----------+-----------+-------------------------+-----------+--------------+-----------+----------------+-------------------+---------- - stts_s2 | stts_yama | col1, col3 FROM stts_t3 | | requested | requested | | 0 bytes | 0 bytes -(1 row) - -drop table stts_t1, stts_t2, stts_t3; -drop schema stts_s1, stts_s2 cascade; -- User with no access CREATE USER regress_stats_user1; GRANT USAGE ON SCHEMA tststats TO regress_stats_user1; diff --git a/src/test/regress/sql/stats_ext.sql b/src/test/regress/sql/stats_ext.sql index c83840298e8e8..cb08b478a42b6 100644 --- a/src/test/regress/sql/stats_ext.sql +++ b/src/test/regress/sql/stats_ext.sql @@ -914,37 +914,6 @@ CREATE STATISTICS tststats.priv_test_stats (mcv) ON a, b ANALYZE tststats.priv_test_tbl; --- Check printing info about extended statistics by \dX -create table stts_t1 (a int, b int); -create statistics stts_1 (ndistinct) on a, b from stts_t1; -create statistics stts_2 (ndistinct, dependencies) on a, b from stts_t1; -create statistics stts_3 (ndistinct, dependencies, mcv) on a, b from stts_t1; - -create table stts_t2 (a int, b int, c int); -create statistics stts_4 on b, c from stts_t2; - -create table stts_t3 (col1 int, col2 int, col3 int); -create statistics stts_hoge on col1, col2, col3 from stts_t3; - -create schema stts_s1; -create schema stts_s2; -create statistics stts_s1.stts_foo on col1, col2 from stts_t3; -create statistics stts_s2.stts_yama (dependencies, mcv) on col1, col3 from stts_t3; - -insert into stts_t1 select i,i from generate_series(1,100) i; -analyze stts_t1; - -\dX -\dX stts_? -\dX *stts_hoge -\dX+ -\dX+ stts_? -\dX+ *stts_hoge -\dX+ stts_s2.stts_yama - -drop table stts_t1, stts_t2, stts_t3; -drop schema stts_s1, stts_s2 cascade; - -- User with no access CREATE USER regress_stats_user1; GRANT USAGE ON SCHEMA tststats TO regress_stats_user1; From cf621d9d84db1e6edaff8ffa26bad93fdce5f830 Mon Sep 17 00:00:00 2001 From: Magnus Hagander Date: Sun, 17 Jan 2021 15:31:23 +0100 Subject: [PATCH 121/240] Add documentation chapter about checksums Data checksums did not have a longer discussion in the docs, this adds a short section with an overview. Extracted from the larger patch for on-line enabling of checksums, which has many more authors and reviewers. Author: Daniel Gustafsson Reviewed-By: Magnus Hagander, Michael Banck (and others through the big patch) Discussion: https://postgr.es/m/5ff49fa4.1c69fb81.658f3.04ac@mx.google.com --- doc/src/sgml/amcheck.sgml | 4 +-- doc/src/sgml/ref/initdb.sgml | 1 + doc/src/sgml/wal.sgml | 49 +++++++++++++++++++++++++++++++++++- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/doc/src/sgml/amcheck.sgml b/doc/src/sgml/amcheck.sgml index 8dfb01a77be09..a2571d33ae67d 100644 --- a/doc/src/sgml/amcheck.sgml +++ b/doc/src/sgml/amcheck.sgml @@ -393,7 +393,7 @@ SET client_min_messages = DEBUG1; amcheck can be effective at detecting various types of failure modes that data page + linkend="app-initdb-data-checksums">data checksums will fail to catch. These include: @@ -497,7 +497,7 @@ SET client_min_messages = DEBUG1; Structural corruption can happen due to faulty storage hardware, or relation files being overwritten or modified by unrelated software. This kind of corruption can also be detected with - data page + data page checksums. diff --git a/doc/src/sgml/ref/initdb.sgml b/doc/src/sgml/ref/initdb.sgml index 995d78408e574..afd344b4c0641 100644 --- a/doc/src/sgml/ref/initdb.sgml +++ b/doc/src/sgml/ref/initdb.sgml @@ -219,6 +219,7 @@ PostgreSQL documentation failures will be reported in the pg_stat_database view. + See for details. diff --git a/doc/src/sgml/wal.sgml b/doc/src/sgml/wal.sgml index f4bc147b10684..66de1ee2f81cb 100644 --- a/doc/src/sgml/wal.sgml +++ b/doc/src/sgml/wal.sgml @@ -196,7 +196,7 @@ Data pages are not currently checksummed by default, though full page images recorded in WAL records will be protected; see initdb - for details about enabling data page checksums. + for details about enabling data checksums. @@ -230,6 +230,53 @@ + + Data Checksums + + checksums + + + + Data pages are not checksum protected by default, but this can optionally be + enabled for a cluster. When enabled, each data page will be assigned a + checksum that is updated when the page is written and verified every time + the page is read. Only data pages are protected by checksums, internal data + structures and temporary files are not. + + + + Checksums are normally enabled when the cluster is initialized using initdb. + They can also be enabled or disabled at a later time as an offline + operation. Data checksums are enabled or disabled at the full cluster + level, and cannot be specified individually for databases or tables. + + + + The current state of checksums in the cluster can be verified by viewing the + value of the read-only configuration variable by issuing the command SHOW + data_checksums. + + + + When attempting to recover from corrupt data it may be necessary to bypass + the checksum protection in order to recover data. To do this, temporarily + set the configuration parameter . + + + + Off-line Enabling of Checksums + + + The pg_checksums + application can be used to enable or disable data checksums, as well as + verify checksums, on an offline cluster. + + + + + Write-Ahead Logging (<acronym>WAL</acronym>) From 0c7d3bb99f72d66ec6ac63aee4c5fe6d683eee86 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 17 Jan 2021 12:53:48 -0500 Subject: [PATCH 122/240] Add missing array-enlargement logic to test_regex.c. The stanza to report a "partial" match could overrun the initially allocated output array, so it needs its own copy of the array-resizing logic that's in the main loop. I overlooked the need for this in ca8217c10. Per report from Alexander Lakhin. Discussion: https://postgr.es/m/3206aace-50db-e02a-bbea-76d5cdaa2cb6@gmail.com --- src/test/modules/test_regex/test_regex.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/test/modules/test_regex/test_regex.c b/src/test/modules/test_regex/test_regex.c index ad3c6d3b1a6c5..095751cf04ee3 100644 --- a/src/test/modules/test_regex/test_regex.c +++ b/src/test/modules/test_regex/test_regex.c @@ -555,6 +555,18 @@ setup_test_matches(text *orig_str, */ if (matchctx->nmatches == 0 && re_flags->partial && re_flags->indices) { + /* enlarge output space if needed */ + while (array_idx + matchctx->npatterns * 2 + 1 > array_len) + { + array_len += array_len + 1; /* 2^n-1 => 2^(n+1)-1 */ + if (array_len > MaxAllocSize / sizeof(int)) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("too many regular expression matches"))); + matchctx->match_locs = (int *) repalloc(matchctx->match_locs, + sizeof(int) * array_len); + } + matchctx->match_locs[array_idx++] = matchctx->details.rm_extend.rm_so; matchctx->match_locs[array_idx++] = matchctx->details.rm_extend.rm_eo; /* we don't have pmatch data, so emit -1 */ @@ -566,6 +578,8 @@ setup_test_matches(text *orig_str, matchctx->nmatches++; } + Assert(array_idx <= array_len); + if (eml > 1) { int64 maxsiz = eml * (int64) maxlen; From 7db0cd2145f2bce84cac92402e205e4d2b045bf2 Mon Sep 17 00:00:00 2001 From: Tomas Vondra Date: Sun, 17 Jan 2021 22:11:39 +0100 Subject: [PATCH 123/240] Set PD_ALL_VISIBLE and visibility map bits in COPY FREEZE Make sure COPY FREEZE marks the pages as PD_ALL_VISIBLE and updates the visibility map. Until now we only marked individual tuples as frozen, but page-level flags were not updated, so the first VACUUM after the COPY FREEZE had to rewrite the whole table. This is a fairly old patch, and multiple people worked on it. The first version was written by Jeff Janes, and then reworked by Pavan Deolasee and Anastasia Lubennikova. Author: Anastasia Lubennikova, Pavan Deolasee, Jeff Janes Reviewed-by: Kuntal Ghosh, Jeff Janes, Tomas Vondra, Masahiko Sawada, Andres Freund, Ibrar Ahmed, Robert Haas, Tatsuro Ishii, Darafei Praliaskouski Discussion: https://postgr.es/m/CABOikdN-ptGv0mZntrK2Q8OtfUuAjqaYMGmkdU1dCKFtUxVLrg@mail.gmail.com Discussion: https://postgr.es/m/CAMkU%3D1w3osJJ2FneELhhNRLxfZitDgp9FPHee08NT2FQFmz_pQ%40mail.gmail.com --- .../pg_visibility/expected/pg_visibility.out | 64 +++++++++++++++ contrib/pg_visibility/sql/pg_visibility.sql | 77 +++++++++++++++++++ src/backend/access/heap/heapam.c | 77 +++++++++++++++++-- src/backend/access/heap/hio.c | 17 ++++ src/include/access/heapam_xlog.h | 3 + 5 files changed, 230 insertions(+), 8 deletions(-) diff --git a/contrib/pg_visibility/expected/pg_visibility.out b/contrib/pg_visibility/expected/pg_visibility.out index ca4b6e186bcaf..0017e3415c84b 100644 --- a/contrib/pg_visibility/expected/pg_visibility.out +++ b/contrib/pg_visibility/expected/pg_visibility.out @@ -179,6 +179,69 @@ select pg_truncate_visibility_map('test_partition'); (1 row) +-- test copy freeze +create table copyfreeze (a int, b char(1500)); +-- load all rows via COPY FREEZE and ensure that all pages are set all-visible +-- and all-frozen. +begin; +truncate copyfreeze; +copy copyfreeze from stdin freeze; +commit; +select * from pg_visibility_map('copyfreeze'); + blkno | all_visible | all_frozen +-------+-------------+------------ + 0 | t | t + 1 | t | t + 2 | t | t +(3 rows) + +select * from pg_check_frozen('copyfreeze'); + t_ctid +-------- +(0 rows) + +-- load half the rows via regular COPY and rest via COPY FREEZE. The pages +-- which are touched by regular COPY must not be set all-visible/all-frozen. On +-- the other hand, pages allocated by COPY FREEZE should be marked +-- all-frozen/all-visible. +begin; +truncate copyfreeze; +copy copyfreeze from stdin; +copy copyfreeze from stdin freeze; +commit; +select * from pg_visibility_map('copyfreeze'); + blkno | all_visible | all_frozen +-------+-------------+------------ + 0 | f | f + 1 | f | f + 2 | t | t +(3 rows) + +select * from pg_check_frozen('copyfreeze'); + t_ctid +-------- +(0 rows) + +-- Try a mix of regular COPY and COPY FREEZE. +begin; +truncate copyfreeze; +copy copyfreeze from stdin freeze; +copy copyfreeze from stdin; +copy copyfreeze from stdin freeze; +commit; +select * from pg_visibility_map('copyfreeze'); + blkno | all_visible | all_frozen +-------+-------------+------------ + 0 | t | t + 1 | f | f + 2 | t | t +(3 rows) + +select * from pg_check_frozen('copyfreeze'); + t_ctid +-------- +(0 rows) + -- cleanup drop table test_partitioned; drop view test_view; @@ -188,3 +251,4 @@ drop server dummy_server; drop foreign data wrapper dummy; drop materialized view matview_visibility_test; drop table regular_table; +drop table copyfreeze; diff --git a/contrib/pg_visibility/sql/pg_visibility.sql b/contrib/pg_visibility/sql/pg_visibility.sql index f79b54480b701..ec1afd490657b 100644 --- a/contrib/pg_visibility/sql/pg_visibility.sql +++ b/contrib/pg_visibility/sql/pg_visibility.sql @@ -94,6 +94,82 @@ select count(*) > 0 from pg_visibility_map_summary('test_partition'); select * from pg_check_frozen('test_partition'); -- hopefully none select pg_truncate_visibility_map('test_partition'); +-- test copy freeze +create table copyfreeze (a int, b char(1500)); + +-- load all rows via COPY FREEZE and ensure that all pages are set all-visible +-- and all-frozen. +begin; +truncate copyfreeze; +copy copyfreeze from stdin freeze; +1 '1' +2 '2' +3 '3' +4 '4' +5 '5' +6 '6' +7 '7' +8 '8' +9 '9' +10 '10' +11 '11' +12 '12' +\. +commit; +select * from pg_visibility_map('copyfreeze'); +select * from pg_check_frozen('copyfreeze'); + +-- load half the rows via regular COPY and rest via COPY FREEZE. The pages +-- which are touched by regular COPY must not be set all-visible/all-frozen. On +-- the other hand, pages allocated by COPY FREEZE should be marked +-- all-frozen/all-visible. +begin; +truncate copyfreeze; +copy copyfreeze from stdin; +1 '1' +2 '2' +3 '3' +4 '4' +5 '5' +6 '6' +\. +copy copyfreeze from stdin freeze; +7 '7' +8 '8' +9 '9' +10 '10' +11 '11' +12 '12' +\. +commit; +select * from pg_visibility_map('copyfreeze'); +select * from pg_check_frozen('copyfreeze'); + +-- Try a mix of regular COPY and COPY FREEZE. +begin; +truncate copyfreeze; +copy copyfreeze from stdin freeze; +1 '1' +2 '2' +3 '3' +4 '4' +5 '5' +\. +copy copyfreeze from stdin; +6 '6' +\. +copy copyfreeze from stdin freeze; +7 '7' +8 '8' +9 '9' +10 '10' +11 '11' +12 '12' +\. +commit; +select * from pg_visibility_map('copyfreeze'); +select * from pg_check_frozen('copyfreeze'); + -- cleanup drop table test_partitioned; drop view test_view; @@ -103,3 +179,4 @@ drop server dummy_server; drop foreign data wrapper dummy; drop materialized view matview_visibility_test; drop table regular_table; +drop table copyfreeze; diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 5b9cfb26cf76f..faffbb18658d7 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -2121,6 +2121,7 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples, int ndone; PGAlignedBlock scratch; Page page; + Buffer vmbuffer = InvalidBuffer; bool needwal; Size saveFreeSpace; bool need_tuple_data = RelationIsLogicallyLogged(relation); @@ -2175,8 +2176,9 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples, while (ndone < ntuples) { Buffer buffer; - Buffer vmbuffer = InvalidBuffer; + bool starting_with_empty_page; bool all_visible_cleared = false; + bool all_frozen_set = false; int nthispage; CHECK_FOR_INTERRUPTS(); @@ -2184,12 +2186,20 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples, /* * Find buffer where at least the next tuple will fit. If the page is * all-visible, this will also pin the requisite visibility map page. + * + * Also pin visibility map page if COPY FREEZE inserts tuples into an + * empty page. See all_frozen_set below. */ buffer = RelationGetBufferForTuple(relation, heaptuples[ndone]->t_len, InvalidBuffer, options, bistate, &vmbuffer, NULL); page = BufferGetPage(buffer); + starting_with_empty_page = PageGetMaxOffsetNumber(page) == 0; + + if (starting_with_empty_page && (options & HEAP_INSERT_FROZEN)) + all_frozen_set = true; + /* NO EREPORT(ERROR) from here till changes are logged */ START_CRIT_SECTION(); @@ -2223,7 +2233,14 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples, log_heap_new_cid(relation, heaptup); } - if (PageIsAllVisible(page)) + /* + * If the page is all visible, need to clear that, unless we're only + * going to add further frozen rows to it. + * + * If we're only adding already frozen rows to a previously empty + * page, mark it as all-visible. + */ + if (PageIsAllVisible(page) && !(options & HEAP_INSERT_FROZEN)) { all_visible_cleared = true; PageClearAllVisible(page); @@ -2231,6 +2248,8 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples, BufferGetBlockNumber(buffer), vmbuffer, VISIBILITYMAP_VALID_BITS); } + else if (all_frozen_set) + PageSetAllVisible(page); /* * XXX Should we set PageSetPrunable on this page ? See heap_insert() @@ -2254,8 +2273,7 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples, * If the page was previously empty, we can reinit the page * instead of restoring the whole thing. */ - init = (ItemPointerGetOffsetNumber(&(heaptuples[ndone]->t_self)) == FirstOffsetNumber && - PageGetMaxOffsetNumber(page) == FirstOffsetNumber + nthispage - 1); + init = starting_with_empty_page; /* allocate xl_heap_multi_insert struct from the scratch area */ xlrec = (xl_heap_multi_insert *) scratchptr; @@ -2273,7 +2291,15 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples, /* the rest of the scratch space is used for tuple data */ tupledata = scratchptr; - xlrec->flags = all_visible_cleared ? XLH_INSERT_ALL_VISIBLE_CLEARED : 0; + /* check that the mutually exclusive flags are not both set */ + Assert (!(all_visible_cleared && all_frozen_set)); + + xlrec->flags = 0; + if (all_visible_cleared) + xlrec->flags = XLH_INSERT_ALL_VISIBLE_CLEARED; + if (all_frozen_set) + xlrec->flags = XLH_INSERT_ALL_FROZEN_SET; + xlrec->ntuples = nthispage; /* @@ -2347,13 +2373,40 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples, END_CRIT_SECTION(); - UnlockReleaseBuffer(buffer); - if (vmbuffer != InvalidBuffer) - ReleaseBuffer(vmbuffer); + /* + * If we've frozen everything on the page, update the visibilitymap. + * We're already holding pin on the vmbuffer. + */ + if (all_frozen_set) + { + Assert(PageIsAllVisible(page)); + Assert(visibilitymap_pin_ok(BufferGetBlockNumber(buffer), vmbuffer)); + /* + * It's fine to use InvalidTransactionId here - this is only used + * when HEAP_INSERT_FROZEN is specified, which intentionally + * violates visibility rules. + */ + visibilitymap_set(relation, BufferGetBlockNumber(buffer), buffer, + InvalidXLogRecPtr, vmbuffer, + InvalidTransactionId, + VISIBILITYMAP_ALL_VISIBLE | VISIBILITYMAP_ALL_FROZEN); + } + + UnlockReleaseBuffer(buffer); ndone += nthispage; + + /* + * NB: Only release vmbuffer after inserting all tuples - it's fairly + * likely that we'll insert into subsequent heap pages that are likely + * to use the same vm page. + */ } + /* We're done with inserting all tuples, so release the last vmbuffer. */ + if (vmbuffer != InvalidBuffer) + ReleaseBuffer(vmbuffer); + /* * We're done with the actual inserts. Check for conflicts again, to * ensure that all rw-conflicts in to these inserts are detected. Without @@ -8725,6 +8778,10 @@ heap_xlog_insert(XLogReaderState *record) if (xlrec->flags & XLH_INSERT_ALL_VISIBLE_CLEARED) PageClearAllVisible(page); + /* XLH_INSERT_ALL_FROZEN_SET implies that all tuples are visible */ + if (xlrec->flags & XLH_INSERT_ALL_FROZEN_SET) + PageSetAllVisible(page); + MarkBufferDirty(buffer); } if (BufferIsValid(buffer)) @@ -8775,6 +8832,10 @@ heap_xlog_multi_insert(XLogReaderState *record) XLogRecGetBlockTag(record, 0, &rnode, NULL, &blkno); + /* check that the mutually exclusive flags are not both set */ + Assert (!((xlrec->flags & XLH_INSERT_ALL_VISIBLE_CLEARED) && + (xlrec->flags & XLH_INSERT_ALL_FROZEN_SET))); + /* * The visibility map may need to be fixed even if the heap page is * already up-to-date. diff --git a/src/backend/access/heap/hio.c b/src/backend/access/heap/hio.c index fac3b8e9ff287..2d23b3ef71945 100644 --- a/src/backend/access/heap/hio.c +++ b/src/backend/access/heap/hio.c @@ -433,6 +433,14 @@ RelationGetBufferForTuple(Relation relation, Size len, buffer = ReadBufferBI(relation, targetBlock, RBM_NORMAL, bistate); if (PageIsAllVisible(BufferGetPage(buffer))) visibilitymap_pin(relation, targetBlock, vmbuffer); + + /* + * If the page is empty, pin vmbuffer to set all_frozen bit later. + */ + if ((options & HEAP_INSERT_FROZEN) && + (PageGetMaxOffsetNumber(BufferGetPage(buffer)) == 0)) + visibilitymap_pin(relation, targetBlock, vmbuffer); + LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); } else if (otherBlock == targetBlock) @@ -619,6 +627,15 @@ RelationGetBufferForTuple(Relation relation, Size len, PageInit(page, BufferGetPageSize(buffer), 0); MarkBufferDirty(buffer); + /* + * The page is empty, pin vmbuffer to set all_frozen bit. + */ + if (options & HEAP_INSERT_FROZEN) + { + Assert(PageGetMaxOffsetNumber(BufferGetPage(buffer)) == 0); + visibilitymap_pin(relation, BufferGetBlockNumber(buffer), vmbuffer); + } + /* * Release the file-extension lock; it's now OK for someone else to extend * the relation some more. diff --git a/src/include/access/heapam_xlog.h b/src/include/access/heapam_xlog.h index 51586b883d373..178d49710a553 100644 --- a/src/include/access/heapam_xlog.h +++ b/src/include/access/heapam_xlog.h @@ -69,6 +69,9 @@ #define XLH_INSERT_CONTAINS_NEW_TUPLE (1<<3) #define XLH_INSERT_ON_TOAST_RELATION (1<<4) +/* all_frozen_set always implies all_visible_set */ +#define XLH_INSERT_ALL_FROZEN_SET (1<<5) + /* * xl_heap_update flag values, 8 bits are available. */ From 04eb75e783ba49ca2e0e75088d6590b64be8ed4d Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Mon, 18 Jan 2021 00:46:03 +0200 Subject: [PATCH 124/240] pageinspect: Fix relcache leak in gist_page_items(). The gist_page_items() function opened the index relation on first call and closed it on the last call. But there's no guarantee that the function is run to completion, leading to a relcache leak and warning at the end of the transaction. To fix, refactor the function to return all the rows in one call, as a tuplestore. Reported-by: Tom Lane Discussion: https://www.postgresql.org/message-id/234863.1610916631%40sss.pgh.pa.us --- contrib/pageinspect/gistfuncs.c | 170 ++++++++++++++------------------ 1 file changed, 74 insertions(+), 96 deletions(-) diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c index 146b2e91b6011..6e1ea04b346ad 100644 --- a/contrib/pageinspect/gistfuncs.c +++ b/contrib/pageinspect/gistfuncs.c @@ -92,65 +92,56 @@ gist_page_opaque_info(PG_FUNCTION_ARGS) return HeapTupleGetDatum(resultTuple); } -typedef struct gist_page_items_state -{ - Page page; - TupleDesc tupd; - OffsetNumber offset; - Relation rel; -} gist_page_items_state; - Datum gist_page_items_bytea(PG_FUNCTION_ARGS) { bytea *raw_page = PG_GETARG_BYTEA_P(0); - FuncCallContext *fctx; - gist_page_items_state *inter_call_data; + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + bool randomAccess; + TupleDesc tupdesc; + Tuplestorestate *tupstore; + MemoryContext oldcontext; + Page page; + OffsetNumber offset; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to use raw page functions"))); - if (SRF_IS_FIRSTCALL()) - { - TupleDesc tupdesc; - MemoryContext mctx; - Page page; - - fctx = SRF_FIRSTCALL_INIT(); - mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx); - - page = get_page_from_raw(raw_page); - - inter_call_data = palloc(sizeof(gist_page_items_state)); + /* check to see if caller supports us returning a tuplestore */ + if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("set-valued function called in context that cannot accept a set"))); + if (!(rsinfo->allowedModes & SFRM_Materialize)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("materialize mode required, but it is not allowed in this context"))); - /* Build a tuple descriptor for our result type */ - if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) - elog(ERROR, "return type must be a row type"); + /* The tupdesc and tuplestore must be created in ecxt_per_query_memory */ + oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory); - if (GistPageIsDeleted(page)) - elog(NOTICE, "page is deleted"); + if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + elog(ERROR, "return type must be a row type"); - inter_call_data->page = page; - inter_call_data->tupd = tupdesc; - inter_call_data->offset = FirstOffsetNumber; + randomAccess = (rsinfo->allowedModes & SFRM_Materialize_Random) != 0; + tupstore = tuplestore_begin_heap(randomAccess, false, work_mem); + rsinfo->returnMode = SFRM_Materialize; + rsinfo->setResult = tupstore; + rsinfo->setDesc = tupdesc; - fctx->max_calls = PageGetMaxOffsetNumber(page); - fctx->user_fctx = inter_call_data; + MemoryContextSwitchTo(oldcontext); - MemoryContextSwitchTo(mctx); - } + page = get_page_from_raw(raw_page); - fctx = SRF_PERCALL_SETUP(); - inter_call_data = fctx->user_fctx; + if (GistPageIsDeleted(page)) + elog(NOTICE, "page is deleted"); - if (fctx->call_cntr < fctx->max_calls) + for (offset = FirstOffsetNumber; + offset <= PageGetMaxOffsetNumber(page); + offset++) { - Page page = inter_call_data->page; - OffsetNumber offset = inter_call_data->offset; - HeapTuple resultTuple; - Datum result; Datum values[4]; bool nulls[4]; ItemId id; @@ -177,15 +168,10 @@ gist_page_items_bytea(PG_FUNCTION_ARGS) memcpy(VARDATA(tuple_bytea), itup, tuple_len); values[3] = PointerGetDatum(tuple_bytea); - /* Build and return the result tuple. */ - resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls); - result = HeapTupleGetDatum(resultTuple); - - inter_call_data->offset++; - SRF_RETURN_NEXT(fctx, result); + tuplestore_putvalues(tupstore, tupdesc, values, nulls); } - SRF_RETURN_DONE(fctx); + return (Datum) 0; } Datum @@ -193,58 +179,56 @@ gist_page_items(PG_FUNCTION_ARGS) { bytea *raw_page = PG_GETARG_BYTEA_P(0); Oid indexRelid = PG_GETARG_OID(1); - FuncCallContext *fctx; - gist_page_items_state *inter_call_data; + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + bool randomAccess; + Relation indexRel; + TupleDesc tupdesc; + Tuplestorestate *tupstore; + MemoryContext oldcontext; + Page page; + OffsetNumber offset; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to use raw page functions"))); - if (SRF_IS_FIRSTCALL()) - { - Relation indexRel; - TupleDesc tupdesc; - MemoryContext mctx; - Page page; - - fctx = SRF_FIRSTCALL_INIT(); - mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx); - - page = get_page_from_raw(raw_page); - - inter_call_data = palloc(sizeof(gist_page_items_state)); + /* check to see if caller supports us returning a tuplestore */ + if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("set-valued function called in context that cannot accept a set"))); + if (!(rsinfo->allowedModes & SFRM_Materialize)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("materialize mode required, but it is not allowed in this context"))); - /* Open the relation */ - indexRel = index_open(indexRelid, AccessShareLock); + /* The tupdesc and tuplestore must be created in ecxt_per_query_memory */ + oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory); - /* Build a tuple descriptor for our result type */ - if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) - elog(ERROR, "return type must be a row type"); + if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + elog(ERROR, "return type must be a row type"); - if (GistPageIsDeleted(page)) - elog(NOTICE, "page is deleted"); + randomAccess = (rsinfo->allowedModes & SFRM_Materialize_Random) != 0; + tupstore = tuplestore_begin_heap(randomAccess, false, work_mem); + rsinfo->returnMode = SFRM_Materialize; + rsinfo->setResult = tupstore; + rsinfo->setDesc = tupdesc; - inter_call_data->page = page; - inter_call_data->tupd = tupdesc; - inter_call_data->offset = FirstOffsetNumber; - inter_call_data->rel = indexRel; + MemoryContextSwitchTo(oldcontext); - fctx->max_calls = PageGetMaxOffsetNumber(page); - fctx->user_fctx = inter_call_data; + /* Open the relation */ + indexRel = index_open(indexRelid, AccessShareLock); - MemoryContextSwitchTo(mctx); - } + page = get_page_from_raw(raw_page); - fctx = SRF_PERCALL_SETUP(); - inter_call_data = fctx->user_fctx; + if (GistPageIsDeleted(page)) + elog(NOTICE, "page is deleted"); - if (fctx->call_cntr < fctx->max_calls) + for (offset = FirstOffsetNumber; + offset <= PageGetMaxOffsetNumber(page); + offset++) { - Page page = inter_call_data->page; - OffsetNumber offset = inter_call_data->offset; - HeapTuple resultTuple; - Datum result; Datum values[4]; bool nulls[4]; ItemId id; @@ -260,11 +244,10 @@ gist_page_items(PG_FUNCTION_ARGS) itup = (IndexTuple) PageGetItem(page, id); - index_deform_tuple(itup, RelationGetDescr(inter_call_data->rel), + index_deform_tuple(itup, RelationGetDescr(indexRel), itup_values, itup_isnull); - key_desc = BuildIndexValueDescription(inter_call_data->rel, itup_values, - itup_isnull); + key_desc = BuildIndexValueDescription(indexRel, itup_values, itup_isnull); memset(nulls, 0, sizeof(nulls)); @@ -273,15 +256,10 @@ gist_page_items(PG_FUNCTION_ARGS) values[2] = Int32GetDatum((int) IndexTupleSize(itup)); values[3] = CStringGetTextDatum(key_desc); - /* Build and return the result tuple. */ - resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls); - result = HeapTupleGetDatum(resultTuple); - - inter_call_data->offset++; - SRF_RETURN_NEXT(fctx, result); + tuplestore_putvalues(tupstore, tupdesc, values, nulls); } - relation_close(inter_call_data->rel, AccessShareLock); + relation_close(indexRel, AccessShareLock); - SRF_RETURN_DONE(fctx); + return (Datum) 0; } From a3dc926009be833ea505eebd77ce4b72fe708b18 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Mon, 18 Jan 2021 14:03:10 +0900 Subject: [PATCH 125/240] Refactor option handling of CLUSTER, REINDEX and VACUUM This continues the work done in b5913f6. All the options of those commands are changed to use hex values rather than enums to reduce the risk of compatibility bugs when introducing new options. Each option set is moved into a new structure that can be extended with more non-boolean options (this was already the case of VACUUM). The code of REINDEX is restructured so as manual REINDEX commands go through a single routine from utility.c, like VACUUM, to ease the allocation handling of option parameters when a command needs to go through multiple transactions. This can be used as a base infrastructure for future patches related to those commands, including reindex filtering and tablespace support. Per discussion with people mentioned below, as well as Alvaro Herrera and Peter Eisentraut. Author: Michael Paquier, Justin Pryzby Reviewed-by: Alexey Kondratov, Justin Pryzby Discussion: https://postgr.es/m/X8riynBLwxAD9uKk@paquier.xyz --- src/backend/catalog/index.c | 22 +++-- src/backend/commands/cluster.c | 19 ++-- src/backend/commands/indexcmds.c | 162 ++++++++++++++++++++----------- src/backend/commands/tablecmds.c | 4 +- src/backend/commands/vacuum.c | 10 +- src/backend/tcop/utility.c | 40 +------- src/include/catalog/index.h | 19 ++-- src/include/commands/cluster.h | 13 ++- src/include/commands/defrem.h | 6 +- src/include/commands/vacuum.h | 27 +++--- src/tools/pgindent/typedefs.list | 2 + 11 files changed, 175 insertions(+), 149 deletions(-) diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index cffbc0ac388ed..b8cd35e995d18 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -3594,7 +3594,7 @@ IndexGetRelation(Oid indexId, bool missing_ok) */ void reindex_index(Oid indexId, bool skip_constraint_checks, char persistence, - int options) + ReindexParams *params) { Relation iRel, heapRelation; @@ -3602,7 +3602,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence, IndexInfo *indexInfo; volatile bool skipped_constraint = false; PGRUsage ru0; - bool progress = (options & REINDEXOPT_REPORT_PROGRESS) != 0; + bool progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0); pg_rusage_init(&ru0); @@ -3611,12 +3611,12 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence, * we only need to be sure no schema or data changes are going on. */ heapId = IndexGetRelation(indexId, - (options & REINDEXOPT_MISSING_OK) != 0); + (params->options & REINDEXOPT_MISSING_OK) != 0); /* if relation is missing, leave */ if (!OidIsValid(heapId)) return; - if ((options & REINDEXOPT_MISSING_OK) != 0) + if ((params->options & REINDEXOPT_MISSING_OK) != 0) heapRelation = try_table_open(heapId, ShareLock); else heapRelation = table_open(heapId, ShareLock); @@ -3792,7 +3792,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence, } /* Log what we did */ - if (options & REINDEXOPT_VERBOSE) + if ((params->options & REINDEXOPT_VERBOSE) != 0) ereport(INFO, (errmsg("index \"%s\" was reindexed", get_rel_name(indexId)), @@ -3846,7 +3846,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence, * index rebuild. */ bool -reindex_relation(Oid relid, int flags, int options) +reindex_relation(Oid relid, int flags, ReindexParams *params) { Relation rel; Oid toast_relid; @@ -3861,7 +3861,7 @@ reindex_relation(Oid relid, int flags, int options) * to prevent schema and data changes in it. The lock level used here * should match ReindexTable(). */ - if ((options & REINDEXOPT_MISSING_OK) != 0) + if ((params->options & REINDEXOPT_MISSING_OK) != 0) rel = try_table_open(relid, ShareLock); else rel = table_open(relid, ShareLock); @@ -3935,7 +3935,7 @@ reindex_relation(Oid relid, int flags, int options) } reindex_index(indexOid, !(flags & REINDEX_REL_CHECK_CONSTRAINTS), - persistence, options); + persistence, params); CommandCounterIncrement(); @@ -3965,8 +3965,10 @@ reindex_relation(Oid relid, int flags, int options) * Note that this should fail if the toast relation is missing, so * reset REINDEXOPT_MISSING_OK. */ - result |= reindex_relation(toast_relid, flags, - options & ~(REINDEXOPT_MISSING_OK)); + ReindexParams newparams = *params; + + newparams.options &= ~(REINDEXOPT_MISSING_OK); + result |= reindex_relation(toast_relid, flags, &newparams); } return result; diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index d5eeb493ac453..096a06f7b3b8d 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -103,7 +103,7 @@ void cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel) { ListCell *lc; - int options = 0; + ClusterParams params = {0}; bool verbose = false; /* Parse option list */ @@ -121,7 +121,7 @@ cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel) parser_errposition(pstate, opt->location))); } - options = (verbose ? CLUOPT_VERBOSE : 0); + params.options = (verbose ? CLUOPT_VERBOSE : 0); if (stmt->relation != NULL) { @@ -192,7 +192,7 @@ cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel) table_close(rel, NoLock); /* Do the job. */ - cluster_rel(tableOid, indexOid, options); + cluster_rel(tableOid, indexOid, ¶ms); } else { @@ -234,14 +234,16 @@ cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel) foreach(rv, rvs) { RelToCluster *rvtc = (RelToCluster *) lfirst(rv); + ClusterParams cluster_params = params; /* Start a new transaction for each relation. */ StartTransactionCommand(); /* functions in indexes may want a snapshot set */ PushActiveSnapshot(GetTransactionSnapshot()); /* Do the job. */ + cluster_params.options |= CLUOPT_RECHECK; cluster_rel(rvtc->tableOid, rvtc->indexOid, - options | CLUOPT_RECHECK); + &cluster_params); PopActiveSnapshot(); CommitTransactionCommand(); } @@ -272,11 +274,11 @@ cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel) * and error messages should refer to the operation as VACUUM not CLUSTER. */ void -cluster_rel(Oid tableOid, Oid indexOid, int options) +cluster_rel(Oid tableOid, Oid indexOid, ClusterParams *params) { Relation OldHeap; - bool verbose = ((options & CLUOPT_VERBOSE) != 0); - bool recheck = ((options & CLUOPT_RECHECK) != 0); + bool verbose = ((params->options & CLUOPT_VERBOSE) != 0); + bool recheck = ((params->options & CLUOPT_RECHECK) != 0); /* Check for user-requested abort. */ CHECK_FOR_INTERRUPTS(); @@ -1355,6 +1357,7 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, ObjectAddress object; Oid mapped_tables[4]; int reindex_flags; + ReindexParams reindex_params = {0}; int i; /* Report that we are now swapping relation files */ @@ -1412,7 +1415,7 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, pgstat_progress_update_param(PROGRESS_CLUSTER_PHASE, PROGRESS_CLUSTER_PHASE_REBUILD_INDEX); - reindex_relation(OIDOldHeap, reindex_flags, 0); + reindex_relation(OIDOldHeap, reindex_flags, &reindex_params); /* Report that we are now doing clean up */ pgstat_progress_update_param(PROGRESS_CLUSTER_PHASE, diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 1b71859020c8f..f9f3ff3b629b3 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -86,12 +86,21 @@ static char *ChooseIndexName(const char *tabname, Oid namespaceId, bool primary, bool isconstraint); static char *ChooseIndexNameAddition(List *colnames); static List *ChooseIndexColumnNames(List *indexElems); +static void ReindexIndex(RangeVar *indexRelation, ReindexParams *params, + bool isTopLevel); static void RangeVarCallbackForReindexIndex(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg); +static Oid ReindexTable(RangeVar *relation, ReindexParams *params, + bool isTopLevel); +static void ReindexMultipleTables(const char *objectName, + ReindexObjectType objectKind, ReindexParams *params); static void reindex_error_callback(void *args); -static void ReindexPartitions(Oid relid, int options, bool isTopLevel); -static void ReindexMultipleInternal(List *relids, int options); -static bool ReindexRelationConcurrently(Oid relationOid, int options); +static void ReindexPartitions(Oid relid, ReindexParams *params, + bool isTopLevel); +static void ReindexMultipleInternal(List *relids, + ReindexParams *params); +static bool ReindexRelationConcurrently(Oid relationOid, + ReindexParams *params); static void update_relispartition(Oid relationId, bool newval); static inline void set_indexsafe_procflags(void); @@ -100,7 +109,7 @@ static inline void set_indexsafe_procflags(void); */ struct ReindexIndexCallbackState { - int options; /* options from statement */ + ReindexParams params; /* options from statement */ Oid locked_table_oid; /* tracks previously locked table */ }; @@ -2452,14 +2461,17 @@ ChooseIndexColumnNames(List *indexElems) } /* - * ReindexParseOptions - * Parse list of REINDEX options, returning a bitmask of ReindexOption. + * ExecReindex + * + * Primary entry point for manual REINDEX commands. This is mainly a + * preparation wrapper for the real operations that will happen in + * each subroutine of REINDEX. */ -int -ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt) +void +ExecReindex(ParseState *pstate, ReindexStmt *stmt, bool isTopLevel) { + ReindexParams params = {0}; ListCell *lc; - int options = 0; bool concurrently = false; bool verbose = false; @@ -2480,19 +2492,51 @@ ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt) parser_errposition(pstate, opt->location))); } - options = + if (concurrently) + PreventInTransactionBlock(isTopLevel, + "REINDEX CONCURRENTLY"); + + params.options = (verbose ? REINDEXOPT_VERBOSE : 0) | (concurrently ? REINDEXOPT_CONCURRENTLY : 0); - return options; + switch (stmt->kind) + { + case REINDEX_OBJECT_INDEX: + ReindexIndex(stmt->relation, ¶ms, isTopLevel); + break; + case REINDEX_OBJECT_TABLE: + ReindexTable(stmt->relation, ¶ms, isTopLevel); + break; + case REINDEX_OBJECT_SCHEMA: + case REINDEX_OBJECT_SYSTEM: + case REINDEX_OBJECT_DATABASE: + + /* + * This cannot run inside a user transaction block; if we were + * inside a transaction, then its commit- and + * start-transaction-command calls would not have the intended + * effect! + */ + PreventInTransactionBlock(isTopLevel, + (stmt->kind == REINDEX_OBJECT_SCHEMA) ? "REINDEX SCHEMA" : + (stmt->kind == REINDEX_OBJECT_SYSTEM) ? "REINDEX SYSTEM" : + "REINDEX DATABASE"); + ReindexMultipleTables(stmt->name, stmt->kind, ¶ms); + break; + default: + elog(ERROR, "unrecognized object type: %d", + (int) stmt->kind); + break; + } } /* * ReindexIndex * Recreate a specific index. */ -void -ReindexIndex(RangeVar *indexRelation, int options, bool isTopLevel) +static void +ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel) { struct ReindexIndexCallbackState state; Oid indOid; @@ -2509,10 +2553,10 @@ ReindexIndex(RangeVar *indexRelation, int options, bool isTopLevel) * upgrade the lock, but that's OK, because other sessions can't hold * locks on our temporary table. */ - state.options = options; + state.params = *params; state.locked_table_oid = InvalidOid; indOid = RangeVarGetRelidExtended(indexRelation, - (options & REINDEXOPT_CONCURRENTLY) != 0 ? + (params->options & REINDEXOPT_CONCURRENTLY) != 0 ? ShareUpdateExclusiveLock : AccessExclusiveLock, 0, RangeVarCallbackForReindexIndex, @@ -2526,13 +2570,17 @@ ReindexIndex(RangeVar *indexRelation, int options, bool isTopLevel) relkind = get_rel_relkind(indOid); if (relkind == RELKIND_PARTITIONED_INDEX) - ReindexPartitions(indOid, options, isTopLevel); - else if ((options & REINDEXOPT_CONCURRENTLY) != 0 && + ReindexPartitions(indOid, params, isTopLevel); + else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 && persistence != RELPERSISTENCE_TEMP) - ReindexRelationConcurrently(indOid, options); + ReindexRelationConcurrently(indOid, params); else - reindex_index(indOid, false, persistence, - options | REINDEXOPT_REPORT_PROGRESS); + { + ReindexParams newparams = *params; + + newparams.options |= REINDEXOPT_REPORT_PROGRESS; + reindex_index(indOid, false, persistence, &newparams); + } } /* @@ -2553,7 +2601,7 @@ RangeVarCallbackForReindexIndex(const RangeVar *relation, * non-concurrent case and table locks used by index_concurrently_*() for * concurrent case. */ - table_lockmode = ((state->options & REINDEXOPT_CONCURRENTLY) != 0) ? + table_lockmode = (state->params.options & REINDEXOPT_CONCURRENTLY) != 0 ? ShareUpdateExclusiveLock : ShareLock; /* @@ -2610,8 +2658,8 @@ RangeVarCallbackForReindexIndex(const RangeVar *relation, * ReindexTable * Recreate all indexes of a table (and of its toast table, if any) */ -Oid -ReindexTable(RangeVar *relation, int options, bool isTopLevel) +static Oid +ReindexTable(RangeVar *relation, ReindexParams *params, bool isTopLevel) { Oid heapOid; bool result; @@ -2625,17 +2673,17 @@ ReindexTable(RangeVar *relation, int options, bool isTopLevel) * locks on our temporary table. */ heapOid = RangeVarGetRelidExtended(relation, - (options & REINDEXOPT_CONCURRENTLY) != 0 ? + (params->options & REINDEXOPT_CONCURRENTLY) != 0 ? ShareUpdateExclusiveLock : ShareLock, 0, RangeVarCallbackOwnsTable, NULL); if (get_rel_relkind(heapOid) == RELKIND_PARTITIONED_TABLE) - ReindexPartitions(heapOid, options, isTopLevel); - else if ((options & REINDEXOPT_CONCURRENTLY) != 0 && + ReindexPartitions(heapOid, params, isTopLevel); + else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 && get_rel_persistence(heapOid) != RELPERSISTENCE_TEMP) { - result = ReindexRelationConcurrently(heapOid, options); + result = ReindexRelationConcurrently(heapOid, params); if (!result) ereport(NOTICE, @@ -2644,10 +2692,13 @@ ReindexTable(RangeVar *relation, int options, bool isTopLevel) } else { + ReindexParams newparams = *params; + + newparams.options |= REINDEXOPT_REPORT_PROGRESS; result = reindex_relation(heapOid, REINDEX_REL_PROCESS_TOAST | REINDEX_REL_CHECK_CONSTRAINTS, - options | REINDEXOPT_REPORT_PROGRESS); + &newparams); if (!result) ereport(NOTICE, (errmsg("table \"%s\" has no indexes to reindex", @@ -2665,9 +2716,9 @@ ReindexTable(RangeVar *relation, int options, bool isTopLevel) * separate transaction, so we can release the lock on it right away. * That means this must not be called within a user transaction block! */ -void +static void ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind, - int options) + ReindexParams *params) { Oid objectOid; Relation relationRelation; @@ -2686,7 +2737,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind, objectKind == REINDEX_OBJECT_DATABASE); if (objectKind == REINDEX_OBJECT_SYSTEM && - (options & REINDEXOPT_CONCURRENTLY) != 0) + (params->options & REINDEXOPT_CONCURRENTLY) != 0) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot reindex system catalogs concurrently"))); @@ -2794,7 +2845,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind, * Skip system tables, since index_create() would reject indexing them * concurrently (and it would likely fail if we tried). */ - if ((options & REINDEXOPT_CONCURRENTLY) != 0 && + if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 && IsCatalogRelationOid(relid)) { if (!concurrent_warning) @@ -2829,7 +2880,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind, * Process each relation listed in a separate transaction. Note that this * commits and then starts a new transaction immediately. */ - ReindexMultipleInternal(relids, options); + ReindexMultipleInternal(relids, params); MemoryContextDelete(private_context); } @@ -2860,7 +2911,7 @@ reindex_error_callback(void *arg) * by the caller. */ static void -ReindexPartitions(Oid relid, int options, bool isTopLevel) +ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel) { List *partitions = NIL; char relkind = get_rel_relkind(relid); @@ -2937,7 +2988,7 @@ ReindexPartitions(Oid relid, int options, bool isTopLevel) * Process each partition listed in a separate transaction. Note that * this commits and then starts a new transaction immediately. */ - ReindexMultipleInternal(partitions, options); + ReindexMultipleInternal(partitions, params); /* * Clean up working storage --- note we must do this after @@ -2955,7 +3006,7 @@ ReindexPartitions(Oid relid, int options, bool isTopLevel) * and starts a new transaction when finished. */ static void -ReindexMultipleInternal(List *relids, int options) +ReindexMultipleInternal(List *relids, ReindexParams *params) { ListCell *l; @@ -2991,35 +3042,38 @@ ReindexMultipleInternal(List *relids, int options) Assert(relkind != RELKIND_PARTITIONED_INDEX && relkind != RELKIND_PARTITIONED_TABLE); - if ((options & REINDEXOPT_CONCURRENTLY) != 0 && + if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 && relpersistence != RELPERSISTENCE_TEMP) { - (void) ReindexRelationConcurrently(relid, - options | - REINDEXOPT_MISSING_OK); + ReindexParams newparams = *params; + + newparams.options |= REINDEXOPT_MISSING_OK; + (void) ReindexRelationConcurrently(relid, &newparams); /* ReindexRelationConcurrently() does the verbose output */ } else if (relkind == RELKIND_INDEX) { - reindex_index(relid, false, relpersistence, - options | - REINDEXOPT_REPORT_PROGRESS | - REINDEXOPT_MISSING_OK); + ReindexParams newparams = *params; + + newparams.options |= + REINDEXOPT_REPORT_PROGRESS | REINDEXOPT_MISSING_OK; + reindex_index(relid, false, relpersistence, &newparams); PopActiveSnapshot(); /* reindex_index() does the verbose output */ } else { bool result; + ReindexParams newparams = *params; + newparams.options |= + REINDEXOPT_REPORT_PROGRESS | REINDEXOPT_MISSING_OK; result = reindex_relation(relid, REINDEX_REL_PROCESS_TOAST | REINDEX_REL_CHECK_CONSTRAINTS, - options | - REINDEXOPT_REPORT_PROGRESS | - REINDEXOPT_MISSING_OK); + &newparams); - if (result && (options & REINDEXOPT_VERBOSE)) + if (result && (params->options & REINDEXOPT_VERBOSE) != 0) ereport(INFO, (errmsg("table \"%s.%s\" was reindexed", get_namespace_name(get_rel_namespace(relid)), @@ -3059,7 +3113,7 @@ ReindexMultipleInternal(List *relids, int options) * anyway, and a non-concurrent reindex is more efficient. */ static bool -ReindexRelationConcurrently(Oid relationOid, int options) +ReindexRelationConcurrently(Oid relationOid, ReindexParams *params) { typedef struct ReindexIndexInfo { @@ -3099,7 +3153,7 @@ ReindexRelationConcurrently(Oid relationOid, int options) "ReindexConcurrent", ALLOCSET_SMALL_SIZES); - if (options & REINDEXOPT_VERBOSE) + if ((params->options & REINDEXOPT_VERBOSE) != 0) { /* Save data needed by REINDEX VERBOSE in private context */ oldcontext = MemoryContextSwitchTo(private_context); @@ -3144,7 +3198,7 @@ ReindexRelationConcurrently(Oid relationOid, int options) errmsg("cannot reindex system catalogs concurrently"))); /* Open relation to get its indexes */ - if ((options & REINDEXOPT_MISSING_OK) != 0) + if ((params->options & REINDEXOPT_MISSING_OK) != 0) { heapRelation = try_table_open(relationOid, ShareUpdateExclusiveLock); @@ -3251,7 +3305,7 @@ ReindexRelationConcurrently(Oid relationOid, int options) case RELKIND_INDEX: { Oid heapId = IndexGetRelation(relationOid, - (options & REINDEXOPT_MISSING_OK) != 0); + (params->options & REINDEXOPT_MISSING_OK) != 0); Relation heapRelation; ReindexIndexInfo *idx; @@ -3281,7 +3335,7 @@ ReindexRelationConcurrently(Oid relationOid, int options) * to rebuild is not complete yet, and REINDEXOPT_MISSING_OK * should not be used once all the session locks are taken. */ - if ((options & REINDEXOPT_MISSING_OK) != 0) + if ((params->options & REINDEXOPT_MISSING_OK) != 0) { heapRelation = try_table_open(heapId, ShareUpdateExclusiveLock); @@ -3803,7 +3857,7 @@ ReindexRelationConcurrently(Oid relationOid, int options) StartTransactionCommand(); /* Log what we did */ - if (options & REINDEXOPT_VERBOSE) + if ((params->options & REINDEXOPT_VERBOSE) != 0) { if (relkind == RELKIND_INDEX) ereport(INFO, diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index fd55bf4ac7dd9..8687e9a97c5bb 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -1854,6 +1854,7 @@ ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged, { Oid heap_relid; Oid toast_relid; + ReindexParams reindex_params = {0}; /* * This effectively deletes all rows in the table, and may be done @@ -1891,7 +1892,8 @@ ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged, /* * Reconstruct the indexes to match, and we're done. */ - reindex_relation(heap_relid, REINDEX_REL_PROCESS_TOAST, 0); + reindex_relation(heap_relid, REINDEX_REL_PROCESS_TOAST, + &reindex_params); } pgstat_count_truncate(rel); diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index b97d48ee01e3b..462f9a0f8225c 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -530,7 +530,7 @@ vacuum(List *relations, VacuumParams *params, * ANALYZE. */ bool -vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, int options) +vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, bits32 options) { char *relname; @@ -604,7 +604,7 @@ vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, int options) * or locked, a log is emitted if possible. */ Relation -vacuum_open_relation(Oid relid, RangeVar *relation, int options, +vacuum_open_relation(Oid relid, RangeVar *relation, bits32 options, bool verbose, LOCKMODE lmode) { Relation onerel; @@ -1916,17 +1916,17 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params) */ if (params->options & VACOPT_FULL) { - int cluster_options = 0; + ClusterParams cluster_params = {0}; /* close relation before vacuuming, but hold lock until commit */ relation_close(onerel, NoLock); onerel = NULL; if ((params->options & VACOPT_VERBOSE) != 0) - cluster_options |= CLUOPT_VERBOSE; + cluster_params.options |= CLUOPT_VERBOSE; /* VACUUM FULL is now a variant of CLUSTER; see cluster.c */ - cluster_rel(relid, InvalidOid, cluster_options); + cluster_rel(relid, InvalidOid, &cluster_params); } else table_relation_vacuum(onerel, params, vac_strategy); diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 53a511f1da81e..1d81071c35724 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -917,45 +917,7 @@ standard_ProcessUtility(PlannedStmt *pstmt, break; case T_ReindexStmt: - { - ReindexStmt *stmt = (ReindexStmt *) parsetree; - int options; - - options = ReindexParseOptions(pstate, stmt); - if ((options & REINDEXOPT_CONCURRENTLY) != 0) - PreventInTransactionBlock(isTopLevel, - "REINDEX CONCURRENTLY"); - - switch (stmt->kind) - { - case REINDEX_OBJECT_INDEX: - ReindexIndex(stmt->relation, options, isTopLevel); - break; - case REINDEX_OBJECT_TABLE: - ReindexTable(stmt->relation, options, isTopLevel); - break; - case REINDEX_OBJECT_SCHEMA: - case REINDEX_OBJECT_SYSTEM: - case REINDEX_OBJECT_DATABASE: - - /* - * This cannot run inside a user transaction block; if - * we were inside a transaction, then its commit- and - * start-transaction-command calls would not have the - * intended effect! - */ - PreventInTransactionBlock(isTopLevel, - (stmt->kind == REINDEX_OBJECT_SCHEMA) ? "REINDEX SCHEMA" : - (stmt->kind == REINDEX_OBJECT_SYSTEM) ? "REINDEX SYSTEM" : - "REINDEX DATABASE"); - ReindexMultipleTables(stmt->name, stmt->kind, options); - break; - default: - elog(ERROR, "unrecognized object type: %d", - (int) stmt->kind); - break; - } - } + ExecReindex(pstate, (ReindexStmt *) parsetree, isTopLevel); break; /* diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h index 9904a76387a55..266f8950dcc08 100644 --- a/src/include/catalog/index.h +++ b/src/include/catalog/index.h @@ -30,13 +30,16 @@ typedef enum } IndexStateFlagsAction; /* options for REINDEX */ -typedef enum ReindexOption +typedef struct ReindexParams { - REINDEXOPT_VERBOSE = 1 << 0, /* print progress info */ - REINDEXOPT_REPORT_PROGRESS = 1 << 1, /* report pgstat progress */ - REINDEXOPT_MISSING_OK = 1 << 2, /* skip missing relations */ - REINDEXOPT_CONCURRENTLY = 1 << 3 /* concurrent mode */ -} ReindexOption; + bits32 options; /* bitmask of REINDEXOPT_* */ +} ReindexParams; + +/* flag bits for ReindexParams->flags */ +#define REINDEXOPT_VERBOSE 0x01 /* print progress info */ +#define REINDEXOPT_REPORT_PROGRESS 0x02 /* report pgstat progress */ +#define REINDEXOPT_MISSING_OK 0x04 /* skip missing relations */ +#define REINDEXOPT_CONCURRENTLY 0x08 /* concurrent mode */ /* state info for validate_index bulkdelete callback */ typedef struct ValidateIndexState @@ -146,7 +149,7 @@ extern void index_set_state_flags(Oid indexId, IndexStateFlagsAction action); extern Oid IndexGetRelation(Oid indexId, bool missing_ok); extern void reindex_index(Oid indexId, bool skip_constraint_checks, - char relpersistence, int options); + char relpersistence, ReindexParams *params); /* Flag bits for reindex_relation(): */ #define REINDEX_REL_PROCESS_TOAST 0x01 @@ -155,7 +158,7 @@ extern void reindex_index(Oid indexId, bool skip_constraint_checks, #define REINDEX_REL_FORCE_INDEXES_UNLOGGED 0x08 #define REINDEX_REL_FORCE_INDEXES_PERMANENT 0x10 -extern bool reindex_relation(Oid relid, int flags, int options); +extern bool reindex_relation(Oid relid, int flags, ReindexParams *params); extern bool ReindexIsProcessingHeap(Oid heapOid); extern bool ReindexIsProcessingIndex(Oid indexOid); diff --git a/src/include/commands/cluster.h b/src/include/commands/cluster.h index 401a0827aecff..a941f2accdaed 100644 --- a/src/include/commands/cluster.h +++ b/src/include/commands/cluster.h @@ -19,15 +19,18 @@ #include "utils/relcache.h" +/* flag bits for ClusterParams->flags */ +#define CLUOPT_RECHECK 0x01 /* recheck relation state */ +#define CLUOPT_VERBOSE 0x02 /* print progress info */ + /* options for CLUSTER */ -typedef enum ClusterOption +typedef struct ClusterParams { - CLUOPT_RECHECK = 1 << 0, /* recheck relation state */ - CLUOPT_VERBOSE = 1 << 1 /* print progress info */ -} ClusterOption; + bits32 options; /* bitmask of CLUOPT_* */ +} ClusterParams; extern void cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel); -extern void cluster_rel(Oid tableOid, Oid indexOid, int options); +extern void cluster_rel(Oid tableOid, Oid indexOid, ClusterParams *params); extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid, bool recheck, LOCKMODE lockmode); extern void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal); diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index e2d2a77ca49d5..1a79540c94deb 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -34,11 +34,7 @@ extern ObjectAddress DefineIndex(Oid relationId, bool check_not_in_use, bool skip_build, bool quiet); -extern int ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt); -extern void ReindexIndex(RangeVar *indexRelation, int options, bool isTopLevel); -extern Oid ReindexTable(RangeVar *relation, int options, bool isTopLevel); -extern void ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind, - int options); +extern void ExecReindex(ParseState *pstate, ReindexStmt *stmt, bool isTopLevel); extern char *makeObjectName(const char *name1, const char *name2, const char *label); extern char *ChooseRelationName(const char *name1, const char *name2, diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index 857509287d767..191cbbd004939 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -174,17 +174,15 @@ typedef struct VacAttrStats int rowstride; } VacAttrStats; -typedef enum VacuumOption -{ - VACOPT_VACUUM = 1 << 0, /* do VACUUM */ - VACOPT_ANALYZE = 1 << 1, /* do ANALYZE */ - VACOPT_VERBOSE = 1 << 2, /* print progress info */ - VACOPT_FREEZE = 1 << 3, /* FREEZE option */ - VACOPT_FULL = 1 << 4, /* FULL (non-concurrent) vacuum */ - VACOPT_SKIP_LOCKED = 1 << 5, /* skip if cannot get lock */ - VACOPT_SKIPTOAST = 1 << 6, /* don't process the TOAST table, if any */ - VACOPT_DISABLE_PAGE_SKIPPING = 1 << 7 /* don't skip any pages */ -} VacuumOption; +/* flag bits for VacuumParams->options */ +#define VACOPT_VACUUM 0x01 /* do VACUUM */ +#define VACOPT_ANALYZE 0x02 /* do ANALYZE */ +#define VACOPT_VERBOSE 0x04 /* print progress info */ +#define VACOPT_FREEZE 0x08 /* FREEZE option */ +#define VACOPT_FULL 0x10 /* FULL (non-concurrent) vacuum */ +#define VACOPT_SKIP_LOCKED 0x20 /* skip if cannot get lock */ +#define VACOPT_SKIPTOAST 0x40 /* don't process the TOAST table, if any */ +#define VACOPT_DISABLE_PAGE_SKIPPING 0x80 /* don't skip any pages */ /* * A ternary value used by vacuum parameters. @@ -207,7 +205,7 @@ typedef enum VacOptTernaryValue */ typedef struct VacuumParams { - int options; /* bitmask of VacuumOption */ + bits32 options; /* bitmask of VACOPT_* */ int freeze_min_age; /* min freeze age, -1 to use default */ int freeze_table_age; /* age at which to scan whole table */ int multixact_freeze_min_age; /* min multixact freeze age, -1 to @@ -275,9 +273,10 @@ extern void vacuum_set_xid_limits(Relation rel, extern void vac_update_datfrozenxid(void); extern void vacuum_delay_point(void); extern bool vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, - int options); + bits32 options); extern Relation vacuum_open_relation(Oid relid, RangeVar *relation, - int options, bool verbose, LOCKMODE lmode); + bits32 options, bool verbose, + LOCKMODE lmode); /* in commands/analyze.c */ extern void analyze_rel(Oid relid, RangeVar *relation, diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index fb57b8393f177..943142ced8c19 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -347,6 +347,7 @@ ClosePortalStmt ClosePtrType Clump ClusterInfo +ClusterParams ClusterStmt CmdType CoalesceExpr @@ -2063,6 +2064,7 @@ RegisteredBgWorker ReindexErrorInfo ReindexIndexInfo ReindexObjectType +ReindexParams ReindexStmt ReindexType RelFileNode From 708d165ddb92c54077a372acf6417e258dcb5fef Mon Sep 17 00:00:00 2001 From: Fujii Masao Date: Mon, 18 Jan 2021 15:11:08 +0900 Subject: [PATCH 126/240] postgres_fdw: Add function to list cached connections to foreign servers. This commit adds function postgres_fdw_get_connections() to return the foreign server names of all the open connections that postgres_fdw established from the local session to the foreign servers. This function also returns whether each connection is valid or not. This function is useful when checking all the open foreign server connections. If we found some connection to drop, from the result of function, probably we can explicitly close them by the function that upcoming commit will add. This commit bumps the version of postgres_fdw to 1.1 since it adds new function. Author: Bharath Rupireddy, tweaked by Fujii Masao Reviewed-by: Zhijie Hou, Alexey Kondratov, Zhihong Yu, Fujii Masao Discussion: https://postgr.es/m/2d5cb0b3-a6e8-9bbb-953f-879f47128faa@oss.nttdata.com --- contrib/postgres_fdw/Makefile | 2 +- contrib/postgres_fdw/connection.c | 135 ++++++++++++++++++ .../postgres_fdw/expected/postgres_fdw.out | 61 +++++++- .../postgres_fdw/postgres_fdw--1.0--1.1.sql | 10 ++ contrib/postgres_fdw/postgres_fdw.control | 2 +- contrib/postgres_fdw/sql/postgres_fdw.sql | 27 ++++ doc/src/sgml/postgres-fdw.sgml | 32 +++++ 7 files changed, 266 insertions(+), 3 deletions(-) create mode 100644 contrib/postgres_fdw/postgres_fdw--1.0--1.1.sql diff --git a/contrib/postgres_fdw/Makefile b/contrib/postgres_fdw/Makefile index ee8a80a3921e5..c1b0cad453f25 100644 --- a/contrib/postgres_fdw/Makefile +++ b/contrib/postgres_fdw/Makefile @@ -14,7 +14,7 @@ PG_CPPFLAGS = -I$(libpq_srcdir) SHLIB_LINK_INTERNAL = $(libpq) EXTENSION = postgres_fdw -DATA = postgres_fdw--1.0.sql +DATA = postgres_fdw--1.0.sql postgres_fdw--1.0--1.1.sql REGRESS = postgres_fdw diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c index eaedfea9f248e..a1404cb6bb1d4 100644 --- a/contrib/postgres_fdw/connection.c +++ b/contrib/postgres_fdw/connection.c @@ -16,12 +16,14 @@ #include "access/xact.h" #include "catalog/pg_user_mapping.h" #include "commands/defrem.h" +#include "funcapi.h" #include "mb/pg_wchar.h" #include "miscadmin.h" #include "pgstat.h" #include "postgres_fdw.h" #include "storage/fd.h" #include "storage/latch.h" +#include "utils/builtins.h" #include "utils/datetime.h" #include "utils/hsearch.h" #include "utils/inval.h" @@ -74,6 +76,11 @@ static unsigned int prep_stmt_number = 0; /* tracks whether any work is needed in callback functions */ static bool xact_got_connection = false; +/* + * SQL functions + */ +PG_FUNCTION_INFO_V1(postgres_fdw_get_connections); + /* prototypes of private functions */ static void make_new_connection(ConnCacheEntry *entry, UserMapping *user); static PGconn *connect_pg_server(ForeignServer *server, UserMapping *user); @@ -1335,3 +1342,131 @@ exit: ; *result = last_res; return timed_out; } + +/* + * List active foreign server connections. + * + * This function takes no input parameter and returns setof record made of + * following values: + * - server_name - server name of active connection. In case the foreign server + * is dropped but still the connection is active, then the server name will + * be NULL in output. + * - valid - true/false representing whether the connection is valid or not. + * Note that the connections can get invalidated in pgfdw_inval_callback. + * + * No records are returned when there are no cached connections at all. + */ +Datum +postgres_fdw_get_connections(PG_FUNCTION_ARGS) +{ +#define POSTGRES_FDW_GET_CONNECTIONS_COLS 2 + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + TupleDesc tupdesc; + Tuplestorestate *tupstore; + MemoryContext per_query_ctx; + MemoryContext oldcontext; + HASH_SEQ_STATUS scan; + ConnCacheEntry *entry; + + /* check to see if caller supports us returning a tuplestore */ + if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("set-valued function called in context that cannot accept a set"))); + if (!(rsinfo->allowedModes & SFRM_Materialize)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("materialize mode required, but it is not allowed in this context"))); + + /* Build a tuple descriptor for our result type */ + if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + elog(ERROR, "return type must be a row type"); + + /* Build tuplestore to hold the result rows */ + per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; + oldcontext = MemoryContextSwitchTo(per_query_ctx); + + tupstore = tuplestore_begin_heap(true, false, work_mem); + rsinfo->returnMode = SFRM_Materialize; + rsinfo->setResult = tupstore; + rsinfo->setDesc = tupdesc; + + MemoryContextSwitchTo(oldcontext); + + /* If cache doesn't exist, we return no records */ + if (!ConnectionHash) + { + /* clean up and return the tuplestore */ + tuplestore_donestoring(tupstore); + + PG_RETURN_VOID(); + } + + hash_seq_init(&scan, ConnectionHash); + while ((entry = (ConnCacheEntry *) hash_seq_search(&scan))) + { + ForeignServer *server; + Datum values[POSTGRES_FDW_GET_CONNECTIONS_COLS]; + bool nulls[POSTGRES_FDW_GET_CONNECTIONS_COLS]; + + /* We only look for open remote connections */ + if (!entry->conn) + continue; + + server = GetForeignServerExtended(entry->serverid, FSV_MISSING_OK); + + MemSet(values, 0, sizeof(values)); + MemSet(nulls, 0, sizeof(nulls)); + + /* + * The foreign server may have been dropped in current explicit + * transaction. It is not possible to drop the server from another + * session when the connection associated with it is in use in the + * current transaction, if tried so, the drop query in another session + * blocks until the current transaction finishes. + * + * Even though the server is dropped in the current transaction, the + * cache can still have associated active connection entry, say we + * call such connections dangling. Since we can not fetch the server + * name from system catalogs for dangling connections, instead we + * show NULL value for server name in output. + * + * We could have done better by storing the server name in the cache + * entry instead of server oid so that it could be used in the output. + * But the server name in each cache entry requires 64 bytes of + * memory, which is huge, when there are many cached connections and + * the use case i.e. dropping the foreign server within the explicit + * current transaction seems rare. So, we chose to show NULL value for + * server name in output. + * + * Such dangling connections get closed either in next use or at the + * end of current explicit transaction in pgfdw_xact_callback. + */ + if (!server) + { + /* + * If the server has been dropped in the current explicit + * transaction, then this entry would have been invalidated in + * pgfdw_inval_callback at the end of drop sever command. Note + * that this connection would not have been closed in + * pgfdw_inval_callback because it is still being used in the + * current explicit transaction. So, assert that here. + */ + Assert(entry->conn && entry->xact_depth > 0 && entry->invalidated); + + /* Show null, if no server name was found */ + nulls[0] = true; + } + else + values[0] = CStringGetTextDatum(server->servername); + + values[1] = BoolGetDatum(!entry->invalidated); + + tuplestore_putvalues(tupstore, tupdesc, values, nulls); + } + + /* clean up and return the tuplestore */ + tuplestore_donestoring(tupstore); + + PG_RETURN_VOID(); +} diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index c11092f8cc59b..1cad311436498 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -13,12 +13,18 @@ DO $d$ OPTIONS (dbname '$$||current_database()||$$', port '$$||current_setting('port')||$$' )$$; + EXECUTE $$CREATE SERVER loopback3 FOREIGN DATA WRAPPER postgres_fdw + OPTIONS (dbname '$$||current_database()||$$', + port '$$||current_setting('port')||$$' + )$$; + END; $d$; CREATE USER MAPPING FOR public SERVER testserver1 OPTIONS (user 'value', password 'value'); CREATE USER MAPPING FOR CURRENT_USER SERVER loopback; CREATE USER MAPPING FOR CURRENT_USER SERVER loopback2; +CREATE USER MAPPING FOR public SERVER loopback3; -- =================================================================== -- create objects used through FDW loopback server -- =================================================================== @@ -129,6 +135,11 @@ CREATE FOREIGN TABLE ft6 ( c2 int NOT NULL, c3 text ) SERVER loopback2 OPTIONS (schema_name 'S 1', table_name 'T 4'); +CREATE FOREIGN TABLE ft7 ( + c1 int NOT NULL, + c2 int NOT NULL, + c3 text +) SERVER loopback3 OPTIONS (schema_name 'S 1', table_name 'T 4'); -- =================================================================== -- tests for validator -- =================================================================== @@ -199,7 +210,8 @@ ALTER FOREIGN TABLE ft2 ALTER COLUMN c1 OPTIONS (column_name 'C 1'); public | ft4 | loopback | (schema_name 'S 1', table_name 'T 3') | public | ft5 | loopback | (schema_name 'S 1', table_name 'T 4') | public | ft6 | loopback2 | (schema_name 'S 1', table_name 'T 4') | -(5 rows) + public | ft7 | loopback3 | (schema_name 'S 1', table_name 'T 4') | +(6 rows) -- Test that alteration of server options causes reconnection -- Remote's errors might be non-English, so hide them to ensure stable results @@ -9040,6 +9052,13 @@ DROP PROCEDURE terminate_backend_and_wait(text); -- =================================================================== -- This test case is for closing the connection in pgfdw_xact_callback BEGIN; +-- List all the existing cached connections. Only loopback2 should be output. +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; + server_name | valid +-------------+------- + loopback2 | t +(1 row) + -- Connection xact depth becomes 1 i.e. the connection is in midst of the xact. SELECT 1 FROM ft1 LIMIT 1; ?column? @@ -9047,9 +9066,49 @@ SELECT 1 FROM ft1 LIMIT 1; 1 (1 row) +SELECT 1 FROM ft7 LIMIT 1; + ?column? +---------- + 1 +(1 row) + +-- List all the existing cached connections. loopback and loopback3 +-- also should be output as valid connections. +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; + server_name | valid +-------------+------- + loopback | t + loopback2 | t + loopback3 | t +(3 rows) + -- Connection is not closed at the end of the alter statement in -- pgfdw_inval_callback. That's because the connection is in midst of this -- xact, it is just marked as invalid. ALTER SERVER loopback OPTIONS (ADD use_remote_estimate 'off'); +DROP SERVER loopback3 CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to user mapping for public on server loopback3 +drop cascades to foreign table ft7 +-- List all the existing cached connections. loopback and loopback3 +-- should be output as invalid connections. Also the server name for +-- loopback3 should be NULL because the server was dropped. +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; + server_name | valid +-------------+------- + loopback | f + loopback2 | t + | f +(3 rows) + -- The invalid connection gets closed in pgfdw_xact_callback during commit. COMMIT; +-- List all the existing cached connections. loopback and loopback3 +-- should not be output because they should be closed at the end of +-- the above transaction. +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; + server_name | valid +-------------+------- + loopback2 | t +(1 row) + diff --git a/contrib/postgres_fdw/postgres_fdw--1.0--1.1.sql b/contrib/postgres_fdw/postgres_fdw--1.0--1.1.sql new file mode 100644 index 0000000000000..7f85784466c45 --- /dev/null +++ b/contrib/postgres_fdw/postgres_fdw--1.0--1.1.sql @@ -0,0 +1,10 @@ +/* contrib/postgres_fdw/postgres_fdw--1.0--1.1.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION postgres_fdw UPDATE TO '1.1'" to load this file. \quit + +CREATE FUNCTION postgres_fdw_get_connections (OUT server_name text, + OUT valid boolean) +RETURNS SETOF record +AS 'MODULE_PATHNAME' +LANGUAGE C STRICT PARALLEL RESTRICTED; diff --git a/contrib/postgres_fdw/postgres_fdw.control b/contrib/postgres_fdw/postgres_fdw.control index f9ed490752b0a..d489382064cfb 100644 --- a/contrib/postgres_fdw/postgres_fdw.control +++ b/contrib/postgres_fdw/postgres_fdw.control @@ -1,5 +1,5 @@ # postgres_fdw extension comment = 'foreign-data wrapper for remote PostgreSQL servers' -default_version = '1.0' +default_version = '1.1' module_pathname = '$libdir/postgres_fdw' relocatable = true diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql index 25dbc08b988f4..ebf6eb10a6167 100644 --- a/contrib/postgres_fdw/sql/postgres_fdw.sql +++ b/contrib/postgres_fdw/sql/postgres_fdw.sql @@ -15,6 +15,11 @@ DO $d$ OPTIONS (dbname '$$||current_database()||$$', port '$$||current_setting('port')||$$' )$$; + EXECUTE $$CREATE SERVER loopback3 FOREIGN DATA WRAPPER postgres_fdw + OPTIONS (dbname '$$||current_database()||$$', + port '$$||current_setting('port')||$$' + )$$; + END; $d$; @@ -22,6 +27,7 @@ CREATE USER MAPPING FOR public SERVER testserver1 OPTIONS (user 'value', password 'value'); CREATE USER MAPPING FOR CURRENT_USER SERVER loopback; CREATE USER MAPPING FOR CURRENT_USER SERVER loopback2; +CREATE USER MAPPING FOR public SERVER loopback3; -- =================================================================== -- create objects used through FDW loopback server @@ -142,6 +148,12 @@ CREATE FOREIGN TABLE ft6 ( c3 text ) SERVER loopback2 OPTIONS (schema_name 'S 1', table_name 'T 4'); +CREATE FOREIGN TABLE ft7 ( + c1 int NOT NULL, + c2 int NOT NULL, + c3 text +) SERVER loopback3 OPTIONS (schema_name 'S 1', table_name 'T 4'); + -- =================================================================== -- tests for validator -- =================================================================== @@ -2703,11 +2715,26 @@ DROP PROCEDURE terminate_backend_and_wait(text); -- =================================================================== -- This test case is for closing the connection in pgfdw_xact_callback BEGIN; +-- List all the existing cached connections. Only loopback2 should be output. +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; -- Connection xact depth becomes 1 i.e. the connection is in midst of the xact. SELECT 1 FROM ft1 LIMIT 1; +SELECT 1 FROM ft7 LIMIT 1; +-- List all the existing cached connections. loopback and loopback3 +-- also should be output as valid connections. +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; -- Connection is not closed at the end of the alter statement in -- pgfdw_inval_callback. That's because the connection is in midst of this -- xact, it is just marked as invalid. ALTER SERVER loopback OPTIONS (ADD use_remote_estimate 'off'); +DROP SERVER loopback3 CASCADE; +-- List all the existing cached connections. loopback and loopback3 +-- should be output as invalid connections. Also the server name for +-- loopback3 should be NULL because the server was dropped. +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; -- The invalid connection gets closed in pgfdw_xact_callback during commit. COMMIT; +-- List all the existing cached connections. loopback and loopback3 +-- should not be output because they should be closed at the end of +-- the above transaction. +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; diff --git a/doc/src/sgml/postgres-fdw.sgml b/doc/src/sgml/postgres-fdw.sgml index e6fd2143c1056..6a91926da837c 100644 --- a/doc/src/sgml/postgres-fdw.sgml +++ b/doc/src/sgml/postgres-fdw.sgml @@ -479,6 +479,38 @@ OPTIONS (ADD password_required 'false'); + + Functions + + + + postgres_fdw_get_connections(OUT server_name text, OUT valid boolean) returns setof record + + + This function returns the foreign server names of all the open + connections that postgres_fdw established from + the local session to the foreign servers. It also returns whether + each connection is valid or not. false is returned + if the foreign server connection is used in the current local + transaction but its foreign server or user mapping is changed or + dropped, and then such invalid connection will be closed at + the end of that transaction. true is returned + otherwise. If there are no open connections, no record is returned. + Example usage of the function: + +postgres=# SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; + server_name | valid +-------------+------- + loopback1 | t + loopback2 | f + + + + + + + + Connection Management From 15251c0a60be76eedee74ac0e94b433f9acca5af Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Mon, 18 Jan 2021 08:49:10 +0100 Subject: [PATCH 127/240] Pause recovery for insufficient parameter settings When certain parameters are changed on a physical replication primary, this is communicated to standbys using the XLOG_PARAMETER_CHANGE WAL record. The standby then checks whether its own settings are at least as big as the ones on the primary. If not, the standby shuts down with a fatal error. This patch changes this behavior for hot standbys to pause recovery at that point instead. That allows read traffic on the standby to continue while database administrators figure out next steps. When recovery is unpaused, the server shuts down (as before). The idea is to fix the parameters while recovery is paused and then restart when there is a maintenance window. Reviewed-by: Sergei Kornilov Discussion: https://www.postgresql.org/message-id/flat/4ad69a4c-cc9b-0dfe-0352-8b1b0cd36c7b@2ndquadrant.com --- doc/src/sgml/high-availability.sgml | 51 +++++++++++++++++++------ src/backend/access/transam/xlog.c | 59 ++++++++++++++++++++++++++--- 2 files changed, 93 insertions(+), 17 deletions(-) diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml index efc382cb8d247..dc263e4106761 100644 --- a/doc/src/sgml/high-availability.sgml +++ b/doc/src/sgml/high-availability.sgml @@ -2129,18 +2129,14 @@ LOG: database system is ready to accept read only connections - The setting of some parameters on the standby will need reconfiguration - if they have been changed on the primary. For these parameters, - the value on the standby must - be equal to or greater than the value on the primary. - Therefore, if you want to increase these values, you should do so on all - standby servers first, before applying the changes to the primary server. - Conversely, if you want to decrease these values, you should do so on the - primary server first, before applying the changes to all standby servers. - If these parameters - are not set high enough then the standby will refuse to start. - Higher values can then be supplied and the server - restarted to begin recovery again. These parameters are: + The settings of some parameters determine the size of shared memory for + tracking transaction IDs, locks, and prepared transactions. These shared + memory structures must be no smaller on a standby than on the primary in + order to ensure that the standby does not run out of shared memory during + recovery. For example, if the primary had used a prepared transaction but + the standby had not allocated any shared memory for tracking prepared + transactions, then recovery could not continue until the standby's + configuration is changed. The parameters affected are: @@ -2169,6 +2165,37 @@ LOG: database system is ready to accept read only connections + + The easiest way to ensure this does not become a problem is to have these + parameters set on the standbys to values equal to or greater than on the + primary. Therefore, if you want to increase these values, you should do + so on all standby servers first, before applying the changes to the + primary server. Conversely, if you want to decrease these values, you + should do so on the primary server first, before applying the changes to + all standby servers. Keep in mind that when a standby is promoted, it + becomes the new reference for the required parameter settings for the + standbys that follow it. Therefore, to avoid this becoming a problem + during a switchover or failover, it is recommended to keep these settings + the same on all standby servers. + + + + The WAL tracks changes to these parameters on the + primary. If a hot standby processes WAL that indicates that the current + value on the primary is higher than its own value, it will log a warning + and pause recovery, for example: + +WARNING: hot standby is not possible because of insufficient parameter settings +DETAIL: max_connections = 80 is a lower setting than on the primary server, where its value was 100. +LOG: recovery has paused +DETAIL: If recovery is unpaused, the server will shut down. +HINT: You can then restart the server after making the necessary configuration changes. + + At that point, the settings on the standby need to be updated and the + instance restarted before recovery can continue. If the standby is not a + hot standby, then when it encounters the incompatible parameter change, it + will shut down immediately without pausing, since there is then no value + in keeping it up. diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 199d911be76be..470e113b33199 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -6261,12 +6261,61 @@ static void RecoveryRequiresIntParameter(const char *param_name, int currValue, int minValue) { if (currValue < minValue) - ereport(ERROR, + { + if (LocalHotStandbyActive) + { + bool warned_for_promote = false; + + ereport(WARNING, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("hot standby is not possible because of insufficient parameter settings"), + errdetail("%s = %d is a lower setting than on the primary server, where its value was %d.", + param_name, + currValue, + minValue))); + + SetRecoveryPause(true); + + ereport(LOG, + (errmsg("recovery has paused"), + errdetail("If recovery is unpaused, the server will shut down."), + errhint("You can then restart the server after making the necessary configuration changes."))); + + while (RecoveryIsPaused()) + { + HandleStartupProcInterrupts(); + + if (CheckForStandbyTrigger()) + { + if (!warned_for_promote) + ereport(WARNING, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("promotion is not possible because of insufficient parameter settings"), + /* Repeat the detail from above so it's easy to find in the log. */ + errdetail("%s = %d is a lower setting than on the primary server, where its value was %d.", + param_name, + currValue, + minValue), + errhint("Restart the server after making the necessary configuration changes."))); + warned_for_promote = true; + } + + pgstat_report_wait_start(WAIT_EVENT_RECOVERY_PAUSE); + pg_usleep(1000000L); /* 1000 ms */ + pgstat_report_wait_end(); + } + } + + ereport(FATAL, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("hot standby is not possible because %s = %d is a lower setting than on the primary server (its value was %d)", - param_name, - currValue, - minValue))); + errmsg("recovery aborted because of insufficient parameter settings"), + /* Repeat the detail from above so it's easy to find in the log. */ + errdetail("%s = %d is a lower setting than on the primary server, where its value was %d.", + param_name, + currValue, + minValue), + errhint("You can restart the server after making the necessary configuration changes."))); + } } /* From 5d1e5c8b758770186b005a1c3888b05e37af79c5 Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Mon, 18 Jan 2021 14:48:43 +0200 Subject: [PATCH 128/240] Check for BuildIndexValueDescription returning NULL in gist_page_items Per Coverity. BuildIndexValueDescription() cannot actually return NULL in this instance, because it only returns NULL if the user doesn't have the required privileges, and this function can only be used by superuser. But better safe than sorry. --- contrib/pageinspect/gistfuncs.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c index 6e1ea04b346ad..d5da1ea839a57 100644 --- a/contrib/pageinspect/gistfuncs.c +++ b/contrib/pageinspect/gistfuncs.c @@ -247,14 +247,20 @@ gist_page_items(PG_FUNCTION_ARGS) index_deform_tuple(itup, RelationGetDescr(indexRel), itup_values, itup_isnull); - key_desc = BuildIndexValueDescription(indexRel, itup_values, itup_isnull); - memset(nulls, 0, sizeof(nulls)); values[0] = DatumGetInt16(offset); values[1] = ItemPointerGetDatum(&itup->t_tid); values[2] = Int32GetDatum((int) IndexTupleSize(itup)); - values[3] = CStringGetTextDatum(key_desc); + + key_desc = BuildIndexValueDescription(indexRel, itup_values, itup_isnull); + if (key_desc) + values[3] = CStringGetTextDatum(key_desc); + else + { + values[3] = (Datum) 0; + nulls[3] = true; + } tuplestore_putvalues(tupstore, tupdesc, values, nulls); } From b2f87b46690ab8cd3ee7c77226fcf3f5bb713e5b Mon Sep 17 00:00:00 2001 From: Magnus Hagander Date: Mon, 18 Jan 2021 17:51:49 +0100 Subject: [PATCH 129/240] Bump PGSTAT_FILE_FORMAT_ID This was missed in 960869da08 Reported-By: Laurenz Albe Discussion: https://postgr.es/m/4f0aacc5fe1b4bfafa32b36ecd97469fae526a75.camel@cybertec.at --- src/include/pgstat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/pgstat.h b/src/include/pgstat.h index a384f6eb56f05..724068cf87e79 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -692,7 +692,7 @@ typedef union PgStat_Msg * ------------------------------------------------------------ */ -#define PGSTAT_FILE_FORMAT_ID 0x01A5BC9F +#define PGSTAT_FILE_FORMAT_ID 0x01A5BCA0 /* ---------- * PgStat_StatDBEntry The collector's data per database From a3ed4d1efe9f3a1765c504ba4a224f1f393b5b14 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Mon, 18 Jan 2021 12:09:52 -0500 Subject: [PATCH 130/240] Allow for error or refusal while absorbing a ProcSignalBarrier. Previously, the per-barrier-type functions tasked with absorbing them were expected to always succeed and never throw an error. However, that's a bit inconvenient. Further study has revealed that there are realistic cases where it might not be possible to absorb a ProcSignalBarrier without terminating the transaction, or even the whole backend. Similarly, for some barrier types, there might be other reasons where it's not reasonably possible to absorb the barrier at certain points in the code, so provide a way for a per-barrier-type function to reject absorbing the barrier. Unfortunately, there's still no committed code making use of this infrastructure; hopefully, we'll get there. :-( Patch by me, reviewed by Andres Freund and Amul Sul. Discussion: http://postgr.es/m/20200908182005.xya7wetdh3pndzim@alap3.anarazel.de Discussion: http://postgr.es/m/CA+Tgmob56Pk1-5aTJdVPCWFHon7me4M96ENpGe9n_R4JUjjhZA@mail.gmail.com --- src/backend/storage/ipc/procsignal.c | 125 ++++++++++++++++++++++++--- 1 file changed, 113 insertions(+), 12 deletions(-) diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c index 583efaecff88e..c43cdd685b4d9 100644 --- a/src/backend/storage/ipc/procsignal.c +++ b/src/backend/storage/ipc/procsignal.c @@ -18,6 +18,7 @@ #include #include "access/parallel.h" +#include "port/pg_bitutils.h" #include "commands/async.h" #include "miscadmin.h" #include "pgstat.h" @@ -87,12 +88,17 @@ typedef struct #define BARRIER_SHOULD_CHECK(flags, type) \ (((flags) & (((uint32) 1) << (uint32) (type))) != 0) +/* Clear the relevant type bit from the flags. */ +#define BARRIER_CLEAR_BIT(flags, type) \ + ((flags) &= ~(((uint32) 1) << (uint32) (type))) + static ProcSignalHeader *ProcSignal = NULL; static volatile ProcSignalSlot *MyProcSignalSlot = NULL; static bool CheckProcSignal(ProcSignalReason reason); static void CleanupProcSignalState(int status, Datum arg); -static void ProcessBarrierPlaceholder(void); +static void ResetProcSignalBarrierBits(uint32 flags); +static bool ProcessBarrierPlaceholder(void); /* * ProcSignalShmemSize @@ -394,6 +400,12 @@ WaitForProcSignalBarrier(uint64 generation) volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i]; uint64 oldval; + /* + * It's important that we check only pss_barrierGeneration here and + * not pss_barrierCheckMask. Bits in pss_barrierCheckMask get cleared + * before the barrier is actually absorbed, but pss_barrierGeneration + * is updated only afterward. + */ oldval = pg_atomic_read_u64(&slot->pss_barrierGeneration); while (oldval < generation) { @@ -453,7 +465,7 @@ ProcessProcSignalBarrier(void) { uint64 local_gen; uint64 shared_gen; - uint32 flags; + volatile uint32 flags; Assert(MyProcSignalSlot); @@ -482,21 +494,92 @@ ProcessProcSignalBarrier(void) * read of the barrier generation above happens before we atomically * extract the flags, and that any subsequent state changes happen * afterward. + * + * NB: In order to avoid race conditions, we must zero pss_barrierCheckMask + * first and only afterwards try to do barrier processing. If we did it + * in the other order, someone could send us another barrier of some + * type right after we called the barrier-processing function but before + * we cleared the bit. We would have no way of knowing that the bit needs + * to stay set in that case, so the need to call the barrier-processing + * function again would just get forgotten. So instead, we tentatively + * clear all the bits and then put back any for which we don't manage + * to successfully absorb the barrier. */ flags = pg_atomic_exchange_u32(&MyProcSignalSlot->pss_barrierCheckMask, 0); /* - * Process each type of barrier. It's important that nothing we call from - * here throws an error, because pss_barrierCheckMask has already been - * cleared. If we jumped out of here before processing all barrier types, - * then we'd forget about the need to do so later. - * - * NB: It ought to be OK to call the barrier-processing functions - * unconditionally, but it's more efficient to call only the ones that - * might need us to do something based on the flags. + * If there are no flags set, then we can skip doing any real work. + * Otherwise, establish a PG_TRY block, so that we don't lose track of + * which types of barrier processing are needed if an ERROR occurs. */ - if (BARRIER_SHOULD_CHECK(flags, PROCSIGNAL_BARRIER_PLACEHOLDER)) - ProcessBarrierPlaceholder(); + if (flags != 0) + { + bool success = true; + + PG_TRY(); + { + /* + * Process each type of barrier. The barrier-processing functions + * should normally return true, but may return false if the barrier + * can't be absorbed at the current time. This should be rare, + * because it's pretty expensive. Every single + * CHECK_FOR_INTERRUPTS() will return here until we manage to + * absorb the barrier, and that cost will add up in a hurry. + * + * NB: It ought to be OK to call the barrier-processing functions + * unconditionally, but it's more efficient to call only the ones + * that might need us to do something based on the flags. + */ + while (flags != 0) + { + ProcSignalBarrierType type; + bool processed = true; + + type = (ProcSignalBarrierType) pg_rightmost_one_pos32(flags); + switch (type) + { + case PROCSIGNAL_BARRIER_PLACEHOLDER: + processed = ProcessBarrierPlaceholder(); + break; + } + + /* + * To avoid an infinite loop, we must always unset the bit + * in flags. + */ + BARRIER_CLEAR_BIT(flags, type); + + /* + * If we failed to process the barrier, reset the shared bit + * so we try again later, and set a flag so that we don't bump + * our generation. + */ + if (!processed) + { + ResetProcSignalBarrierBits(((uint32) 1) << type); + success = false; + } + } + } + PG_CATCH(); + { + /* + * If an ERROR occurred, we'll need to try again later to handle + * that barrier type and any others that haven't been handled yet + * or weren't successfully absorbed. + */ + ResetProcSignalBarrierBits(flags); + PG_RE_THROW(); + } + PG_END_TRY(); + + /* + * If some barrier types were not successfully absorbed, we will have + * to try again later. + */ + if (!success) + return; + } /* * State changes related to all types of barriers that might have been @@ -508,7 +591,20 @@ ProcessProcSignalBarrier(void) pg_atomic_write_u64(&MyProcSignalSlot->pss_barrierGeneration, shared_gen); } +/* + * If it turns out that we couldn't absorb one or more barrier types, either + * because the barrier-processing functions returned false or due to an error, + * arrange for processing to be retried later. + */ static void +ResetProcSignalBarrierBits(uint32 flags) +{ + pg_atomic_fetch_or_u32(&MyProcSignalSlot->pss_barrierCheckMask, flags); + ProcSignalBarrierPending = true; + InterruptPending = true; +} + +static bool ProcessBarrierPlaceholder(void) { /* @@ -518,7 +614,12 @@ ProcessBarrierPlaceholder(void) * appropriately descriptive. Get rid of this function and instead have * ProcessBarrierSomethingElse. Most likely, that function should live in * the file pertaining to that subsystem, rather than here. + * + * The return value should be 'true' if the barrier was successfully + * absorbed and 'false' if not. Note that returning 'false' can lead to + * very frequent retries, so try hard to make that an uncommon case. */ + return true; } /* From a6cf3df4ebdcbc7857910a67f259705645383e9f Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 18 Jan 2021 15:11:32 -0500 Subject: [PATCH 131/240] Add bytea equivalents of ltrim() and rtrim(). We had bytea btrim() already, but for some reason not the other two. Joel Jacobson Discussion: https://postgr.es/m/d10cd5cd-a901-42f1-b832-763ac6f7ff3a@www.fastmail.com --- doc/src/sgml/func.sgml | 49 ++++++- src/backend/utils/adt/oracle_compat.c | 152 ++++++++++++++++------ src/backend/utils/adt/ruleutils.c | 2 + src/include/catalog/catversion.h | 2 +- src/include/catalog/pg_proc.dat | 8 +- src/test/regress/expected/create_view.out | 10 +- src/test/regress/expected/strings.out | 12 ++ src/test/regress/sql/create_view.sql | 5 +- src/test/regress/sql/strings.sql | 2 + 9 files changed, 194 insertions(+), 48 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index fd0370a1b438b..aa99665e2eb79 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -3948,15 +3948,16 @@ SELECT format('Testing %3$s, %2$s, %s', 'one', 'two', 'three'); trim - trim ( BOTH + trim ( LEADING | TRAILING | BOTH bytesremoved bytea FROM bytes bytea ) bytea Removes the longest string containing only bytes appearing in - bytesremoved from the start - and end of bytes. + bytesremoved from the start, + end, or both ends (BOTH is the default) + of bytes. trim('\x9012'::bytea from '\x1234567890'::bytea) @@ -3966,7 +3967,7 @@ SELECT format('Testing %3$s, %2$s, %s', 'one', 'two', 'three'); - trim ( BOTH FROM + trim ( LEADING | TRAILING | BOTH FROM bytes bytea, bytesremoved bytea ) bytea @@ -4109,6 +4110,26 @@ SELECT format('Testing %3$s, %2$s, %s', 'one', 'two', 'three'); + + + + ltrim + + ltrim ( bytes bytea, + bytesremoved bytea ) + bytea + + + Removes the longest string containing only bytes appearing in + bytesremoved from the start of + bytes. + + + ltrim('\x1234567890'::bytea, '\x9012'::bytea) + \x34567890 + + + @@ -4127,6 +4148,26 @@ SELECT format('Testing %3$s, %2$s, %s', 'one', 'two', 'three'); + + + + rtrim + + rtrim ( bytes bytea, + bytesremoved bytea ) + bytea + + + Removes the longest string containing only bytes appearing in + bytesremoved from the end of + bytes. + + + rtrim('\x1234567890'::bytea, '\x9012'::bytea) + \x12345678 + + + diff --git a/src/backend/utils/adt/oracle_compat.c b/src/backend/utils/adt/oracle_compat.c index 99077a90b92ad..f737aa6fbde73 100644 --- a/src/backend/utils/adt/oracle_compat.c +++ b/src/backend/utils/adt/oracle_compat.c @@ -24,6 +24,8 @@ static text *dotrim(const char *string, int stringlen, const char *set, int setlen, bool doltrim, bool dortrim); +static bytea *dobyteatrim(bytea *string, bytea *set, + bool doltrim, bool dortrim); /******************************************************************** @@ -521,27 +523,12 @@ dotrim(const char *string, int stringlen, return cstring_to_text_with_len(string, stringlen); } -/******************************************************************** - * - * byteatrim - * - * Syntax: - * - * bytea byteatrim(bytea string, bytea set) - * - * Purpose: - * - * Returns string with characters removed from the front and back - * up to the first character not in set. - * - * Cloned from btrim and modified as required. - ********************************************************************/ - -Datum -byteatrim(PG_FUNCTION_ARGS) +/* + * Common implementation for bytea versions of btrim, ltrim, rtrim + */ +bytea * +dobyteatrim(bytea *string, bytea *set, bool doltrim, bool dortrim) { - bytea *string = PG_GETARG_BYTEA_PP(0); - bytea *set = PG_GETARG_BYTEA_PP(1); bytea *ret; char *ptr, *end, @@ -556,7 +543,7 @@ byteatrim(PG_FUNCTION_ARGS) setlen = VARSIZE_ANY_EXHDR(set); if (stringlen <= 0 || setlen <= 0) - PG_RETURN_BYTEA_P(string); + return string; m = stringlen; ptr = VARDATA_ANY(string); @@ -564,39 +551,126 @@ byteatrim(PG_FUNCTION_ARGS) ptr2start = VARDATA_ANY(set); end2 = ptr2start + setlen - 1; - while (m > 0) + if (doltrim) { - ptr2 = ptr2start; - while (ptr2 <= end2) + while (m > 0) { - if (*ptr == *ptr2) + ptr2 = ptr2start; + while (ptr2 <= end2) + { + if (*ptr == *ptr2) + break; + ++ptr2; + } + if (ptr2 > end2) break; - ++ptr2; + ptr++; + m--; } - if (ptr2 > end2) - break; - ptr++; - m--; } - while (m > 0) + if (dortrim) { - ptr2 = ptr2start; - while (ptr2 <= end2) + while (m > 0) { - if (*end == *ptr2) + ptr2 = ptr2start; + while (ptr2 <= end2) + { + if (*end == *ptr2) + break; + ++ptr2; + } + if (ptr2 > end2) break; - ++ptr2; + end--; + m--; } - if (ptr2 > end2) - break; - end--; - m--; } ret = (bytea *) palloc(VARHDRSZ + m); SET_VARSIZE(ret, VARHDRSZ + m); memcpy(VARDATA(ret), ptr, m); + return ret; +} + +/******************************************************************** + * + * byteatrim + * + * Syntax: + * + * bytea byteatrim(bytea string, bytea set) + * + * Purpose: + * + * Returns string with characters removed from the front and back + * up to the first character not in set. + * + * Cloned from btrim and modified as required. + ********************************************************************/ + +Datum +byteatrim(PG_FUNCTION_ARGS) +{ + bytea *string = PG_GETARG_BYTEA_PP(0); + bytea *set = PG_GETARG_BYTEA_PP(1); + bytea *ret; + + ret = dobyteatrim(string, set, true, true); + + PG_RETURN_BYTEA_P(ret); +} + +/******************************************************************** + * + * bytealtrim + * + * Syntax: + * + * bytea bytealtrim(bytea string, bytea set) + * + * Purpose: + * + * Returns string with initial characters removed up to the first + * character not in set. + * + ********************************************************************/ + +Datum +bytealtrim(PG_FUNCTION_ARGS) +{ + bytea *string = PG_GETARG_BYTEA_PP(0); + bytea *set = PG_GETARG_BYTEA_PP(1); + bytea *ret; + + ret = dobyteatrim(string, set, true, false); + + PG_RETURN_BYTEA_P(ret); +} + +/******************************************************************** + * + * byteartrim + * + * Syntax: + * + * bytea byteartrim(bytea string, bytea set) + * + * Purpose: + * + * Returns string with final characters removed after the last + * character not in set. + * + ********************************************************************/ + +Datum +byteartrim(PG_FUNCTION_ARGS) +{ + bytea *string = PG_GETARG_BYTEA_PP(0); + bytea *set = PG_GETARG_BYTEA_PP(1); + bytea *ret; + + ret = dobyteatrim(string, set, false, true); PG_RETURN_BYTEA_P(ret); } diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index db803b4388124..8a1fbda57227e 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -9680,6 +9680,7 @@ get_func_sql_syntax(FuncExpr *expr, deparse_context *context) appendStringInfoChar(buf, ')'); return true; + case F_LTRIM_BYTEA_BYTEA: case F_LTRIM_TEXT: case F_LTRIM_TEXT_TEXT: /* TRIM() */ @@ -9694,6 +9695,7 @@ get_func_sql_syntax(FuncExpr *expr, deparse_context *context) appendStringInfoChar(buf, ')'); return true; + case F_RTRIM_BYTEA_BYTEA: case F_RTRIM_TEXT: case F_RTRIM_TEXT_TEXT: /* TRIM() */ diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 385d108c292b0..ee0049dc9718f 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202101171 +#define CATALOG_VERSION_NO 202101181 #endif diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index dd64c3bd60bd4..b5f52d4e4a3ea 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -5779,9 +5779,15 @@ { oid => '2014', descr => 'position of substring', proname => 'position', prorettype => 'int4', proargtypes => 'bytea bytea', prosrc => 'byteapos' }, -{ oid => '2015', descr => 'trim both ends of string', +{ oid => '2015', descr => 'trim selected bytes from both ends of string', proname => 'btrim', prorettype => 'bytea', proargtypes => 'bytea bytea', prosrc => 'byteatrim' }, +{ oid => '9612', descr => 'trim selected bytes from left end of string', + proname => 'ltrim', prorettype => 'bytea', proargtypes => 'bytea bytea', + prosrc => 'bytealtrim' }, +{ oid => '9613', descr => 'trim selected bytes from right end of string', + proname => 'rtrim', prorettype => 'bytea', proargtypes => 'bytea bytea', + prosrc => 'byteartrim' }, { oid => '2019', descr => 'convert timestamp with time zone to time', proname => 'time', provolatile => 's', prorettype => 'time', diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out index b234d2d4f9fe1..bd5fe604504af 100644 --- a/src/test/regress/expected/create_view.out +++ b/src/test/regress/expected/create_view.out @@ -1735,7 +1735,10 @@ select substring('foo' from 'oo') as ssf, -- historically-permitted abuse trim(' ' from ' foo ') as bt, trim(leading ' ' from ' foo ') as lt, - trim(trailing ' foo ') as rt; + trim(trailing ' foo ') as rt, + trim(E'\\000'::bytea from E'\\000Tom\\000'::bytea) as btb, + trim(leading E'\\000'::bytea from E'\\000Tom\\000'::bytea) as ltb, + trim(trailing E'\\000'::bytea from E'\\000Tom\\000'::bytea) as rtb; select pg_get_viewdef('tt201v', true); pg_get_viewdef ----------------------------------------------------------------------------------------------- @@ -1753,7 +1756,10 @@ select pg_get_viewdef('tt201v', true); "substring"('foo'::text, 'oo'::text) AS ssf, + TRIM(BOTH ' '::text FROM ' foo '::text) AS bt, + TRIM(LEADING ' '::text FROM ' foo '::text) AS lt, + - TRIM(TRAILING FROM ' foo '::text) AS rt; + TRIM(TRAILING FROM ' foo '::text) AS rt, + + TRIM(BOTH '\x00'::bytea FROM '\x00546f6d00'::bytea) AS btb, + + TRIM(LEADING '\x00'::bytea FROM '\x00546f6d00'::bytea) AS ltb, + + TRIM(TRAILING '\x00'::bytea FROM '\x00546f6d00'::bytea) AS rtb; (1 row) -- corner cases with empty join conditions diff --git a/src/test/regress/expected/strings.out b/src/test/regress/expected/strings.out index 595bd2446e525..7c91afa6e4a9a 100644 --- a/src/test/regress/expected/strings.out +++ b/src/test/regress/expected/strings.out @@ -2131,6 +2131,18 @@ SELECT trim(E'\\000'::bytea from E'\\000Tom\\000'::bytea); Tom (1 row) +SELECT trim(leading E'\\000'::bytea from E'\\000Tom\\000'::bytea); + ltrim +--------- + Tom\000 +(1 row) + +SELECT trim(trailing E'\\000'::bytea from E'\\000Tom\\000'::bytea); + rtrim +--------- + \000Tom +(1 row) + SELECT btrim(E'\\000trim\\000'::bytea, E'\\000'::bytea); btrim ------- diff --git a/src/test/regress/sql/create_view.sql b/src/test/regress/sql/create_view.sql index 6d4dd53965528..fbd1313b9ceef 100644 --- a/src/test/regress/sql/create_view.sql +++ b/src/test/regress/sql/create_view.sql @@ -605,7 +605,10 @@ select substring('foo' from 'oo') as ssf, -- historically-permitted abuse trim(' ' from ' foo ') as bt, trim(leading ' ' from ' foo ') as lt, - trim(trailing ' foo ') as rt; + trim(trailing ' foo ') as rt, + trim(E'\\000'::bytea from E'\\000Tom\\000'::bytea) as btb, + trim(leading E'\\000'::bytea from E'\\000Tom\\000'::bytea) as ltb, + trim(trailing E'\\000'::bytea from E'\\000Tom\\000'::bytea) as rtb; select pg_get_viewdef('tt201v', true); -- corner cases with empty join conditions diff --git a/src/test/regress/sql/strings.sql b/src/test/regress/sql/strings.sql index ca465d050f70c..ef4bfb008acec 100644 --- a/src/test/regress/sql/strings.sql +++ b/src/test/regress/sql/strings.sql @@ -722,6 +722,8 @@ SELECT SUBSTRING('string'::bytea FROM -10 FOR 2147483646) AS "string"; SELECT SUBSTRING('string'::bytea FROM -10 FOR -2147483646) AS "error"; SELECT trim(E'\\000'::bytea from E'\\000Tom\\000'::bytea); +SELECT trim(leading E'\\000'::bytea from E'\\000Tom\\000'::bytea); +SELECT trim(trailing E'\\000'::bytea from E'\\000Tom\\000'::bytea); SELECT btrim(E'\\000trim\\000'::bytea, E'\\000'::bytea); SELECT btrim(''::bytea, E'\\000'::bytea); SELECT btrim(E'\\000trim\\000'::bytea, ''::bytea); From 3fd80c728dc36fbd250ca3019c2f5fa2567f1a75 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 18 Jan 2021 15:55:01 -0500 Subject: [PATCH 132/240] Narrow the scope of a local variable. This is better style and more symmetrical with the other if-branch. This likely should have been included in 9de77b545 (which created the opportunity), but it was overlooked. Japin Li Discussion: https://postgr.es/m/MEYP282MB16699FA4A7CD57EB250E871FB6A40@MEYP282MB1669.AUSP282.PROD.OUTLOOK.COM --- src/backend/replication/logical/proto.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/backend/replication/logical/proto.c b/src/backend/replication/logical/proto.c index 62275ebabeaef..f2c85cabb5233 100644 --- a/src/backend/replication/logical/proto.c +++ b/src/backend/replication/logical/proto.c @@ -493,7 +493,6 @@ logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple, bool binar HeapTuple typtup; Form_pg_type typclass; Form_pg_attribute att = TupleDescAttr(desc, i); - char *outputstr; if (att->attisdropped || att->attgenerated) continue; @@ -537,6 +536,8 @@ logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple, bool binar } else { + char *outputstr; + pq_sendbyte(out, LOGICALREP_COLUMN_TEXT); outputstr = OidOutputFunctionCall(typclass->typoutput, values[i]); pq_sendcountedtext(out, outputstr, strlen(outputstr), false); From 60661bbf2dca0c1e744c948c74bccab98933c45b Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 18 Jan 2021 18:32:30 -0500 Subject: [PATCH 133/240] Avoid crash with WHERE CURRENT OF and a custom scan plan. execCurrent.c's search_plan_tree() assumed that ForeignScanStates and CustomScanStates necessarily have a valid ss_currentRelation. This is demonstrably untrue for postgres_fdw's remote join and remote aggregation plans, and non-leaf custom scans might not have an identifiable scan relation either. Avoid crashing by ignoring such nodes when the field is null. This solution will lead to errors like 'cursor "foo" is not a simply updatable scan of table "bar"' in cases where maybe we could have allowed WHERE CURRENT OF to work. That's not an issue for postgres_fdw's usages, since joins or aggregations would render WHERE CURRENT OF invalid anyway. But an otherwise-transparent upper level custom scan node might find this annoying. When and if someone cares to expend work on such a scenario, we could invent a custom-scan-provider callback to determine what's safe. Report and patch by David Geier, commentary by me. It's been like this for awhile, so back-patch to all supported branches. Discussion: https://postgr.es/m/0253344d-9bdd-11c4-7f0d-d88c02cd7991@swarm64.com --- src/backend/executor/execCurrent.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/backend/executor/execCurrent.c b/src/backend/executor/execCurrent.c index 0852bb9cec8c0..ff42cdd808815 100644 --- a/src/backend/executor/execCurrent.c +++ b/src/backend/executor/execCurrent.c @@ -317,7 +317,12 @@ search_plan_tree(PlanState *node, Oid table_oid, switch (nodeTag(node)) { /* - * Relation scan nodes can all be treated alike + * Relation scan nodes can all be treated alike. Note that + * ForeignScan and CustomScan might not have a currentRelation, in + * which case we just ignore them. (We dare not descend to any + * child plan nodes they might have, since we do not know the + * relationship of such a node's current output tuple to the + * children's current outputs.) */ case T_SeqScanState: case T_SampleScanState: @@ -330,7 +335,8 @@ search_plan_tree(PlanState *node, Oid table_oid, { ScanState *sstate = (ScanState *) node; - if (RelationGetRelid(sstate->ss_currentRelation) == table_oid) + if (sstate->ss_currentRelation && + RelationGetRelid(sstate->ss_currentRelation) == table_oid) result = sstate; break; } From 9e7dbe3369cd8f5b0136c53b817471002505f934 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Mon, 18 Jan 2021 18:48:25 -0500 Subject: [PATCH 134/240] doc: adjust alignment of doc file list for "pg_waldump.sgml" Backpatch-through: 10 --- doc/src/sgml/ref/allfiles.sgml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/sgml/ref/allfiles.sgml b/doc/src/sgml/ref/allfiles.sgml index 0f0064150c42e..bee7d28928941 100644 --- a/doc/src/sgml/ref/allfiles.sgml +++ b/doc/src/sgml/ref/allfiles.sgml @@ -215,7 +215,7 @@ Complete list of usable sgml source files in this directory. - + From ed43677e20369040ca4e50c698010c39d5ac0f47 Mon Sep 17 00:00:00 2001 From: Amit Kapila Date: Tue, 19 Jan 2021 08:10:13 +0530 Subject: [PATCH 135/240] pgindent worker.c. This is a leftover from commit 0926e96c49. Changing this separately because this file is being modified for upcoming patch logical replication of 2PC. Author: Peter Smith Discussion: https://postgr.es/m/CAHut+Ps+EgG8KzcmAyAgBUi_vuTps6o9ZA8DG6SdnO0-YuOhPQ@mail.gmail.com --- src/backend/replication/logical/worker.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c index f2b2549a51584..eb7db89cef7d5 100644 --- a/src/backend/replication/logical/worker.c +++ b/src/backend/replication/logical/worker.c @@ -225,7 +225,7 @@ static void maybe_reread_subscription(void); static void apply_dispatch(StringInfo s); static void apply_handle_commit_internal(StringInfo s, - LogicalRepCommitData* commit_data); + LogicalRepCommitData *commit_data); static void apply_handle_insert_internal(ResultRelInfo *relinfo, EState *estate, TupleTableSlot *remoteslot); static void apply_handle_update_internal(ResultRelInfo *relinfo, @@ -752,10 +752,10 @@ apply_handle_stream_start(StringInfo s) /* * Start a transaction on stream start, this transaction will be committed - * on the stream stop unless it is a tablesync worker in which case it will - * be committed after processing all the messages. We need the transaction - * for handling the buffile, used for serializing the streaming data and - * subxact info. + * on the stream stop unless it is a tablesync worker in which case it + * will be committed after processing all the messages. We need the + * transaction for handling the buffile, used for serializing the + * streaming data and subxact info. */ ensure_transaction(); @@ -1060,7 +1060,7 @@ apply_handle_stream_commit(StringInfo s) * Helper function for apply_handle_commit and apply_handle_stream_commit. */ static void -apply_handle_commit_internal(StringInfo s, LogicalRepCommitData* commit_data) +apply_handle_commit_internal(StringInfo s, LogicalRepCommitData *commit_data) { /* The synchronization worker runs in single transaction. */ if (IsTransactionState() && !am_tablesync_worker()) From ee79a548e746da9a99df0cac70a3ddc095f2829a Mon Sep 17 00:00:00 2001 From: Fujii Masao Date: Tue, 19 Jan 2021 00:56:10 +0900 Subject: [PATCH 136/240] doc: Add note about the server name of postgres_fdw_get_connections() returns. Previously the document didn't mention the case where postgres_fdw_get_connections() returns NULL in server_name column. Users might be confused about why NULL was returned. This commit adds the note that, in postgres_fdw_get_connections(), the server name of an invalid connection will be NULL if the server is dropped. Suggested-by: Zhijie Hou Author: Bharath Rupireddy Reviewed-by: Zhijie Hou, Fujii Masao Discussion: https://postgr.es/m/e7ddd14e96444fce88e47a709c196537@G08CNEXMBPEKD05.g08.fujitsu.local --- doc/src/sgml/postgres-fdw.sgml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/src/sgml/postgres-fdw.sgml b/doc/src/sgml/postgres-fdw.sgml index 6a91926da837c..9adc8d12a9dd0 100644 --- a/doc/src/sgml/postgres-fdw.sgml +++ b/doc/src/sgml/postgres-fdw.sgml @@ -493,7 +493,9 @@ OPTIONS (ADD password_required 'false'); each connection is valid or not. false is returned if the foreign server connection is used in the current local transaction but its foreign server or user mapping is changed or - dropped, and then such invalid connection will be closed at + dropped (Note that server name of an invalid connection will be + NULL if the server is dropped), + and then such invalid connection will be closed at the end of that transaction. true is returned otherwise. If there are no open connections, no record is returned. Example usage of the function: From f18aa1b203930ed28cfe42e82d3418ae6277576d Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Tue, 19 Jan 2021 10:28:05 +0100 Subject: [PATCH 137/240] pageinspect: Change block number arguments to bigint Block numbers are 32-bit unsigned integers. Therefore, the smallest SQL integer type that they can fit in is bigint. However, in the pageinspect module, most input and output parameters dealing with block numbers were declared as int. The behavior with block numbers larger than a signed 32-bit integer was therefore dubious. Change these arguments to type bigint and add some more explicit error checking on the block range. (Other contrib modules appear to do this correctly already.) Since we are changing argument types of existing functions, in order to not misbehave if the binary is updated before the extension is updated, we need to create new C symbols for the entry points, similar to how it's done in other extensions as well. Reported-by: Ashutosh Bapat Reviewed-by: Alvaro Herrera Reviewed-by: Michael Paquier Discussion: https://www.postgresql.org/message-id/flat/d8f6bdd536df403b9b33816e9f7e0b9d@G08CNEXMBPEKD05.g08.fujitsu.local --- contrib/pageinspect/Makefile | 2 +- contrib/pageinspect/brinfuncs.c | 13 +++- contrib/pageinspect/btreefuncs.c | 76 ++++++++++++++---- contrib/pageinspect/expected/btree.out | 6 ++ contrib/pageinspect/expected/gin.out | 1 + contrib/pageinspect/expected/hash.out | 4 + .../pageinspect/expected/oldextversions.out | 40 ++++++++++ contrib/pageinspect/expected/page.out | 4 + contrib/pageinspect/hashfuncs.c | 11 ++- contrib/pageinspect/pageinspect--1.8--1.9.sql | 77 +++++++++++++++++++ contrib/pageinspect/pageinspect.h | 9 +++ contrib/pageinspect/rawpage.c | 75 +++++++++++++++++- contrib/pageinspect/sql/btree.sql | 3 + contrib/pageinspect/sql/gin.sql | 2 + contrib/pageinspect/sql/hash.sql | 2 + contrib/pageinspect/sql/oldextversions.sql | 20 +++++ contrib/pageinspect/sql/page.sql | 2 + doc/src/sgml/pageinspect.sgml | 12 +-- 18 files changed, 328 insertions(+), 31 deletions(-) create mode 100644 contrib/pageinspect/expected/oldextversions.out create mode 100644 contrib/pageinspect/sql/oldextversions.sql diff --git a/contrib/pageinspect/Makefile b/contrib/pageinspect/Makefile index 4539f0aef79ad..2d330ddb2857d 100644 --- a/contrib/pageinspect/Makefile +++ b/contrib/pageinspect/Makefile @@ -21,7 +21,7 @@ DATA = pageinspect--1.8--1.9.sql \ pageinspect--1.0--1.1.sql PGFILEDESC = "pageinspect - functions to inspect contents of database pages" -REGRESS = page btree brin gin gist hash checksum +REGRESS = page btree brin gin gist hash checksum oldextversions ifdef USE_PGXS PG_CONFIG = pg_config diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c index e872f65f012e7..0e3c2deb66c02 100644 --- a/contrib/pageinspect/brinfuncs.c +++ b/contrib/pageinspect/brinfuncs.c @@ -252,7 +252,18 @@ brin_page_items(PG_FUNCTION_ARGS) int att = attno - 1; values[0] = UInt16GetDatum(offset); - values[1] = UInt32GetDatum(dtup->bt_blkno); + switch (TupleDescAttr(tupdesc, 1)->atttypid) + { + case INT8OID: + values[1] = Int64GetDatum((int64) dtup->bt_blkno); + break; + case INT4OID: + /* support for old extension version */ + values[1] = UInt32GetDatum(dtup->bt_blkno); + break; + default: + elog(ERROR, "incorrect output types"); + } values[2] = UInt16GetDatum(attno); values[3] = BoolGetDatum(dtup->bt_columns[att].bv_allnulls); values[4] = BoolGetDatum(dtup->bt_columns[att].bv_hasnulls); diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c index 445605db58af5..8bb180bbbe0ef 100644 --- a/contrib/pageinspect/btreefuncs.c +++ b/contrib/pageinspect/btreefuncs.c @@ -41,8 +41,10 @@ #include "utils/varlena.h" PG_FUNCTION_INFO_V1(bt_metap); +PG_FUNCTION_INFO_V1(bt_page_items_1_9); PG_FUNCTION_INFO_V1(bt_page_items); PG_FUNCTION_INFO_V1(bt_page_items_bytea); +PG_FUNCTION_INFO_V1(bt_page_stats_1_9); PG_FUNCTION_INFO_V1(bt_page_stats); #define IS_INDEX(r) ((r)->rd_rel->relkind == RELKIND_INDEX) @@ -160,11 +162,11 @@ GetBTPageStatistics(BlockNumber blkno, Buffer buffer, BTPageStat *stat) * Usage: SELECT * FROM bt_page_stats('t1_pkey', 1); * ----------------------------------------------- */ -Datum -bt_page_stats(PG_FUNCTION_ARGS) +static Datum +bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version) { text *relname = PG_GETARG_TEXT_PP(0); - uint32 blkno = PG_GETARG_UINT32(1); + int64 blkno = (ext_version == PAGEINSPECT_V1_8 ? PG_GETARG_UINT32(1) : PG_GETARG_INT64(1)); Buffer buffer; Relation rel; RangeVar *relrv; @@ -197,8 +199,15 @@ bt_page_stats(PG_FUNCTION_ARGS) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot access temporary tables of other sessions"))); + if (blkno < 0 || blkno > MaxBlockNumber) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid block number"))); + if (blkno == 0) - elog(ERROR, "block 0 is a meta page"); + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("block 0 is a meta page"))); CHECK_RELATION_BLOCK_RANGE(rel, blkno); @@ -219,16 +228,16 @@ bt_page_stats(PG_FUNCTION_ARGS) elog(ERROR, "return type must be a row type"); j = 0; - values[j++] = psprintf("%d", stat.blkno); + values[j++] = psprintf("%u", stat.blkno); values[j++] = psprintf("%c", stat.type); - values[j++] = psprintf("%d", stat.live_items); - values[j++] = psprintf("%d", stat.dead_items); - values[j++] = psprintf("%d", stat.avg_item_size); - values[j++] = psprintf("%d", stat.page_size); - values[j++] = psprintf("%d", stat.free_size); - values[j++] = psprintf("%d", stat.btpo_prev); - values[j++] = psprintf("%d", stat.btpo_next); - values[j++] = psprintf("%d", (stat.type == 'd') ? stat.btpo.xact : stat.btpo.level); + values[j++] = psprintf("%u", stat.live_items); + values[j++] = psprintf("%u", stat.dead_items); + values[j++] = psprintf("%u", stat.avg_item_size); + values[j++] = psprintf("%u", stat.page_size); + values[j++] = psprintf("%u", stat.free_size); + values[j++] = psprintf("%u", stat.btpo_prev); + values[j++] = psprintf("%u", stat.btpo_next); + values[j++] = psprintf("%u", (stat.type == 'd') ? stat.btpo.xact : stat.btpo.level); values[j++] = psprintf("%d", stat.btpo_flags); tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc), @@ -239,6 +248,19 @@ bt_page_stats(PG_FUNCTION_ARGS) PG_RETURN_DATUM(result); } +Datum +bt_page_stats_1_9(PG_FUNCTION_ARGS) +{ + return bt_page_stats_internal(fcinfo, PAGEINSPECT_V1_9); +} + +/* entry point for old extension version */ +Datum +bt_page_stats(PG_FUNCTION_ARGS) +{ + return bt_page_stats_internal(fcinfo, PAGEINSPECT_V1_8); +} + /* * cross-call data structure for SRF @@ -405,11 +427,11 @@ bt_page_print_tuples(struct user_args *uargs) * Usage: SELECT * FROM bt_page_items('t1_pkey', 1); *------------------------------------------------------- */ -Datum -bt_page_items(PG_FUNCTION_ARGS) +static Datum +bt_page_items_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version) { text *relname = PG_GETARG_TEXT_PP(0); - uint32 blkno = PG_GETARG_UINT32(1); + int64 blkno = (ext_version == PAGEINSPECT_V1_8 ? PG_GETARG_UINT32(1) : PG_GETARG_INT64(1)); Datum result; FuncCallContext *fctx; MemoryContext mctx; @@ -447,8 +469,15 @@ bt_page_items(PG_FUNCTION_ARGS) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot access temporary tables of other sessions"))); + if (blkno < 0 || blkno > MaxBlockNumber) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid block number"))); + if (blkno == 0) - elog(ERROR, "block 0 is a meta page"); + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("block 0 is a meta page"))); CHECK_RELATION_BLOCK_RANGE(rel, blkno); @@ -506,6 +535,19 @@ bt_page_items(PG_FUNCTION_ARGS) SRF_RETURN_DONE(fctx); } +Datum +bt_page_items_1_9(PG_FUNCTION_ARGS) +{ + return bt_page_items_internal(fcinfo, PAGEINSPECT_V1_9); +} + +/* entry point for old extension version */ +Datum +bt_page_items(PG_FUNCTION_ARGS) +{ + return bt_page_items_internal(fcinfo, PAGEINSPECT_V1_8); +} + /*------------------------------------------------------- * bt_page_items_bytea() * diff --git a/contrib/pageinspect/expected/btree.out b/contrib/pageinspect/expected/btree.out index 17bf0c5470825..a7632be36a116 100644 --- a/contrib/pageinspect/expected/btree.out +++ b/contrib/pageinspect/expected/btree.out @@ -14,6 +14,8 @@ oldest_xact | 0 last_cleanup_num_tuples | -1 allequalimage | t +SELECT * FROM bt_page_stats('test1_a_idx', -1); +ERROR: invalid block number SELECT * FROM bt_page_stats('test1_a_idx', 0); ERROR: block 0 is a meta page SELECT * FROM bt_page_stats('test1_a_idx', 1); @@ -32,6 +34,8 @@ btpo_flags | 3 SELECT * FROM bt_page_stats('test1_a_idx', 2); ERROR: block number out of range +SELECT * FROM bt_page_items('test1_a_idx', -1); +ERROR: invalid block number SELECT * FROM bt_page_items('test1_a_idx', 0); ERROR: block 0 is a meta page SELECT * FROM bt_page_items('test1_a_idx', 1); @@ -48,6 +52,8 @@ tids | SELECT * FROM bt_page_items('test1_a_idx', 2); ERROR: block number out of range +SELECT * FROM bt_page_items(get_raw_page('test1_a_idx', -1)); +ERROR: invalid block number SELECT * FROM bt_page_items(get_raw_page('test1_a_idx', 0)); ERROR: block is a meta page SELECT * FROM bt_page_items(get_raw_page('test1_a_idx', 1)); diff --git a/contrib/pageinspect/expected/gin.out b/contrib/pageinspect/expected/gin.out index 82f63b23b19d7..ef7570b9723be 100644 --- a/contrib/pageinspect/expected/gin.out +++ b/contrib/pageinspect/expected/gin.out @@ -35,3 +35,4 @@ FROM gin_leafpage_items(get_raw_page('test1_y_idx', -[ RECORD 1 ] ?column? | t +DROP TABLE test1; diff --git a/contrib/pageinspect/expected/hash.out b/contrib/pageinspect/expected/hash.out index 75d7bcfad5f74..bd0628d01369a 100644 --- a/contrib/pageinspect/expected/hash.out +++ b/contrib/pageinspect/expected/hash.out @@ -28,6 +28,8 @@ hash_page_type | bitmap SELECT hash_page_type(get_raw_page('test_hash_a_idx', 6)); ERROR: block number 6 is out of range for relation "test_hash_a_idx" +SELECT * FROM hash_bitmap_info('test_hash_a_idx', -1); +ERROR: invalid block number SELECT * FROM hash_bitmap_info('test_hash_a_idx', 0); ERROR: invalid overflow block number 0 SELECT * FROM hash_bitmap_info('test_hash_a_idx', 1); @@ -40,6 +42,8 @@ SELECT * FROM hash_bitmap_info('test_hash_a_idx', 4); ERROR: invalid overflow block number 4 SELECT * FROM hash_bitmap_info('test_hash_a_idx', 5); ERROR: invalid overflow block number 5 +SELECT * FROM hash_bitmap_info('test_hash_a_idx', 6); +ERROR: block number 6 is out of range for relation "test_hash_a_idx" SELECT magic, version, ntuples, bsize, bmsize, bmshift, maxbucket, highmask, lowmask, ovflpoint, firstfree, nmaps, procid, spares, mapp FROM hash_metapage_info(get_raw_page('test_hash_a_idx', 0)); diff --git a/contrib/pageinspect/expected/oldextversions.out b/contrib/pageinspect/expected/oldextversions.out new file mode 100644 index 0000000000000..04dc7f8640eba --- /dev/null +++ b/contrib/pageinspect/expected/oldextversions.out @@ -0,0 +1,40 @@ +-- test old extension version entry points +DROP EXTENSION pageinspect; +CREATE EXTENSION pageinspect VERSION '1.8'; +CREATE TABLE test1 (a int8, b text); +INSERT INTO test1 VALUES (72057594037927937, 'text'); +CREATE INDEX test1_a_idx ON test1 USING btree (a); +-- from page.sql +SELECT octet_length(get_raw_page('test1', 0)) AS main_0; + main_0 +-------- + 8192 +(1 row) + +SELECT octet_length(get_raw_page('test1', 'main', 0)) AS main_0; + main_0 +-------- + 8192 +(1 row) + +SELECT page_checksum(get_raw_page('test1', 0), 0) IS NOT NULL AS silly_checksum_test; + silly_checksum_test +--------------------- + t +(1 row) + +-- from btree.sql +SELECT * FROM bt_page_stats('test1_a_idx', 1); + blkno | type | live_items | dead_items | avg_item_size | page_size | free_size | btpo_prev | btpo_next | btpo | btpo_flags +-------+------+------------+------------+---------------+-----------+-----------+-----------+-----------+------+------------ + 1 | l | 1 | 0 | 16 | 8192 | 8128 | 0 | 0 | 0 | 3 +(1 row) + +SELECT * FROM bt_page_items('test1_a_idx', 1); + itemoffset | ctid | itemlen | nulls | vars | data | dead | htid | tids +------------+-------+---------+-------+------+-------------------------+------+-------+------ + 1 | (0,1) | 16 | f | f | 01 00 00 00 00 00 00 01 | f | (0,1) | +(1 row) + +DROP TABLE test1; +DROP EXTENSION pageinspect; diff --git a/contrib/pageinspect/expected/page.out b/contrib/pageinspect/expected/page.out index b6aea0124bbc1..4cd0db80183fe 100644 --- a/contrib/pageinspect/expected/page.out +++ b/contrib/pageinspect/expected/page.out @@ -32,6 +32,8 @@ SELECT octet_length(get_raw_page('test1', 'vm', 0)) AS vm_0; SELECT octet_length(get_raw_page('test1', 'vm', 1)) AS vm_1; ERROR: block number 1 is out of range for relation "test1" +SELECT octet_length(get_raw_page('test1', 'main', -1)); +ERROR: invalid block number SELECT octet_length(get_raw_page('xxx', 'main', 0)); ERROR: relation "xxx" does not exist SELECT octet_length(get_raw_page('test1', 'xxx', 0)); @@ -55,6 +57,8 @@ SELECT page_checksum(get_raw_page('test1', 0), 0) IS NOT NULL AS silly_checksum_ t (1 row) +SELECT page_checksum(get_raw_page('test1', 0), -1); +ERROR: invalid block number SELECT tuple_data_split('test1'::regclass, t_data, t_infomask, t_infomask2, t_bits) FROM heap_page_items(get_raw_page('test1', 0)); tuple_data_split diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c index aa11ef396b06c..ff01119474a47 100644 --- a/contrib/pageinspect/hashfuncs.c +++ b/contrib/pageinspect/hashfuncs.c @@ -390,7 +390,7 @@ Datum hash_bitmap_info(PG_FUNCTION_ARGS) { Oid indexRelid = PG_GETARG_OID(0); - uint64 ovflblkno = PG_GETARG_INT64(1); + int64 ovflblkno = PG_GETARG_INT64(1); HashMetaPage metap; Buffer metabuf, mapbuf; @@ -425,11 +425,16 @@ hash_bitmap_info(PG_FUNCTION_ARGS) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot access temporary tables of other sessions"))); + if (ovflblkno < 0 || ovflblkno > MaxBlockNumber) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid block number"))); + if (ovflblkno >= RelationGetNumberOfBlocks(indexRel)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("block number " UINT64_FORMAT " is out of range for relation \"%s\"", - ovflblkno, RelationGetRelationName(indexRel)))); + errmsg("block number %lld is out of range for relation \"%s\"", + (long long int) ovflblkno, RelationGetRelationName(indexRel)))); /* Read the metapage so we can determine which bitmap page to use */ metabuf = _hash_getbuf(indexRel, HASH_METAPAGE, HASH_READ, LH_META_PAGE); diff --git a/contrib/pageinspect/pageinspect--1.8--1.9.sql b/contrib/pageinspect/pageinspect--1.8--1.9.sql index 9dc342fabc269..b4248d791f0d1 100644 --- a/contrib/pageinspect/pageinspect--1.8--1.9.sql +++ b/contrib/pageinspect/pageinspect--1.8--1.9.sql @@ -39,3 +39,80 @@ CREATE FUNCTION gist_page_items(IN page bytea, RETURNS SETOF record AS 'MODULE_PATHNAME', 'gist_page_items' LANGUAGE C STRICT PARALLEL SAFE; + +-- +-- get_raw_page() +-- +DROP FUNCTION get_raw_page(text, int4); +CREATE FUNCTION get_raw_page(text, int8) +RETURNS bytea +AS 'MODULE_PATHNAME', 'get_raw_page_1_9' +LANGUAGE C STRICT PARALLEL SAFE; + +DROP FUNCTION get_raw_page(text, text, int4); +CREATE FUNCTION get_raw_page(text, text, int8) +RETURNS bytea +AS 'MODULE_PATHNAME', 'get_raw_page_fork_1_9' +LANGUAGE C STRICT PARALLEL SAFE; + +-- +-- page_checksum() +-- +DROP FUNCTION page_checksum(IN page bytea, IN blkno int4); +CREATE FUNCTION page_checksum(IN page bytea, IN blkno int8) +RETURNS smallint +AS 'MODULE_PATHNAME', 'page_checksum_1_9' +LANGUAGE C STRICT PARALLEL SAFE; + +-- +-- bt_page_stats() +-- +DROP FUNCTION bt_page_stats(text, int4); +CREATE FUNCTION bt_page_stats(IN relname text, IN blkno int8, + OUT blkno int8, + OUT type "char", + OUT live_items int4, + OUT dead_items int4, + OUT avg_item_size int4, + OUT page_size int4, + OUT free_size int4, + OUT btpo_prev int8, + OUT btpo_next int8, + OUT btpo int4, + OUT btpo_flags int4) +AS 'MODULE_PATHNAME', 'bt_page_stats_1_9' +LANGUAGE C STRICT PARALLEL SAFE; + +-- +-- bt_page_items() +-- +DROP FUNCTION bt_page_items(text, int4); +CREATE FUNCTION bt_page_items(IN relname text, IN blkno int8, + OUT itemoffset smallint, + OUT ctid tid, + OUT itemlen smallint, + OUT nulls bool, + OUT vars bool, + OUT data text, + OUT dead boolean, + OUT htid tid, + OUT tids tid[]) +RETURNS SETOF record +AS 'MODULE_PATHNAME', 'bt_page_items_1_9' +LANGUAGE C STRICT PARALLEL SAFE; + +-- +-- brin_page_items() +-- +DROP FUNCTION brin_page_items(IN page bytea, IN index_oid regclass); +CREATE FUNCTION brin_page_items(IN page bytea, IN index_oid regclass, + OUT itemoffset int, + OUT blknum int8, + OUT attnum int, + OUT allnulls bool, + OUT hasnulls bool, + OUT placeholder bool, + OUT value text) +RETURNS SETOF record +AS 'MODULE_PATHNAME', 'brin_page_items' +LANGUAGE C STRICT PARALLEL SAFE; diff --git a/contrib/pageinspect/pageinspect.h b/contrib/pageinspect/pageinspect.h index c15bc23fe6b4d..3812a3c23397a 100644 --- a/contrib/pageinspect/pageinspect.h +++ b/contrib/pageinspect/pageinspect.h @@ -15,6 +15,15 @@ #include "storage/bufpage.h" +/* + * Extension version number, for supporting older extension versions' objects + */ +enum pageinspect_version +{ + PAGEINSPECT_V1_8, + PAGEINSPECT_V1_9, +}; + /* in rawpage.c */ extern Page get_page_from_raw(bytea *raw_page); diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c index ae1dc41e0551e..9e9ee8a493f87 100644 --- a/contrib/pageinspect/rawpage.c +++ b/contrib/pageinspect/rawpage.c @@ -40,6 +40,28 @@ static bytea *get_raw_page_internal(text *relname, ForkNumber forknum, * * Returns a copy of a page from shared buffers as a bytea */ +PG_FUNCTION_INFO_V1(get_raw_page_1_9); + +Datum +get_raw_page_1_9(PG_FUNCTION_ARGS) +{ + text *relname = PG_GETARG_TEXT_PP(0); + int64 blkno = PG_GETARG_INT64(1); + bytea *raw_page; + + if (blkno < 0 || blkno > MaxBlockNumber) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid block number"))); + + raw_page = get_raw_page_internal(relname, MAIN_FORKNUM, blkno); + + PG_RETURN_BYTEA_P(raw_page); +} + +/* + * entry point for old extension version + */ PG_FUNCTION_INFO_V1(get_raw_page); Datum @@ -69,6 +91,32 @@ get_raw_page(PG_FUNCTION_ARGS) * * Same, for any fork */ +PG_FUNCTION_INFO_V1(get_raw_page_fork_1_9); + +Datum +get_raw_page_fork_1_9(PG_FUNCTION_ARGS) +{ + text *relname = PG_GETARG_TEXT_PP(0); + text *forkname = PG_GETARG_TEXT_PP(1); + int64 blkno = PG_GETARG_INT64(2); + bytea *raw_page; + ForkNumber forknum; + + forknum = forkname_to_number(text_to_cstring(forkname)); + + if (blkno < 0 || blkno > MaxBlockNumber) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid block number"))); + + raw_page = get_raw_page_internal(relname, forknum, blkno); + + PG_RETURN_BYTEA_P(raw_page); +} + +/* + * Entry point for old extension version + */ PG_FUNCTION_INFO_V1(get_raw_page_fork); Datum @@ -292,13 +340,14 @@ page_header(PG_FUNCTION_ARGS) * Compute checksum of a raw page */ +PG_FUNCTION_INFO_V1(page_checksum_1_9); PG_FUNCTION_INFO_V1(page_checksum); -Datum -page_checksum(PG_FUNCTION_ARGS) +static Datum +page_checksum_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version) { bytea *raw_page = PG_GETARG_BYTEA_P(0); - uint32 blkno = PG_GETARG_INT32(1); + int64 blkno = (ext_version == PAGEINSPECT_V1_8 ? PG_GETARG_UINT32(1) : PG_GETARG_INT64(1)); int raw_page_size; PageHeader page; @@ -307,6 +356,11 @@ page_checksum(PG_FUNCTION_ARGS) (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to use raw page functions"))); + if (blkno < 0 || blkno > MaxBlockNumber) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid block number"))); + raw_page_size = VARSIZE(raw_page) - VARHDRSZ; /* @@ -321,3 +375,18 @@ page_checksum(PG_FUNCTION_ARGS) PG_RETURN_INT16(pg_checksum_page((char *) page, blkno)); } + +Datum +page_checksum_1_9(PG_FUNCTION_ARGS) +{ + return page_checksum_internal(fcinfo, PAGEINSPECT_V1_9); +} + +/* + * Entry point for old extension version + */ +Datum +page_checksum(PG_FUNCTION_ARGS) +{ + return page_checksum_internal(fcinfo, PAGEINSPECT_V1_8); +} diff --git a/contrib/pageinspect/sql/btree.sql b/contrib/pageinspect/sql/btree.sql index 8eac64c7b3cb7..963591795973e 100644 --- a/contrib/pageinspect/sql/btree.sql +++ b/contrib/pageinspect/sql/btree.sql @@ -6,14 +6,17 @@ CREATE INDEX test1_a_idx ON test1 USING btree (a); SELECT * FROM bt_metap('test1_a_idx'); +SELECT * FROM bt_page_stats('test1_a_idx', -1); SELECT * FROM bt_page_stats('test1_a_idx', 0); SELECT * FROM bt_page_stats('test1_a_idx', 1); SELECT * FROM bt_page_stats('test1_a_idx', 2); +SELECT * FROM bt_page_items('test1_a_idx', -1); SELECT * FROM bt_page_items('test1_a_idx', 0); SELECT * FROM bt_page_items('test1_a_idx', 1); SELECT * FROM bt_page_items('test1_a_idx', 2); +SELECT * FROM bt_page_items(get_raw_page('test1_a_idx', -1)); SELECT * FROM bt_page_items(get_raw_page('test1_a_idx', 0)); SELECT * FROM bt_page_items(get_raw_page('test1_a_idx', 1)); SELECT * FROM bt_page_items(get_raw_page('test1_a_idx', 2)); diff --git a/contrib/pageinspect/sql/gin.sql b/contrib/pageinspect/sql/gin.sql index d516ed3cbd441..423f5c574999b 100644 --- a/contrib/pageinspect/sql/gin.sql +++ b/contrib/pageinspect/sql/gin.sql @@ -17,3 +17,5 @@ SELECT COUNT(*) > 0 FROM gin_leafpage_items(get_raw_page('test1_y_idx', (pg_relation_size('test1_y_idx') / current_setting('block_size')::bigint)::int - 1)); + +DROP TABLE test1; diff --git a/contrib/pageinspect/sql/hash.sql b/contrib/pageinspect/sql/hash.sql index 87ee549a7b4f5..64f33f1d52fd1 100644 --- a/contrib/pageinspect/sql/hash.sql +++ b/contrib/pageinspect/sql/hash.sql @@ -13,12 +13,14 @@ SELECT hash_page_type(get_raw_page('test_hash_a_idx', 5)); SELECT hash_page_type(get_raw_page('test_hash_a_idx', 6)); +SELECT * FROM hash_bitmap_info('test_hash_a_idx', -1); SELECT * FROM hash_bitmap_info('test_hash_a_idx', 0); SELECT * FROM hash_bitmap_info('test_hash_a_idx', 1); SELECT * FROM hash_bitmap_info('test_hash_a_idx', 2); SELECT * FROM hash_bitmap_info('test_hash_a_idx', 3); SELECT * FROM hash_bitmap_info('test_hash_a_idx', 4); SELECT * FROM hash_bitmap_info('test_hash_a_idx', 5); +SELECT * FROM hash_bitmap_info('test_hash_a_idx', 6); SELECT magic, version, ntuples, bsize, bmsize, bmshift, maxbucket, highmask, diff --git a/contrib/pageinspect/sql/oldextversions.sql b/contrib/pageinspect/sql/oldextversions.sql new file mode 100644 index 0000000000000..78e08f40e8247 --- /dev/null +++ b/contrib/pageinspect/sql/oldextversions.sql @@ -0,0 +1,20 @@ +-- test old extension version entry points + +DROP EXTENSION pageinspect; +CREATE EXTENSION pageinspect VERSION '1.8'; + +CREATE TABLE test1 (a int8, b text); +INSERT INTO test1 VALUES (72057594037927937, 'text'); +CREATE INDEX test1_a_idx ON test1 USING btree (a); + +-- from page.sql +SELECT octet_length(get_raw_page('test1', 0)) AS main_0; +SELECT octet_length(get_raw_page('test1', 'main', 0)) AS main_0; +SELECT page_checksum(get_raw_page('test1', 0), 0) IS NOT NULL AS silly_checksum_test; + +-- from btree.sql +SELECT * FROM bt_page_stats('test1_a_idx', 1); +SELECT * FROM bt_page_items('test1_a_idx', 1); + +DROP TABLE test1; +DROP EXTENSION pageinspect; diff --git a/contrib/pageinspect/sql/page.sql b/contrib/pageinspect/sql/page.sql index bd049aeb247fc..01844cb629c9d 100644 --- a/contrib/pageinspect/sql/page.sql +++ b/contrib/pageinspect/sql/page.sql @@ -17,6 +17,7 @@ SELECT octet_length(get_raw_page('test1', 'fsm', 1)) AS fsm_1; SELECT octet_length(get_raw_page('test1', 'vm', 0)) AS vm_0; SELECT octet_length(get_raw_page('test1', 'vm', 1)) AS vm_1; +SELECT octet_length(get_raw_page('test1', 'main', -1)); SELECT octet_length(get_raw_page('xxx', 'main', 0)); SELECT octet_length(get_raw_page('test1', 'xxx', 0)); @@ -25,6 +26,7 @@ SELECT get_raw_page('test1', 0) = get_raw_page('test1', 'main', 0); SELECT pagesize, version FROM page_header(get_raw_page('test1', 0)); SELECT page_checksum(get_raw_page('test1', 0), 0) IS NOT NULL AS silly_checksum_test; +SELECT page_checksum(get_raw_page('test1', 0), -1); SELECT tuple_data_split('test1'::regclass, t_data, t_infomask, t_infomask2, t_bits) FROM heap_page_items(get_raw_page('test1', 0)); diff --git a/doc/src/sgml/pageinspect.sgml b/doc/src/sgml/pageinspect.sgml index 35858e1557604..0cad08a8a7e32 100644 --- a/doc/src/sgml/pageinspect.sgml +++ b/doc/src/sgml/pageinspect.sgml @@ -19,7 +19,7 @@ - get_raw_page(relname text, fork text, blkno int) returns bytea + get_raw_page(relname text, fork text, blkno bigint) returns bytea get_raw_page @@ -40,7 +40,7 @@ - get_raw_page(relname text, blkno int) returns bytea + get_raw_page(relname text, blkno bigint) returns bytea @@ -91,7 +91,7 @@ test=# SELECT * FROM page_header(get_raw_page('pg_class', 0)); - page_checksum(page bytea, blkno int4) returns smallint + page_checksum(page bytea, blkno bigint) returns smallint page_checksum @@ -315,7 +315,7 @@ allequalimage | f - bt_page_stats(relname text, blkno int) returns record + bt_page_stats(relname text, blkno bigint) returns record bt_page_stats @@ -346,7 +346,7 @@ btpo_flags | 3 - bt_page_items(relname text, blkno int) returns setof record + bt_page_items(relname text, blkno bigint) returns setof record bt_page_items @@ -845,7 +845,7 @@ test=# SELECT * FROM hash_page_items(get_raw_page('con_hash_index', 1)) LIMIT 5; - hash_bitmap_info(index oid, blkno int) returns record + hash_bitmap_info(index oid, blkno bigint) returns record hash_bitmap_info From a0efda88a679edaee9855628cb05b2ab00d80a15 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 19 Jan 2021 13:25:33 -0500 Subject: [PATCH 138/240] Remove faulty support for MergeAppend plan with WHERE CURRENT OF. Somebody extended search_plan_tree() to treat MergeAppend exactly like Append, which is 100% wrong, because unlike Append we can't assume that only one input node is actively returning tuples. Hence a cursor using a MergeAppend across a UNION ALL or inheritance tree could falsely match a WHERE CURRENT OF query at a row that isn't actually the cursor's current output row, but coincidentally has the same TID (in a different table) as the current output row. Delete the faulty code; this means that such a case will now return an error like 'cursor "foo" is not a simply updatable scan of table "bar"', instead of silently misbehaving. Users should not find that surprising though, as the same cursor query could have failed that way already depending on the chosen plan. (It would fail like that if the sort were done with an explicit Sort node instead of MergeAppend.) Expand the clearly-inadequate commentary to be more explicit about what this code is doing, in hopes of forestalling future mistakes. It's been like this for awhile, so back-patch to all supported branches. Discussion: https://postgr.es/m/482865.1611075182@sss.pgh.pa.us --- src/backend/executor/execCurrent.c | 53 +++++++++++++++--------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/src/backend/executor/execCurrent.c b/src/backend/executor/execCurrent.c index ff42cdd808815..33221a4d6ce1a 100644 --- a/src/backend/executor/execCurrent.c +++ b/src/backend/executor/execCurrent.c @@ -299,6 +299,10 @@ fetch_cursor_param_value(ExprContext *econtext, int paramId) * Search through a PlanState tree for a scan node on the specified table. * Return NULL if not found or multiple candidates. * + * CAUTION: this function is not charged simply with finding some candidate + * scan, but with ensuring that that scan returned the plan tree's current + * output row. That's why we must reject multiple-match cases. + * * If a candidate is found, set *pending_rescan to true if that candidate * or any node above it has a pending rescan action, i.e. chgParam != NULL. * That indicates that we shouldn't consider the node to be positioned on a @@ -317,7 +321,9 @@ search_plan_tree(PlanState *node, Oid table_oid, switch (nodeTag(node)) { /* - * Relation scan nodes can all be treated alike. Note that + * Relation scan nodes can all be treated alike: check to see if + * they are scanning the specified table. + * * ForeignScan and CustomScan might not have a currentRelation, in * which case we just ignore them. (We dare not descend to any * child plan nodes they might have, since we do not know the @@ -342,8 +348,26 @@ search_plan_tree(PlanState *node, Oid table_oid, } /* - * For Append, we must look through the members; watch out for - * multiple matches (possible if it was from UNION ALL) + * For Append, we can check each input node. It is safe to + * descend to the inputs because only the input that resulted in + * the Append's current output node could be positioned on a tuple + * at all; the other inputs are either at EOF or not yet started. + * Hence, if the desired table is scanned by some + * currently-inactive input node, we will find that node but then + * our caller will realize that it didn't emit the tuple of + * interest. + * + * We do need to watch out for multiple matches (possible if + * Append was from UNION ALL rather than an inheritance tree). + * + * Note: we can NOT descend through MergeAppend similarly, since + * its inputs are likely all active, and we don't know which one + * returned the current output tuple. (Perhaps that could be + * fixed if we were to let this code know more about MergeAppend's + * internal state, but it does not seem worth the trouble. Users + * should not expect plans for ORDER BY queries to be considered + * simply-updatable, since they won't be if the sorting is + * implemented by a Sort node.) */ case T_AppendState: { @@ -365,29 +389,6 @@ search_plan_tree(PlanState *node, Oid table_oid, break; } - /* - * Similarly for MergeAppend - */ - case T_MergeAppendState: - { - MergeAppendState *mstate = (MergeAppendState *) node; - int i; - - for (i = 0; i < mstate->ms_nplans; i++) - { - ScanState *elem = search_plan_tree(mstate->mergeplans[i], - table_oid, - pending_rescan); - - if (!elem) - continue; - if (result) - return NULL; /* multiple matches */ - result = elem; - } - break; - } - /* * Result and Limit can be descended through (these are safe * because they always return their input's current row) From 21378e1fefedcaed3d855ae7aa772555295d05d6 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Wed, 20 Jan 2021 11:38:17 +0900 Subject: [PATCH 139/240] Fix ALTER DEFAULT PRIVILEGES with duplicated objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Specifying duplicated objects in this command would lead to unique constraint violations in pg_default_acl or "tuple already updated by self" errors. Similarly to GRANT/REVOKE, increment the command ID after each subcommand processing to allow this case to work transparently. A regression test is added by tweaking one of the existing queries of privileges.sql to stress this case. Reported-by: Andrus Author: Michael Paquier Reviewed-by: Álvaro Herrera Discussion: https://postgr.es/m/ae2a7dc1-9d71-8cba-3bb9-e4cb7eb1f44e@hot.ee Backpatch-through: 9.5 --- src/backend/catalog/aclchk.c | 3 +++ src/test/regress/expected/privileges.out | 3 ++- src/test/regress/sql/privileges.sql | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index 1a81e768eccd5..f3c1ca18ae747 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -1365,6 +1365,9 @@ SetDefaultACL(InternalDefaultACL *iacls) ReleaseSysCache(tuple); table_close(rel, RowExclusiveLock); + + /* prevent error when processing duplicate objects */ + CommandCounterIncrement(); } diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out index 7754c20db47aa..5e5f98ac68a58 100644 --- a/src/test/regress/expected/privileges.out +++ b/src/test/regress/expected/privileges.out @@ -1649,7 +1649,8 @@ SELECT has_table_privilege('regress_priv_user1', 'testns.acltest1', 'INSERT'); - f (1 row) -ALTER DEFAULT PRIVILEGES IN SCHEMA testns GRANT SELECT ON TABLES TO public; +-- placeholder for test with duplicated schema and role names +ALTER DEFAULT PRIVILEGES IN SCHEMA testns,testns GRANT SELECT ON TABLES TO public,public; SELECT has_table_privilege('regress_priv_user1', 'testns.acltest1', 'SELECT'); -- no has_table_privilege --------------------- diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql index 4911ad4add847..fff76e0bd08d1 100644 --- a/src/test/regress/sql/privileges.sql +++ b/src/test/regress/sql/privileges.sql @@ -985,7 +985,8 @@ CREATE TABLE testns.acltest1 (x int); SELECT has_table_privilege('regress_priv_user1', 'testns.acltest1', 'SELECT'); -- no SELECT has_table_privilege('regress_priv_user1', 'testns.acltest1', 'INSERT'); -- no -ALTER DEFAULT PRIVILEGES IN SCHEMA testns GRANT SELECT ON TABLES TO public; +-- placeholder for test with duplicated schema and role names +ALTER DEFAULT PRIVILEGES IN SCHEMA testns,testns GRANT SELECT ON TABLES TO public,public; SELECT has_table_privilege('regress_priv_user1', 'testns.acltest1', 'SELECT'); -- no SELECT has_table_privilege('regress_priv_user1', 'testns.acltest1', 'INSERT'); -- no From a36dc04d424a6bfa03ee2cf75c85a6b7f9697e70 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Wed, 20 Jan 2021 13:28:10 +0900 Subject: [PATCH 140/240] Add regression test for DROP OWNED BY with default ACLs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DROP OWNED BY has a specific code path to remove ACLs stored in pg_default_acl when cleaning up shared dependencies that had no coverage with the existing tests. This issue has been found while digging into the bug fixed by 21378e1. As ALTER DEFAULT PRIVILEGES impacts the ACLs of all objects created while the default permissions are visible, the test uses a transaction rollback to isolate the test and avoid any impact with other sessions running in parallel. Reviewed-by: Álvaro Herrera Discussion: https://postgr.es/m/YAbQ1OD+3ip4lRv8@paquier.xyz --- src/test/regress/expected/privileges.out | 29 ++++++++++++++++++++++++ src/test/regress/sql/privileges.sql | 20 ++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out index 5e5f98ac68a58..8f2fc89851bc1 100644 --- a/src/test/regress/expected/privileges.out +++ b/src/test/regress/expected/privileges.out @@ -1760,6 +1760,35 @@ SELECT has_schema_privilege('regress_priv_user2', 'testns4', 'CREATE'); -- yes ALTER DEFAULT PRIVILEGES REVOKE ALL ON SCHEMAS FROM regress_priv_user2; COMMIT; +-- Test for DROP OWNED BY with shared dependencies. This is done in a +-- separate, rollbacked, transaction to avoid any trouble with other +-- regression sessions. +BEGIN; +ALTER DEFAULT PRIVILEGES GRANT ALL ON FUNCTIONS TO regress_priv_user2; +ALTER DEFAULT PRIVILEGES GRANT ALL ON SCHEMAS TO regress_priv_user2; +ALTER DEFAULT PRIVILEGES GRANT ALL ON SEQUENCES TO regress_priv_user2; +ALTER DEFAULT PRIVILEGES GRANT ALL ON TABLES TO regress_priv_user2; +ALTER DEFAULT PRIVILEGES GRANT ALL ON TYPES TO regress_priv_user2; +SELECT count(*) FROM pg_shdepend + WHERE deptype = 'a' AND + refobjid = 'regress_priv_user2'::regrole AND + classid = 'pg_default_acl'::regclass; + count +------- + 5 +(1 row) + +DROP OWNED BY regress_priv_user2, regress_priv_user2; +SELECT count(*) FROM pg_shdepend + WHERE deptype = 'a' AND + refobjid = 'regress_priv_user2'::regrole AND + classid = 'pg_default_acl'::regclass; + count +------- + 0 +(1 row) + +ROLLBACK; CREATE SCHEMA testns5; SELECT has_schema_privilege('regress_priv_user2', 'testns5', 'USAGE'); -- no has_schema_privilege diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql index fff76e0bd08d1..1c250a11fe1ac 100644 --- a/src/test/regress/sql/privileges.sql +++ b/src/test/regress/sql/privileges.sql @@ -1049,6 +1049,26 @@ ALTER DEFAULT PRIVILEGES REVOKE ALL ON SCHEMAS FROM regress_priv_user2; COMMIT; +-- Test for DROP OWNED BY with shared dependencies. This is done in a +-- separate, rollbacked, transaction to avoid any trouble with other +-- regression sessions. +BEGIN; +ALTER DEFAULT PRIVILEGES GRANT ALL ON FUNCTIONS TO regress_priv_user2; +ALTER DEFAULT PRIVILEGES GRANT ALL ON SCHEMAS TO regress_priv_user2; +ALTER DEFAULT PRIVILEGES GRANT ALL ON SEQUENCES TO regress_priv_user2; +ALTER DEFAULT PRIVILEGES GRANT ALL ON TABLES TO regress_priv_user2; +ALTER DEFAULT PRIVILEGES GRANT ALL ON TYPES TO regress_priv_user2; +SELECT count(*) FROM pg_shdepend + WHERE deptype = 'a' AND + refobjid = 'regress_priv_user2'::regrole AND + classid = 'pg_default_acl'::regclass; +DROP OWNED BY regress_priv_user2, regress_priv_user2; +SELECT count(*) FROM pg_shdepend + WHERE deptype = 'a' AND + refobjid = 'regress_priv_user2'::regrole AND + classid = 'pg_default_acl'::regclass; +ROLLBACK; + CREATE SCHEMA testns5; SELECT has_schema_privilege('regress_priv_user2', 'testns5', 'USAGE'); -- no From 679744cf1b0d0569d16b4dd2d020f9095ea3d53b Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Wed, 20 Jan 2021 22:31:26 +1300 Subject: [PATCH 141/240] Fix sample output of EXPLAIN ANALYZE. Since commit f0f13a3a08b2757997410f3a1c38bdc22973c525, we estimate ModifyTable paths without a RETURNING clause differently. Update an example from the manual that showed the old behavior. Author: Takayuki Tsunakawa Reviewed-by: Laurenz Albe Discussion: https://postgr.es/m/TYAPR01MB29905674F41693BBA9DA28CAFEA20%40TYAPR01MB2990.jpnprd01.prod.outlook.com --- doc/src/sgml/perform.sgml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/src/sgml/perform.sgml b/doc/src/sgml/perform.sgml index 117a1f7ff92a6..aca1fe86a7c80 100644 --- a/doc/src/sgml/perform.sgml +++ b/doc/src/sgml/perform.sgml @@ -773,7 +773,7 @@ EXPLAIN ANALYZE UPDATE tenk1 SET hundred = hundred + 1 WHERE unique1 < 100; QUERY PLAN -------------------------------------------------------------------&zwsp;------------------------------------------------------------- - Update on tenk1 (cost=5.07..229.46 rows=101 width=250) (actual time=14.628..14.628 rows=0 loops=1) + Update on tenk1 (cost=5.07..229.46 rows=0 width=0) (actual time=14.628..14.628 rows=0 loops=1) -> Bitmap Heap Scan on tenk1 (cost=5.07..229.46 rows=101 width=250) (actual time=0.101..0.439 rows=100 loops=1) Recheck Cond: (unique1 < 100) -> Bitmap Index Scan on tenk1_unique1 (cost=0.00..5.04 rows=101 width=0) (actual time=0.043..0.043 rows=100 loops=1) @@ -809,7 +809,7 @@ ROLLBACK; EXPLAIN UPDATE parent SET f2 = f2 + 1 WHERE f1 = 101; QUERY PLAN -------------------------------------------------------------------&zwsp;---------------- - Update on parent (cost=0.00..24.53 rows=4 width=14) + Update on parent (cost=0.00..24.53 rows=0 width=0) Update on parent Update on child1 Update on child2 From 6b4d3046f422c2682365924b515c7588d5a3e651 Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Wed, 20 Jan 2021 11:58:03 +0200 Subject: [PATCH 142/240] Fix bug in detecting concurrent page splits in GiST insert In commit 9eb5607e699, I got the condition on checking for split or deleted page wrong: I used && instead of ||. The comment correctly said "concurrent split _or_ deletion". As a result, GiST insertion could miss a concurrent split, and insert to wrong page. Duncan Sands demonstrated this with a test script that did a lot of concurrent inserts. Backpatch to v12, where this was introduced. REINDEX is required to fix indexes that were affected by this bug. Backpatch-through: 12 Reported-by: Duncan Sands Discussion: https://www.postgresql.org/message-id/a9690483-6c6c-3c82-c8ba-dc1a40848f11%40deepbluecap.com --- src/backend/access/gist/gist.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index 992936cfa8eac..f203bb594cdb9 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -248,6 +248,9 @@ gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate, if (GistFollowRight(page)) elog(ERROR, "concurrent GiST page split was incomplete"); + /* should never try to insert to a deleted page */ + Assert(!GistPageIsDeleted(page)); + *splitinfo = NIL; /* @@ -863,7 +866,7 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace, */ } else if ((GistFollowRight(stack->page) || - stack->parent->lsn < GistPageGetNSN(stack->page)) && + stack->parent->lsn < GistPageGetNSN(stack->page)) || GistPageIsDeleted(stack->page)) { /* From c2dc1a79767a0f947e1145f82eb65dfe4360d25f Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 20 Jan 2021 11:49:29 -0500 Subject: [PATCH 143/240] Disable vacuum page skipping in selected test cases. By default VACUUM will skip pages that it can't immediately get exclusive access to, which means that even activities as harmless and unpredictable as checkpoint buffer writes might prevent a page from being processed. Ordinarily this is no big deal, but we have a small number of test cases that examine the results of VACUUM's processing and therefore will fail if the page of interest is skipped. This seems to be the explanation for some rare buildfarm failures. To fix, add the DISABLE_PAGE_SKIPPING option to the VACUUM commands in tests where this could be an issue. In passing, remove a duplicated query in pageinspect/sql/page.sql. Back-patch as necessary (some of these cases are as old as v10). Discussion: https://postgr.es/m/413923.1611006484@sss.pgh.pa.us --- contrib/amcheck/expected/check_heap.out | 2 +- contrib/amcheck/sql/check_heap.sql | 2 +- contrib/amcheck/t/001_verify_heapam.pl | 2 +- contrib/pageinspect/expected/page.out | 16 +++------------- contrib/pageinspect/sql/page.sql | 12 +++--------- contrib/pg_visibility/expected/pg_visibility.out | 6 +++--- contrib/pg_visibility/sql/pg_visibility.sql | 6 +++--- 7 files changed, 15 insertions(+), 31 deletions(-) diff --git a/contrib/amcheck/expected/check_heap.out b/contrib/amcheck/expected/check_heap.out index 882f853d56ac3..1fb3823142902 100644 --- a/contrib/amcheck/expected/check_heap.out +++ b/contrib/amcheck/expected/check_heap.out @@ -109,7 +109,7 @@ ERROR: ending block number must be between 0 and 0 SELECT * FROM verify_heapam(relation := 'heaptest', startblock := 10000, endblock := 11000); ERROR: starting block number must be between 0 and 0 -- Vacuum freeze to change the xids encountered in subsequent tests -VACUUM FREEZE heaptest; +VACUUM (FREEZE, DISABLE_PAGE_SKIPPING) heaptest; -- Check that valid options are not rejected nor corruption reported -- for a non-empty frozen table SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'none'); diff --git a/contrib/amcheck/sql/check_heap.sql b/contrib/amcheck/sql/check_heap.sql index c10a25f21cb89..298de6886afd8 100644 --- a/contrib/amcheck/sql/check_heap.sql +++ b/contrib/amcheck/sql/check_heap.sql @@ -51,7 +51,7 @@ SELECT * FROM verify_heapam(relation := 'heaptest', startblock := 0, endblock := SELECT * FROM verify_heapam(relation := 'heaptest', startblock := 10000, endblock := 11000); -- Vacuum freeze to change the xids encountered in subsequent tests -VACUUM FREEZE heaptest; +VACUUM (FREEZE, DISABLE_PAGE_SKIPPING) heaptest; -- Check that valid options are not rejected nor corruption reported -- for a non-empty frozen table diff --git a/contrib/amcheck/t/001_verify_heapam.pl b/contrib/amcheck/t/001_verify_heapam.pl index 1581e51f3ca7f..a2f65b826d375 100644 --- a/contrib/amcheck/t/001_verify_heapam.pl +++ b/contrib/amcheck/t/001_verify_heapam.pl @@ -46,7 +46,7 @@ # Check a corrupt table with all-frozen data # fresh_test_table('test'); -$node->safe_psql('postgres', q(VACUUM FREEZE test)); +$node->safe_psql('postgres', q(VACUUM (FREEZE, DISABLE_PAGE_SKIPPING) test)); corrupt_first_page('test'); detects_heap_corruption("verify_heapam('test')", "all-frozen corrupted table"); diff --git a/contrib/pageinspect/expected/page.out b/contrib/pageinspect/expected/page.out index 4cd0db80183fe..4da28f0a1db58 100644 --- a/contrib/pageinspect/expected/page.out +++ b/contrib/pageinspect/expected/page.out @@ -1,7 +1,7 @@ CREATE EXTENSION pageinspect; CREATE TABLE test1 (a int, b int); INSERT INTO test1 VALUES (16777217, 131584); -VACUUM test1; -- set up FSM +VACUUM (DISABLE_PAGE_SKIPPING) test1; -- set up FSM -- The page contents can vary, so just test that it can be read -- successfully, but don't keep the output. SELECT octet_length(get_raw_page('test1', 'main', 0)) AS main_0; @@ -87,18 +87,8 @@ SELECT * FROM fsm_page_contents(get_raw_page('test1', 'fsm', 0)); (1 row) -- If we freeze the only tuple on test1, the infomask should --- always be the same in all test runs. we show raw flags by --- default: HEAP_XMIN_COMMITTED and HEAP_XMIN_INVALID. -VACUUM FREEZE test1; -SELECT t_infomask, t_infomask2, raw_flags, combined_flags -FROM heap_page_items(get_raw_page('test1', 0)), - LATERAL heap_tuple_infomask_flags(t_infomask, t_infomask2); - t_infomask | t_infomask2 | raw_flags | combined_flags -------------+-------------+-----------------------------------------------------------+-------------------- - 2816 | 2 | {HEAP_XMIN_COMMITTED,HEAP_XMIN_INVALID,HEAP_XMAX_INVALID} | {HEAP_XMIN_FROZEN} -(1 row) - --- output the decoded flag HEAP_XMIN_FROZEN instead +-- always be the same in all test runs. +VACUUM (FREEZE, DISABLE_PAGE_SKIPPING) test1; SELECT t_infomask, t_infomask2, raw_flags, combined_flags FROM heap_page_items(get_raw_page('test1', 0)), LATERAL heap_tuple_infomask_flags(t_infomask, t_infomask2); diff --git a/contrib/pageinspect/sql/page.sql b/contrib/pageinspect/sql/page.sql index 01844cb629c9d..d333b763d709a 100644 --- a/contrib/pageinspect/sql/page.sql +++ b/contrib/pageinspect/sql/page.sql @@ -3,7 +3,7 @@ CREATE EXTENSION pageinspect; CREATE TABLE test1 (a int, b int); INSERT INTO test1 VALUES (16777217, 131584); -VACUUM test1; -- set up FSM +VACUUM (DISABLE_PAGE_SKIPPING) test1; -- set up FSM -- The page contents can vary, so just test that it can be read -- successfully, but don't keep the output. @@ -34,15 +34,9 @@ SELECT tuple_data_split('test1'::regclass, t_data, t_infomask, t_infomask2, t_bi SELECT * FROM fsm_page_contents(get_raw_page('test1', 'fsm', 0)); -- If we freeze the only tuple on test1, the infomask should --- always be the same in all test runs. we show raw flags by --- default: HEAP_XMIN_COMMITTED and HEAP_XMIN_INVALID. -VACUUM FREEZE test1; +-- always be the same in all test runs. +VACUUM (FREEZE, DISABLE_PAGE_SKIPPING) test1; -SELECT t_infomask, t_infomask2, raw_flags, combined_flags -FROM heap_page_items(get_raw_page('test1', 0)), - LATERAL heap_tuple_infomask_flags(t_infomask, t_infomask2); - --- output the decoded flag HEAP_XMIN_FROZEN instead SELECT t_infomask, t_infomask2, raw_flags, combined_flags FROM heap_page_items(get_raw_page('test1', 0)), LATERAL heap_tuple_infomask_flags(t_infomask, t_infomask2); diff --git a/contrib/pg_visibility/expected/pg_visibility.out b/contrib/pg_visibility/expected/pg_visibility.out index 0017e3415c84b..315633bfea66c 100644 --- a/contrib/pg_visibility/expected/pg_visibility.out +++ b/contrib/pg_visibility/expected/pg_visibility.out @@ -105,7 +105,7 @@ ERROR: "test_foreign_table" is not a table, materialized view, or TOAST table create table regular_table (a int, b text); alter table regular_table alter column b set storage external; insert into regular_table values (1, repeat('one', 1000)), (2, repeat('two', 1000)); -vacuum regular_table; +vacuum (disable_page_skipping) regular_table; select count(*) > 0 from pg_visibility('regular_table'); ?column? ---------- @@ -132,7 +132,7 @@ select count(*) > 0 from pg_visibility((select reltoastrelid from pg_class where (1 row) create materialized view matview_visibility_test as select * from regular_table; -vacuum matview_visibility_test; +vacuum (disable_page_skipping) matview_visibility_test; select count(*) > 0 from pg_visibility('matview_visibility_test'); ?column? ---------- @@ -149,7 +149,7 @@ select count(*) > 0 from pg_visibility('matview_visibility_test'); -- regular tables which are part of a partition *do* have visibility maps insert into test_partition values (1); -vacuum test_partition; +vacuum (disable_page_skipping) test_partition; select count(*) > 0 from pg_visibility('test_partition', 0); ?column? ---------- diff --git a/contrib/pg_visibility/sql/pg_visibility.sql b/contrib/pg_visibility/sql/pg_visibility.sql index ec1afd490657b..ff3538f9964a1 100644 --- a/contrib/pg_visibility/sql/pg_visibility.sql +++ b/contrib/pg_visibility/sql/pg_visibility.sql @@ -71,7 +71,7 @@ select pg_truncate_visibility_map('test_foreign_table'); create table regular_table (a int, b text); alter table regular_table alter column b set storage external; insert into regular_table values (1, repeat('one', 1000)), (2, repeat('two', 1000)); -vacuum regular_table; +vacuum (disable_page_skipping) regular_table; select count(*) > 0 from pg_visibility('regular_table'); select count(*) > 0 from pg_visibility((select reltoastrelid from pg_class where relname = 'regular_table')); truncate regular_table; @@ -79,7 +79,7 @@ select count(*) > 0 from pg_visibility('regular_table'); select count(*) > 0 from pg_visibility((select reltoastrelid from pg_class where relname = 'regular_table')); create materialized view matview_visibility_test as select * from regular_table; -vacuum matview_visibility_test; +vacuum (disable_page_skipping) matview_visibility_test; select count(*) > 0 from pg_visibility('matview_visibility_test'); insert into regular_table values (1), (2); refresh materialized view matview_visibility_test; @@ -87,7 +87,7 @@ select count(*) > 0 from pg_visibility('matview_visibility_test'); -- regular tables which are part of a partition *do* have visibility maps insert into test_partition values (1); -vacuum test_partition; +vacuum (disable_page_skipping) test_partition; select count(*) > 0 from pg_visibility('test_partition', 0); select count(*) > 0 from pg_visibility_map('test_partition'); select count(*) > 0 from pg_visibility_map_summary('test_partition'); From 9d23c15a034ba163ae1045b945954e8e1bcfc72a Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 20 Jan 2021 12:07:23 -0500 Subject: [PATCH 144/240] Further tweaking of PG_SYSROOT heuristics for macOS. It emerges that in some phases of the moon (perhaps to do with directory entry order?), xcrun will report that the SDK path is /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk which is normally a symlink to a version-numbered sibling directory. Our heuristic to skip non-version-numbered pathnames was rejecting that, which is the wrong thing to do. We'd still like to end up with a version-numbered PG_SYSROOT value, but we can have that by dereferencing the symlink. Like the previous fix, back-patch to all supported versions. Discussion: https://postgr.es/m/522433.1611089678@sss.pgh.pa.us --- src/template/darwin | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/template/darwin b/src/template/darwin index 1868c147cbf11..e14d53b601acf 100644 --- a/src/template/darwin +++ b/src/template/darwin @@ -7,13 +7,20 @@ if test x"$PG_SYSROOT" = x"" ; then # This is far more complicated than it ought to be. We first ask # "xcrun --show-sdk-path", which seems to match the default -isysroot - # setting of Apple's compilers. However, that may produce no result or - # a result that is not version-specific (i.e., just ".../SDKs/MacOSX.sdk"). - # Using a version-specific sysroot seems desirable, so if there are not - # digits in the directory name, try "xcrun --sdk macosx --show-sdk-path"; - # and if that still doesn't work, fall back to asking xcodebuild, - # which is often a good deal slower. + # setting of Apple's compilers. PG_SYSROOT=`xcrun --show-sdk-path 2>/dev/null` + # That may fail, or produce a result that is not version-specific (i.e., + # just ".../SDKs/MacOSX.sdk"). Using a version-specific sysroot seems + # desirable, so if the path is a non-version-specific symlink, expand it. + if test -L "$PG_SYSROOT"; then + if expr x"$PG_SYSROOT" : '.*[0-9]\.[0-9][^/]*$' >/dev/null ; then : okay + else + PG_SYSROOT=`expr "$PG_SYSROOT" : '\(.*\)/'`/`readlink "$PG_SYSROOT"` + fi + fi + # If there are still not digits in the directory name, try + # "xcrun --sdk macosx --show-sdk-path"; and if that still doesn't work, + # fall back to asking xcodebuild, which is often a good deal slower. if expr x"$PG_SYSROOT" : '.*[0-9]\.[0-9][^/]*$' >/dev/null ; then : okay else PG_SYSROOT=`xcrun --sdk macosx --show-sdk-path 2>/dev/null` From ad600bba0422dde4b73fbd61049ff2a3847b068a Mon Sep 17 00:00:00 2001 From: Tomas Vondra Date: Wed, 20 Jan 2021 22:56:06 +0100 Subject: [PATCH 145/240] psql \dX: list extended statistics objects The new command lists extended statistics objects. All past releases with extended statistics are supported. This is a simplified version of commit 891a1d0bca, which had to be reverted due to not considering pg_statistic_ext_data is not accessible by regular users. Fields requiring access to this catalog were removed. It's possible to add them, but it'll require changes to core. Author: Tatsuro Yamada Reviewed-by: Julien Rouhaud, Alvaro Herrera, Tomas Vondra, Noriyoshi Shinoda Discussion: https://postgr.es/m/c027a541-5856-75a5-0868-341301e1624b%40nttcom.co.jp_1 --- doc/src/sgml/ref/psql-ref.sgml | 21 +++++ src/bin/psql/command.c | 3 + src/bin/psql/describe.c | 83 +++++++++++++++++ src/bin/psql/describe.h | 3 + src/bin/psql/help.c | 1 + src/bin/psql/tab-complete.c | 4 +- src/test/regress/expected/stats_ext.out | 116 ++++++++++++++++++++++++ src/test/regress/sql/stats_ext.sql | 37 ++++++++ 8 files changed, 267 insertions(+), 1 deletion(-) diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index 221a967bfe664..13c1edfa4ddbb 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -1919,6 +1919,27 @@ testdb=> + + \dX [ pattern ] + + + Lists extended statistics. + If pattern + is specified, only those extended statistics whose names match the + pattern are listed. + + + + The column of the kind of extended stats (e.g. Ndistinct) shows its status. + NULL means that it doesn't exists. "defined" means that it was requested + when creating the statistics. + You can use pg_stats_ext if you'd like to know whether + ANALYZE was run and statistics are available to the + planner. + + + + \dy[+] [ pattern ] diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 303e7c3ad8b38..c98e3d31d0c71 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -928,6 +928,9 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd) else success = listExtensions(pattern); break; + case 'X': /* Extended Statistics */ + success = listExtendedStats(pattern); + break; case 'y': /* Event Triggers */ success = listEventTriggers(pattern, show_verbose); break; diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index caf97563f4871..20af5a92b4f41 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -4392,6 +4392,89 @@ listEventTriggers(const char *pattern, bool verbose) return true; } +/* + * \dX + * + * Describes extended statistics. + */ +bool +listExtendedStats(const char *pattern) +{ + PQExpBufferData buf; + PGresult *res; + printQueryOpt myopt = pset.popt; + + if (pset.sversion < 100000) + { + char sverbuf[32]; + + pg_log_error("The server (version %s) does not support extended statistics.", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); + return true; + } + + initPQExpBuffer(&buf); + printfPQExpBuffer(&buf, + "SELECT \n" + "es.stxnamespace::pg_catalog.regnamespace::text AS \"%s\", \n" + "es.stxname AS \"%s\", \n" + "pg_catalog.format('%%s FROM %%s', \n" + " (SELECT pg_catalog.string_agg(pg_catalog.quote_ident(a.attname),', ') \n" + " FROM pg_catalog.unnest(es.stxkeys) s(attnum) \n" + " JOIN pg_catalog.pg_attribute a \n" + " ON (es.stxrelid = a.attrelid \n" + " AND a.attnum = s.attnum \n" + " AND NOT a.attisdropped)), \n" + "es.stxrelid::regclass) AS \"%s\"", + gettext_noop("Schema"), + gettext_noop("Name"), + gettext_noop("Definition")); + + appendPQExpBuffer(&buf, + ",\nCASE WHEN 'd' = any(es.stxkind) THEN 'defined' \n" + "END AS \"%s\", \n" + "CASE WHEN 'f' = any(es.stxkind) THEN 'defined' \n" + "END AS \"%s\"", + gettext_noop("Ndistinct"), + gettext_noop("Dependencies")); + + /* + * Include the MCV statistics kind. + */ + if (pset.sversion >= 120000) + { + appendPQExpBuffer(&buf, + ",\nCASE WHEN 'm' = any(es.stxkind) THEN 'defined' \n" + "END AS \"%s\" ", + gettext_noop("MCV")); + } + + appendPQExpBufferStr(&buf, + " \nFROM pg_catalog.pg_statistic_ext es \n"); + + processSQLNamePattern(pset.db, &buf, pattern, + false, false, + "es.stxnamespace::pg_catalog.regnamespace::text", "es.stxname", + NULL, NULL); + + appendPQExpBufferStr(&buf, "ORDER BY 1, 2;"); + + res = PSQLexec(buf.data); + termPQExpBuffer(&buf); + if (!res) + return false; + + myopt.nullPrint = NULL; + myopt.title = _("List of extended statistics"); + myopt.translate_header = true; + + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); + + PQclear(res); + return true; +} + /* * \dC * diff --git a/src/bin/psql/describe.h b/src/bin/psql/describe.h index 6044e3a08284a..39856a0c7e8f0 100644 --- a/src/bin/psql/describe.h +++ b/src/bin/psql/describe.h @@ -102,6 +102,9 @@ extern bool listExtensions(const char *pattern); /* \dx+ */ extern bool listExtensionContents(const char *pattern); +/* \dX */ +extern bool listExtendedStats(const char *pattern); + /* \dy */ extern bool listEventTriggers(const char *pattern, bool verbose); diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index 9ec1c4e810c74..4883ebd2ed0b1 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -267,6 +267,7 @@ slashUsage(unsigned short int pager) fprintf(output, _(" \\du[S+] [PATTERN] list roles\n")); fprintf(output, _(" \\dv[S+] [PATTERN] list views\n")); fprintf(output, _(" \\dx[+] [PATTERN] list extensions\n")); + fprintf(output, _(" \\dX [PATTERN] list extended statistics\n")); fprintf(output, _(" \\dy [PATTERN] list event triggers\n")); fprintf(output, _(" \\l[+] [PATTERN] list databases\n")); fprintf(output, _(" \\sf[+] FUNCNAME show a function's definition\n")); diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 6abcbea96349a..17f726503888d 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -1505,7 +1505,7 @@ psql_completion(const char *text, int start, int end) "\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dL", "\\dm", "\\dn", "\\do", "\\dO", "\\dp", "\\dP", "\\dPi", "\\dPt", "\\drds", "\\dRs", "\\dRp", "\\ds", "\\dS", - "\\dt", "\\dT", "\\dv", "\\du", "\\dx", "\\dy", + "\\dt", "\\dT", "\\dv", "\\du", "\\dx", "\\dX", "\\dy", "\\e", "\\echo", "\\ef", "\\elif", "\\else", "\\encoding", "\\endif", "\\errverbose", "\\ev", "\\f", @@ -3974,6 +3974,8 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL); else if (TailMatchesCS("\\dx*")) COMPLETE_WITH_QUERY(Query_for_list_of_extensions); + else if (TailMatchesCS("\\dX*")) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_statistics, NULL); else if (TailMatchesCS("\\dm*")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL); else if (TailMatchesCS("\\dE*")) diff --git a/src/test/regress/expected/stats_ext.out b/src/test/regress/expected/stats_ext.out index f094731e328ca..431b3fa3de1f4 100644 --- a/src/test/regress/expected/stats_ext.out +++ b/src/test/regress/expected/stats_ext.out @@ -1727,6 +1727,122 @@ INSERT INTO tststats.priv_test_tbl CREATE STATISTICS tststats.priv_test_stats (mcv) ON a, b FROM tststats.priv_test_tbl; ANALYZE tststats.priv_test_tbl; +-- Check printing info about extended statistics by \dX +create table stts_t1 (a int, b int); +create statistics stts_1 (ndistinct) on a, b from stts_t1; +create statistics stts_2 (ndistinct, dependencies) on a, b from stts_t1; +create statistics stts_3 (ndistinct, dependencies, mcv) on a, b from stts_t1; +create table stts_t2 (a int, b int, c int); +create statistics stts_4 on b, c from stts_t2; +create table stts_t3 (col1 int, col2 int, col3 int); +create statistics stts_hoge on col1, col2, col3 from stts_t3; +create schema stts_s1; +create schema stts_s2; +create statistics stts_s1.stts_foo on col1, col2 from stts_t3; +create statistics stts_s2.stts_yama (dependencies, mcv) on col1, col3 from stts_t3; +insert into stts_t1 select i,i from generate_series(1,100) i; +analyze stts_t1; +\dX + List of extended statistics + Schema | Name | Definition | Ndistinct | Dependencies | MCV +----------+------------------------+--------------------------------------+-----------+--------------+--------- + public | func_deps_stat | a, b, c FROM functional_dependencies | | defined | + public | mcv_lists_arrays_stats | a, b, c FROM mcv_lists_arrays | | | defined + public | mcv_lists_bool_stats | a, b, c FROM mcv_lists_bool | | | defined + public | mcv_lists_stats | a, b, d FROM mcv_lists | | | defined + public | stts_1 | a, b FROM stts_t1 | defined | | + public | stts_2 | a, b FROM stts_t1 | defined | defined | + public | stts_3 | a, b FROM stts_t1 | defined | defined | defined + public | stts_4 | b, c FROM stts_t2 | defined | defined | defined + public | stts_hoge | col1, col2, col3 FROM stts_t3 | defined | defined | defined + stts_s1 | stts_foo | col1, col2 FROM stts_t3 | defined | defined | defined + stts_s2 | stts_yama | col1, col3 FROM stts_t3 | | defined | defined + tststats | priv_test_stats | a, b FROM tststats.priv_test_tbl | | | defined +(12 rows) + +\dX stts_? + List of extended statistics + Schema | Name | Definition | Ndistinct | Dependencies | MCV +--------+--------+-------------------+-----------+--------------+--------- + public | stts_1 | a, b FROM stts_t1 | defined | | + public | stts_2 | a, b FROM stts_t1 | defined | defined | + public | stts_3 | a, b FROM stts_t1 | defined | defined | defined + public | stts_4 | b, c FROM stts_t2 | defined | defined | defined +(4 rows) + +\dX *stts_hoge + List of extended statistics + Schema | Name | Definition | Ndistinct | Dependencies | MCV +--------+-----------+-------------------------------+-----------+--------------+--------- + public | stts_hoge | col1, col2, col3 FROM stts_t3 | defined | defined | defined +(1 row) + +\dX+ + List of extended statistics + Schema | Name | Definition | Ndistinct | Dependencies | MCV +----------+------------------------+--------------------------------------+-----------+--------------+--------- + public | func_deps_stat | a, b, c FROM functional_dependencies | | defined | + public | mcv_lists_arrays_stats | a, b, c FROM mcv_lists_arrays | | | defined + public | mcv_lists_bool_stats | a, b, c FROM mcv_lists_bool | | | defined + public | mcv_lists_stats | a, b, d FROM mcv_lists | | | defined + public | stts_1 | a, b FROM stts_t1 | defined | | + public | stts_2 | a, b FROM stts_t1 | defined | defined | + public | stts_3 | a, b FROM stts_t1 | defined | defined | defined + public | stts_4 | b, c FROM stts_t2 | defined | defined | defined + public | stts_hoge | col1, col2, col3 FROM stts_t3 | defined | defined | defined + stts_s1 | stts_foo | col1, col2 FROM stts_t3 | defined | defined | defined + stts_s2 | stts_yama | col1, col3 FROM stts_t3 | | defined | defined + tststats | priv_test_stats | a, b FROM tststats.priv_test_tbl | | | defined +(12 rows) + +\dX+ stts_? + List of extended statistics + Schema | Name | Definition | Ndistinct | Dependencies | MCV +--------+--------+-------------------+-----------+--------------+--------- + public | stts_1 | a, b FROM stts_t1 | defined | | + public | stts_2 | a, b FROM stts_t1 | defined | defined | + public | stts_3 | a, b FROM stts_t1 | defined | defined | defined + public | stts_4 | b, c FROM stts_t2 | defined | defined | defined +(4 rows) + +\dX+ *stts_hoge + List of extended statistics + Schema | Name | Definition | Ndistinct | Dependencies | MCV +--------+-----------+-------------------------------+-----------+--------------+--------- + public | stts_hoge | col1, col2, col3 FROM stts_t3 | defined | defined | defined +(1 row) + +\dX+ stts_s2.stts_yama + List of extended statistics + Schema | Name | Definition | Ndistinct | Dependencies | MCV +---------+-----------+-------------------------+-----------+--------------+--------- + stts_s2 | stts_yama | col1, col3 FROM stts_t3 | | defined | defined +(1 row) + +create role regress_stats_ext nosuperuser; +set role regress_stats_ext; +\dX + List of extended statistics + Schema | Name | Definition | Ndistinct | Dependencies | MCV +----------+------------------------+--------------------------------------+-----------+--------------+--------- + public | func_deps_stat | a, b, c FROM functional_dependencies | | defined | + public | mcv_lists_arrays_stats | a, b, c FROM mcv_lists_arrays | | | defined + public | mcv_lists_bool_stats | a, b, c FROM mcv_lists_bool | | | defined + public | mcv_lists_stats | a, b, d FROM mcv_lists | | | defined + public | stts_1 | a, b FROM stts_t1 | defined | | + public | stts_2 | a, b FROM stts_t1 | defined | defined | + public | stts_3 | a, b FROM stts_t1 | defined | defined | defined + public | stts_4 | b, c FROM stts_t2 | defined | defined | defined + public | stts_hoge | col1, col2, col3 FROM stts_t3 | defined | defined | defined + stts_s1 | stts_foo | col1, col2 FROM stts_t3 | defined | defined | defined + stts_s2 | stts_yama | col1, col3 FROM stts_t3 | | defined | defined + tststats | priv_test_stats | a, b FROM tststats.priv_test_tbl | | | defined +(12 rows) + +reset role; +drop table stts_t1, stts_t2, stts_t3; +drop schema stts_s1, stts_s2 cascade; +drop user regress_stats_ext; -- User with no access CREATE USER regress_stats_user1; GRANT USAGE ON SCHEMA tststats TO regress_stats_user1; diff --git a/src/test/regress/sql/stats_ext.sql b/src/test/regress/sql/stats_ext.sql index cb08b478a42b6..0d7a114b198fa 100644 --- a/src/test/regress/sql/stats_ext.sql +++ b/src/test/regress/sql/stats_ext.sql @@ -914,6 +914,43 @@ CREATE STATISTICS tststats.priv_test_stats (mcv) ON a, b ANALYZE tststats.priv_test_tbl; +-- Check printing info about extended statistics by \dX +create table stts_t1 (a int, b int); +create statistics stts_1 (ndistinct) on a, b from stts_t1; +create statistics stts_2 (ndistinct, dependencies) on a, b from stts_t1; +create statistics stts_3 (ndistinct, dependencies, mcv) on a, b from stts_t1; + +create table stts_t2 (a int, b int, c int); +create statistics stts_4 on b, c from stts_t2; + +create table stts_t3 (col1 int, col2 int, col3 int); +create statistics stts_hoge on col1, col2, col3 from stts_t3; + +create schema stts_s1; +create schema stts_s2; +create statistics stts_s1.stts_foo on col1, col2 from stts_t3; +create statistics stts_s2.stts_yama (dependencies, mcv) on col1, col3 from stts_t3; + +insert into stts_t1 select i,i from generate_series(1,100) i; +analyze stts_t1; + +\dX +\dX stts_? +\dX *stts_hoge +\dX+ +\dX+ stts_? +\dX+ *stts_hoge +\dX+ stts_s2.stts_yama + +create role regress_stats_ext nosuperuser; +set role regress_stats_ext; +\dX +reset role; + +drop table stts_t1, stts_t2, stts_t3; +drop schema stts_s1, stts_s2 cascade; +drop user regress_stats_ext; + -- User with no access CREATE USER regress_stats_user1; GRANT USAGE ON SCHEMA tststats TO regress_stats_user1; From b663a4136331de6c7364226e3dbf7c88bfee7145 Mon Sep 17 00:00:00 2001 From: Tomas Vondra Date: Wed, 20 Jan 2021 23:05:46 +0100 Subject: [PATCH 146/240] Implement support for bulk inserts in postgres_fdw Extends the FDW API to allow batching inserts into foreign tables. That is usually much more efficient than inserting individual rows, due to high latency for each round-trip to the foreign server. It was possible to implement something similar in the regular FDW API, but it was inconvenient and there were issues with reporting the number of actually inserted rows etc. This extends the FDW API with two new functions: * GetForeignModifyBatchSize - allows the FDW picking optimal batch size * ExecForeignBatchInsert - inserts a batch of rows at once Currently, only INSERT queries support batching. Support for DELETE and UPDATE may be added in the future. This also implements batching for postgres_fdw. The batch size may be specified using "batch_size" option both at the server and table level. The initial patch version was written by me, but it was rewritten and improved in many ways by Takayuki Tsunakawa. Author: Takayuki Tsunakawa Reviewed-by: Tomas Vondra, Amit Langote Discussion: https://postgr.es/m/20200628151002.7x5laxwpgvkyiu3q@development --- contrib/postgres_fdw/deparse.c | 54 ++- .../postgres_fdw/expected/postgres_fdw.out | 155 ++++++++- contrib/postgres_fdw/option.c | 14 + contrib/postgres_fdw/postgres_fdw.c | 329 +++++++++++++++--- contrib/postgres_fdw/postgres_fdw.h | 5 +- contrib/postgres_fdw/sql/postgres_fdw.sql | 93 +++++ doc/src/sgml/fdwhandler.sgml | 89 ++++- doc/src/sgml/postgres-fdw.sgml | 13 + src/backend/executor/execPartition.c | 17 + src/backend/executor/nodeModifyTable.c | 160 +++++++++ src/backend/nodes/list.c | 15 + src/include/foreign/fdwapi.h | 10 + src/include/nodes/execnodes.h | 6 + src/include/nodes/pg_list.h | 15 + 14 files changed, 903 insertions(+), 72 deletions(-) diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c index 3cf7b4eb1e046..6faf499f9a670 100644 --- a/contrib/postgres_fdw/deparse.c +++ b/contrib/postgres_fdw/deparse.c @@ -1705,13 +1705,16 @@ deparseRangeTblRef(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel, * The statement text is appended to buf, and we also create an integer List * of the columns being retrieved by WITH CHECK OPTION or RETURNING (if any), * which is returned to *retrieved_attrs. + * + * This also stores end position of the VALUES clause, so that we can rebuild + * an INSERT for a batch of rows later. */ void deparseInsertSql(StringInfo buf, RangeTblEntry *rte, Index rtindex, Relation rel, List *targetAttrs, bool doNothing, List *withCheckOptionList, List *returningList, - List **retrieved_attrs) + List **retrieved_attrs, int *values_end_len) { AttrNumber pindex; bool first; @@ -1754,6 +1757,7 @@ deparseInsertSql(StringInfo buf, RangeTblEntry *rte, } else appendStringInfoString(buf, " DEFAULT VALUES"); + *values_end_len = buf->len; if (doNothing) appendStringInfoString(buf, " ON CONFLICT DO NOTHING"); @@ -1763,6 +1767,54 @@ deparseInsertSql(StringInfo buf, RangeTblEntry *rte, withCheckOptionList, returningList, retrieved_attrs); } +/* + * rebuild remote INSERT statement + * + * Provided a number of rows in a batch, builds INSERT statement with the + * right number of parameters. + */ +void +rebuildInsertSql(StringInfo buf, char *orig_query, + int values_end_len, int num_cols, + int num_rows) +{ + int i, j; + int pindex; + bool first; + + /* Make sure the values_end_len is sensible */ + Assert((values_end_len > 0) && (values_end_len <= strlen(orig_query))); + + /* Copy up to the end of the first record from the original query */ + appendBinaryStringInfo(buf, orig_query, values_end_len); + + /* + * Add records to VALUES clause (we already have parameters for the + * first row, so start at the right offset). + */ + pindex = num_cols + 1; + for (i = 0; i < num_rows; i++) + { + appendStringInfoString(buf, ", ("); + + first = true; + for (j = 0; j < num_cols; j++) + { + if (!first) + appendStringInfoString(buf, ", "); + first = false; + + appendStringInfo(buf, "$%d", pindex); + pindex++; + } + + appendStringInfoChar(buf, ')'); + } + + /* Copy stuff after VALUES clause from the original query */ + appendStringInfoString(buf, orig_query + values_end_len); +} + /* * deparse remote UPDATE statement * diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index 1cad311436498..b4a04d2c1432d 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -3887,9 +3887,10 @@ EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st7; ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Insert on public.ft1 Remote SQL: INSERT INTO "S 1"."T 1"("C 1", c2, c3, c4, c5, c6, c7, c8) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) + Batch Size: 1 -> Result Output: NULL::integer, 1001, 101, 'foo'::text, NULL::timestamp with time zone, NULL::timestamp without time zone, NULL::character varying, 'ft1 '::character(10), NULL::user_enum -(4 rows) +(5 rows) ALTER TABLE "S 1"."T 1" RENAME TO "T 0"; ALTER FOREIGN TABLE ft1 OPTIONS (SET table_name 'T 0'); @@ -3920,9 +3921,10 @@ EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st7; ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Insert on public.ft1 Remote SQL: INSERT INTO "S 1"."T 0"("C 1", c2, c3, c4, c5, c6, c7, c8) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) + Batch Size: 1 -> Result Output: NULL::integer, 1001, 101, 'foo'::text, NULL::timestamp with time zone, NULL::timestamp without time zone, NULL::character varying, 'ft1 '::character(10), NULL::user_enum -(4 rows) +(5 rows) ALTER TABLE "S 1"."T 0" RENAME TO "T 1"; ALTER FOREIGN TABLE ft1 OPTIONS (SET table_name 'T 1'); @@ -4244,12 +4246,13 @@ INSERT INTO ft2 (c1,c2,c3) SELECT c1+1000,c2+100, c3 || c3 FROM ft2 LIMIT 20; -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Insert on public.ft2 Remote SQL: INSERT INTO "S 1"."T 1"("C 1", c2, c3, c4, c5, c6, c7, c8) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) + Batch Size: 1 -> Subquery Scan on "*SELECT*" Output: "*SELECT*"."?column?", "*SELECT*"."?column?_1", NULL::integer, "*SELECT*"."?column?_2", NULL::timestamp with time zone, NULL::timestamp without time zone, NULL::character varying, 'ft2 '::character(10), NULL::user_enum -> Foreign Scan on public.ft2 ft2_1 Output: (ft2_1.c1 + 1000), (ft2_1.c2 + 100), (ft2_1.c3 || ft2_1.c3) Remote SQL: SELECT "C 1", c2, c3 FROM "S 1"."T 1" LIMIT 20::bigint -(7 rows) +(8 rows) INSERT INTO ft2 (c1,c2,c3) SELECT c1+1000,c2+100, c3 || c3 FROM ft2 LIMIT 20; INSERT INTO ft2 (c1,c2,c3) @@ -5360,9 +5363,10 @@ INSERT INTO ft2 (c1,c2,c3) VALUES (1200,999,'foo') RETURNING tableoid::regclass; Insert on public.ft2 Output: (ft2.tableoid)::regclass Remote SQL: INSERT INTO "S 1"."T 1"("C 1", c2, c3, c4, c5, c6, c7, c8) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) + Batch Size: 1 -> Result Output: 1200, 999, NULL::integer, 'foo'::text, NULL::timestamp with time zone, NULL::timestamp without time zone, NULL::character varying, 'ft2 '::character(10), NULL::user_enum -(5 rows) +(6 rows) INSERT INTO ft2 (c1,c2,c3) VALUES (1200,999,'foo') RETURNING tableoid::regclass; tableoid @@ -6212,9 +6216,10 @@ INSERT INTO rw_view VALUES (0, 5); -------------------------------------------------------------------------------- Insert on public.foreign_tbl Remote SQL: INSERT INTO public.base_tbl(a, b) VALUES ($1, $2) RETURNING a, b + Batch Size: 1 -> Result Output: 0, 5 -(4 rows) +(5 rows) INSERT INTO rw_view VALUES (0, 5); -- should fail ERROR: new row violates check option for view "rw_view" @@ -6225,9 +6230,10 @@ INSERT INTO rw_view VALUES (0, 15); -------------------------------------------------------------------------------- Insert on public.foreign_tbl Remote SQL: INSERT INTO public.base_tbl(a, b) VALUES ($1, $2) RETURNING a, b + Batch Size: 1 -> Result Output: 0, 15 -(4 rows) +(5 rows) INSERT INTO rw_view VALUES (0, 15); -- ok SELECT * FROM foreign_tbl; @@ -8923,7 +8929,7 @@ DO $d$ END; $d$; ERROR: invalid option "password" -HINT: Valid options in this context are: service, passfile, channel_binding, connect_timeout, dbname, host, hostaddr, port, options, application_name, keepalives, keepalives_idle, keepalives_interval, keepalives_count, tcp_user_timeout, sslmode, sslcompression, sslcert, sslkey, sslrootcert, sslcrl, requirepeer, ssl_min_protocol_version, ssl_max_protocol_version, gssencmode, krbsrvname, gsslib, target_session_attrs, use_remote_estimate, fdw_startup_cost, fdw_tuple_cost, extensions, updatable, fetch_size +HINT: Valid options in this context are: service, passfile, channel_binding, connect_timeout, dbname, host, hostaddr, port, options, application_name, keepalives, keepalives_idle, keepalives_interval, keepalives_count, tcp_user_timeout, sslmode, sslcompression, sslcert, sslkey, sslrootcert, sslcrl, requirepeer, ssl_min_protocol_version, ssl_max_protocol_version, gssencmode, krbsrvname, gsslib, target_session_attrs, use_remote_estimate, fdw_startup_cost, fdw_tuple_cost, extensions, updatable, fetch_size, batch_size CONTEXT: SQL statement "ALTER SERVER loopback_nopw OPTIONS (ADD password 'dummypw')" PL/pgSQL function inline_code_block line 3 at EXECUTE -- If we add a password for our user mapping instead, we should get a different @@ -9112,3 +9118,138 @@ SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; loopback2 | t (1 row) +-- =================================================================== +-- batch insert +-- =================================================================== +BEGIN; +CREATE SERVER batch10 FOREIGN DATA WRAPPER postgres_fdw OPTIONS( batch_size '10' ); +SELECT count(*) +FROM pg_foreign_server +WHERE srvname = 'batch10' +AND srvoptions @> array['batch_size=10']; + count +------- + 1 +(1 row) + +ALTER SERVER batch10 OPTIONS( SET batch_size '20' ); +SELECT count(*) +FROM pg_foreign_server +WHERE srvname = 'batch10' +AND srvoptions @> array['batch_size=10']; + count +------- + 0 +(1 row) + +SELECT count(*) +FROM pg_foreign_server +WHERE srvname = 'batch10' +AND srvoptions @> array['batch_size=20']; + count +------- + 1 +(1 row) + +CREATE FOREIGN TABLE table30 ( x int ) SERVER batch10 OPTIONS ( batch_size '30' ); +SELECT COUNT(*) +FROM pg_foreign_table +WHERE ftrelid = 'table30'::regclass +AND ftoptions @> array['batch_size=30']; + count +------- + 1 +(1 row) + +ALTER FOREIGN TABLE table30 OPTIONS ( SET batch_size '40'); +SELECT COUNT(*) +FROM pg_foreign_table +WHERE ftrelid = 'table30'::regclass +AND ftoptions @> array['batch_size=30']; + count +------- + 0 +(1 row) + +SELECT COUNT(*) +FROM pg_foreign_table +WHERE ftrelid = 'table30'::regclass +AND ftoptions @> array['batch_size=40']; + count +------- + 1 +(1 row) + +ROLLBACK; +CREATE TABLE batch_table ( x int ); +CREATE FOREIGN TABLE ftable ( x int ) SERVER loopback OPTIONS ( table_name 'batch_table', batch_size '10' ); +EXPLAIN (VERBOSE, COSTS OFF) INSERT INTO ftable SELECT * FROM generate_series(1, 10) i; + QUERY PLAN +------------------------------------------------------------- + Insert on public.ftable + Remote SQL: INSERT INTO public.batch_table(x) VALUES ($1) + Batch Size: 10 + -> Function Scan on pg_catalog.generate_series i + Output: i.i + Function Call: generate_series(1, 10) +(6 rows) + +INSERT INTO ftable SELECT * FROM generate_series(1, 10) i; +INSERT INTO ftable SELECT * FROM generate_series(11, 31) i; +INSERT INTO ftable VALUES (32); +INSERT INTO ftable VALUES (33), (34); +SELECT COUNT(*) FROM ftable; + count +------- + 34 +(1 row) + +TRUNCATE batch_table; +DROP FOREIGN TABLE ftable; +-- Disable batch insert +CREATE FOREIGN TABLE ftable ( x int ) SERVER loopback OPTIONS ( table_name 'batch_table', batch_size '1' ); +EXPLAIN (VERBOSE, COSTS OFF) INSERT INTO ftable VALUES (1), (2); + QUERY PLAN +------------------------------------------------------------- + Insert on public.ftable + Remote SQL: INSERT INTO public.batch_table(x) VALUES ($1) + Batch Size: 1 + -> Values Scan on "*VALUES*" + Output: "*VALUES*".column1 +(5 rows) + +INSERT INTO ftable VALUES (1), (2); +SELECT COUNT(*) FROM ftable; + count +------- + 2 +(1 row) + +DROP FOREIGN TABLE ftable; +DROP TABLE batch_table; +-- Use partitioning +CREATE TABLE batch_table ( x int ) PARTITION BY HASH (x); +CREATE TABLE batch_table_p0 (LIKE batch_table); +CREATE FOREIGN TABLE batch_table_p0f + PARTITION OF batch_table + FOR VALUES WITH (MODULUS 3, REMAINDER 0) + SERVER loopback + OPTIONS (table_name 'batch_table_p0', batch_size '10'); +CREATE TABLE batch_table_p1 (LIKE batch_table); +CREATE FOREIGN TABLE batch_table_p1f + PARTITION OF batch_table + FOR VALUES WITH (MODULUS 3, REMAINDER 1) + SERVER loopback + OPTIONS (table_name 'batch_table_p1', batch_size '1'); +CREATE TABLE batch_table_p2 + PARTITION OF batch_table + FOR VALUES WITH (MODULUS 3, REMAINDER 2); +INSERT INTO batch_table SELECT * FROM generate_series(1, 66) i; +SELECT COUNT(*) FROM batch_table; + count +------- + 66 +(1 row) + +-- Clean up +DROP TABLE batch_table CASCADE; diff --git a/contrib/postgres_fdw/option.c b/contrib/postgres_fdw/option.c index 1fec3c3eeac61..64698c4da3a50 100644 --- a/contrib/postgres_fdw/option.c +++ b/contrib/postgres_fdw/option.c @@ -142,6 +142,17 @@ postgres_fdw_validator(PG_FUNCTION_ARGS) errmsg("%s requires a non-negative integer value", def->defname))); } + else if (strcmp(def->defname, "batch_size") == 0) + { + int batch_size; + + batch_size = strtol(defGetString(def), NULL, 10); + if (batch_size <= 0) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("%s requires a non-negative integer value", + def->defname))); + } else if (strcmp(def->defname, "password_required") == 0) { bool pw_required = defGetBoolean(def); @@ -203,6 +214,9 @@ InitPgFdwOptions(void) /* fetch_size is available on both server and table */ {"fetch_size", ForeignServerRelationId, false}, {"fetch_size", ForeignTableRelationId, false}, + /* batch_size is available on both server and table */ + {"batch_size", ForeignServerRelationId, false}, + {"batch_size", ForeignTableRelationId, false}, {"password_required", UserMappingRelationId, false}, /* diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index 2f2d4d171c18b..9a31bbb86b2ac 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -87,8 +87,10 @@ enum FdwScanPrivateIndex * 1) INSERT/UPDATE/DELETE statement text to be sent to the remote server * 2) Integer list of target attribute numbers for INSERT/UPDATE * (NIL for a DELETE) - * 3) Boolean flag showing if the remote query has a RETURNING clause - * 4) Integer list of attribute numbers retrieved by RETURNING, if any + * 3) Length till the end of VALUES clause for INSERT + * (-1 for a DELETE/UPDATE) + * 4) Boolean flag showing if the remote query has a RETURNING clause + * 5) Integer list of attribute numbers retrieved by RETURNING, if any */ enum FdwModifyPrivateIndex { @@ -96,6 +98,8 @@ enum FdwModifyPrivateIndex FdwModifyPrivateUpdateSql, /* Integer list of target attribute numbers for INSERT/UPDATE */ FdwModifyPrivateTargetAttnums, + /* Length till the end of VALUES clause (as an integer Value node) */ + FdwModifyPrivateLen, /* has-returning flag (as an integer Value node) */ FdwModifyPrivateHasReturning, /* Integer list of attribute numbers retrieved by RETURNING */ @@ -176,7 +180,10 @@ typedef struct PgFdwModifyState /* extracted fdw_private data */ char *query; /* text of INSERT/UPDATE/DELETE command */ + char *orig_query; /* original text of INSERT command */ List *target_attrs; /* list of target attribute numbers */ + int values_end; /* length up to the end of VALUES */ + int batch_size; /* value of FDW option "batch_size" */ bool has_returning; /* is there a RETURNING clause? */ List *retrieved_attrs; /* attr numbers retrieved by RETURNING */ @@ -185,6 +192,9 @@ typedef struct PgFdwModifyState int p_nums; /* number of parameters to transmit */ FmgrInfo *p_flinfo; /* output conversion functions for them */ + /* batch operation stuff */ + int num_slots; /* number of slots to insert */ + /* working memory context */ MemoryContext temp_cxt; /* context for per-tuple temporary data */ @@ -343,6 +353,12 @@ static TupleTableSlot *postgresExecForeignInsert(EState *estate, ResultRelInfo *resultRelInfo, TupleTableSlot *slot, TupleTableSlot *planSlot); +static TupleTableSlot **postgresExecForeignBatchInsert(EState *estate, + ResultRelInfo *resultRelInfo, + TupleTableSlot **slots, + TupleTableSlot **planSlots, + int *numSlots); +static int postgresGetForeignModifyBatchSize(ResultRelInfo *resultRelInfo); static TupleTableSlot *postgresExecForeignUpdate(EState *estate, ResultRelInfo *resultRelInfo, TupleTableSlot *slot, @@ -429,20 +445,24 @@ static PgFdwModifyState *create_foreign_modify(EState *estate, Plan *subplan, char *query, List *target_attrs, + int len, bool has_returning, List *retrieved_attrs); -static TupleTableSlot *execute_foreign_modify(EState *estate, +static TupleTableSlot **execute_foreign_modify(EState *estate, ResultRelInfo *resultRelInfo, CmdType operation, - TupleTableSlot *slot, - TupleTableSlot *planSlot); + TupleTableSlot **slots, + TupleTableSlot **planSlots, + int *numSlots); static void prepare_foreign_modify(PgFdwModifyState *fmstate); static const char **convert_prep_stmt_params(PgFdwModifyState *fmstate, ItemPointer tupleid, - TupleTableSlot *slot); + TupleTableSlot **slots, + int numSlots); static void store_returning_result(PgFdwModifyState *fmstate, TupleTableSlot *slot, PGresult *res); static void finish_foreign_modify(PgFdwModifyState *fmstate); +static void deallocate_query(PgFdwModifyState *fmstate); static List *build_remote_returning(Index rtindex, Relation rel, List *returningList); static void rebuild_fdw_scan_tlist(ForeignScan *fscan, List *tlist); @@ -505,6 +525,7 @@ static void apply_table_options(PgFdwRelationInfo *fpinfo); static void merge_fdw_options(PgFdwRelationInfo *fpinfo, const PgFdwRelationInfo *fpinfo_o, const PgFdwRelationInfo *fpinfo_i); +static int get_batch_size_option(Relation rel); /* @@ -530,6 +551,8 @@ postgres_fdw_handler(PG_FUNCTION_ARGS) routine->PlanForeignModify = postgresPlanForeignModify; routine->BeginForeignModify = postgresBeginForeignModify; routine->ExecForeignInsert = postgresExecForeignInsert; + routine->ExecForeignBatchInsert = postgresExecForeignBatchInsert; + routine->GetForeignModifyBatchSize = postgresGetForeignModifyBatchSize; routine->ExecForeignUpdate = postgresExecForeignUpdate; routine->ExecForeignDelete = postgresExecForeignDelete; routine->EndForeignModify = postgresEndForeignModify; @@ -1665,6 +1688,7 @@ postgresPlanForeignModify(PlannerInfo *root, List *returningList = NIL; List *retrieved_attrs = NIL; bool doNothing = false; + int values_end_len = -1; initStringInfo(&sql); @@ -1752,7 +1776,7 @@ postgresPlanForeignModify(PlannerInfo *root, deparseInsertSql(&sql, rte, resultRelation, rel, targetAttrs, doNothing, withCheckOptionList, returningList, - &retrieved_attrs); + &retrieved_attrs, &values_end_len); break; case CMD_UPDATE: deparseUpdateSql(&sql, rte, resultRelation, rel, @@ -1776,8 +1800,9 @@ postgresPlanForeignModify(PlannerInfo *root, * Build the fdw_private list that will be available to the executor. * Items in the list must match enum FdwModifyPrivateIndex, above. */ - return list_make4(makeString(sql.data), + return list_make5(makeString(sql.data), targetAttrs, + makeInteger(values_end_len), makeInteger((retrieved_attrs != NIL)), retrieved_attrs); } @@ -1797,6 +1822,7 @@ postgresBeginForeignModify(ModifyTableState *mtstate, char *query; List *target_attrs; bool has_returning; + int values_end_len; List *retrieved_attrs; RangeTblEntry *rte; @@ -1812,6 +1838,8 @@ postgresBeginForeignModify(ModifyTableState *mtstate, FdwModifyPrivateUpdateSql)); target_attrs = (List *) list_nth(fdw_private, FdwModifyPrivateTargetAttnums); + values_end_len = intVal(list_nth(fdw_private, + FdwModifyPrivateLen)); has_returning = intVal(list_nth(fdw_private, FdwModifyPrivateHasReturning)); retrieved_attrs = (List *) list_nth(fdw_private, @@ -1829,6 +1857,7 @@ postgresBeginForeignModify(ModifyTableState *mtstate, mtstate->mt_plans[subplan_index]->plan, query, target_attrs, + values_end_len, has_returning, retrieved_attrs); @@ -1846,7 +1875,37 @@ postgresExecForeignInsert(EState *estate, TupleTableSlot *planSlot) { PgFdwModifyState *fmstate = (PgFdwModifyState *) resultRelInfo->ri_FdwState; - TupleTableSlot *rslot; + TupleTableSlot **rslot; + int numSlots = 1; + + /* + * If the fmstate has aux_fmstate set, use the aux_fmstate (see + * postgresBeginForeignInsert()) + */ + if (fmstate->aux_fmstate) + resultRelInfo->ri_FdwState = fmstate->aux_fmstate; + rslot = execute_foreign_modify(estate, resultRelInfo, CMD_INSERT, + &slot, &planSlot, &numSlots); + /* Revert that change */ + if (fmstate->aux_fmstate) + resultRelInfo->ri_FdwState = fmstate; + + return rslot ? *rslot : NULL; +} + +/* + * postgresExecForeignBatchInsert + * Insert multiple rows into a foreign table + */ +static TupleTableSlot ** +postgresExecForeignBatchInsert(EState *estate, + ResultRelInfo *resultRelInfo, + TupleTableSlot **slots, + TupleTableSlot **planSlots, + int *numSlots) +{ + PgFdwModifyState *fmstate = (PgFdwModifyState *) resultRelInfo->ri_FdwState; + TupleTableSlot **rslot; /* * If the fmstate has aux_fmstate set, use the aux_fmstate (see @@ -1855,7 +1914,7 @@ postgresExecForeignInsert(EState *estate, if (fmstate->aux_fmstate) resultRelInfo->ri_FdwState = fmstate->aux_fmstate; rslot = execute_foreign_modify(estate, resultRelInfo, CMD_INSERT, - slot, planSlot); + slots, planSlots, numSlots); /* Revert that change */ if (fmstate->aux_fmstate) resultRelInfo->ri_FdwState = fmstate; @@ -1863,6 +1922,42 @@ postgresExecForeignInsert(EState *estate, return rslot; } +/* + * postgresGetForeignModifyBatchSize + * Determine the maximum number of tuples that can be inserted in bulk + * + * Returns the batch size specified for server or table. When batching is not + * allowed (e.g. for tables with AFTER ROW triggers or with RETURNING clause), + * returns 1. + */ +static int +postgresGetForeignModifyBatchSize(ResultRelInfo *resultRelInfo) +{ + int batch_size; + + /* should be called only once */ + Assert(resultRelInfo->ri_BatchSize == 0); + + /* + * In EXPLAIN without ANALYZE, ri_fdwstate is NULL, so we have to lookup + * the option directly in server/table options. Otherwise just use the + * value we determined earlier. + */ + if (resultRelInfo->ri_FdwState) + batch_size = ((PgFdwModifyState *) resultRelInfo->ri_FdwState)->batch_size; + else + batch_size = get_batch_size_option(resultRelInfo->ri_RelationDesc); + + /* Disable batching when we have to use RETURNING. */ + if (resultRelInfo->ri_projectReturning != NULL || + (resultRelInfo->ri_TrigDesc && + resultRelInfo->ri_TrigDesc->trig_insert_after_row)) + return 1; + + /* Otherwise use the batch size specified for server/table. */ + return batch_size; +} + /* * postgresExecForeignUpdate * Update one row in a foreign table @@ -1873,8 +1968,13 @@ postgresExecForeignUpdate(EState *estate, TupleTableSlot *slot, TupleTableSlot *planSlot) { - return execute_foreign_modify(estate, resultRelInfo, CMD_UPDATE, - slot, planSlot); + TupleTableSlot **rslot; + int numSlots = 1; + + rslot = execute_foreign_modify(estate, resultRelInfo, CMD_UPDATE, + &slot, &planSlot, &numSlots); + + return rslot ? rslot[0] : NULL; } /* @@ -1887,8 +1987,13 @@ postgresExecForeignDelete(EState *estate, TupleTableSlot *slot, TupleTableSlot *planSlot) { - return execute_foreign_modify(estate, resultRelInfo, CMD_DELETE, - slot, planSlot); + TupleTableSlot **rslot; + int numSlots = 1; + + rslot = execute_foreign_modify(estate, resultRelInfo, CMD_DELETE, + &slot, &planSlot, &numSlots); + + return rslot ? rslot[0] : NULL; } /* @@ -1925,6 +2030,7 @@ postgresBeginForeignInsert(ModifyTableState *mtstate, RangeTblEntry *rte; TupleDesc tupdesc = RelationGetDescr(rel); int attnum; + int values_end_len; StringInfoData sql; List *targetAttrs = NIL; List *retrieved_attrs = NIL; @@ -2001,7 +2107,7 @@ postgresBeginForeignInsert(ModifyTableState *mtstate, deparseInsertSql(&sql, rte, resultRelation, rel, targetAttrs, doNothing, resultRelInfo->ri_WithCheckOptions, resultRelInfo->ri_returningList, - &retrieved_attrs); + &retrieved_attrs, &values_end_len); /* Construct an execution state. */ fmstate = create_foreign_modify(mtstate->ps.state, @@ -2011,6 +2117,7 @@ postgresBeginForeignInsert(ModifyTableState *mtstate, NULL, sql.data, targetAttrs, + values_end_len, retrieved_attrs != NIL, retrieved_attrs); @@ -2636,6 +2743,13 @@ postgresExplainForeignModify(ModifyTableState *mtstate, FdwModifyPrivateUpdateSql)); ExplainPropertyText("Remote SQL", sql, es); + + /* + * For INSERT we should always have batch size >= 1, but UPDATE + * and DELETE don't support batching so don't show the property. + */ + if (rinfo->ri_BatchSize > 0) + ExplainPropertyInteger("Batch Size", NULL, rinfo->ri_BatchSize, es); } } @@ -3530,6 +3644,7 @@ create_foreign_modify(EState *estate, Plan *subplan, char *query, List *target_attrs, + int values_end, bool has_returning, List *retrieved_attrs) { @@ -3564,7 +3679,10 @@ create_foreign_modify(EState *estate, /* Set up remote query information. */ fmstate->query = query; + if (operation == CMD_INSERT) + fmstate->orig_query = pstrdup(fmstate->query); fmstate->target_attrs = target_attrs; + fmstate->values_end = values_end; fmstate->has_returning = has_returning; fmstate->retrieved_attrs = retrieved_attrs; @@ -3616,6 +3734,12 @@ create_foreign_modify(EState *estate, Assert(fmstate->p_nums <= n_params); + /* Set batch_size from foreign server/table options. */ + if (operation == CMD_INSERT) + fmstate->batch_size = get_batch_size_option(rel); + + fmstate->num_slots = 1; + /* Initialize auxiliary state */ fmstate->aux_fmstate = NULL; @@ -3626,26 +3750,48 @@ create_foreign_modify(EState *estate, * execute_foreign_modify * Perform foreign-table modification as required, and fetch RETURNING * result if any. (This is the shared guts of postgresExecForeignInsert, - * postgresExecForeignUpdate, and postgresExecForeignDelete.) + * postgresExecForeignBatchInsert, postgresExecForeignUpdate, and + * postgresExecForeignDelete.) */ -static TupleTableSlot * +static TupleTableSlot ** execute_foreign_modify(EState *estate, ResultRelInfo *resultRelInfo, CmdType operation, - TupleTableSlot *slot, - TupleTableSlot *planSlot) + TupleTableSlot **slots, + TupleTableSlot **planSlots, + int *numSlots) { PgFdwModifyState *fmstate = (PgFdwModifyState *) resultRelInfo->ri_FdwState; ItemPointer ctid = NULL; const char **p_values; PGresult *res; int n_rows; + StringInfoData sql; /* The operation should be INSERT, UPDATE, or DELETE */ Assert(operation == CMD_INSERT || operation == CMD_UPDATE || operation == CMD_DELETE); + /* + * If the existing query was deparsed and prepared for a different number + * of rows, rebuild it for the proper number. + */ + if (operation == CMD_INSERT && fmstate->num_slots != *numSlots) + { + /* Destroy the prepared statement created previously */ + if (fmstate->p_name) + deallocate_query(fmstate); + + /* Build INSERT string with numSlots records in its VALUES clause. */ + initStringInfo(&sql); + rebuildInsertSql(&sql, fmstate->orig_query, fmstate->values_end, + fmstate->p_nums, *numSlots - 1); + pfree(fmstate->query); + fmstate->query = sql.data; + fmstate->num_slots = *numSlots; + } + /* Set up the prepared statement on the remote server, if we didn't yet */ if (!fmstate->p_name) prepare_foreign_modify(fmstate); @@ -3658,7 +3804,7 @@ execute_foreign_modify(EState *estate, Datum datum; bool isNull; - datum = ExecGetJunkAttribute(planSlot, + datum = ExecGetJunkAttribute(planSlots[0], fmstate->ctidAttno, &isNull); /* shouldn't ever get a null result... */ @@ -3668,14 +3814,14 @@ execute_foreign_modify(EState *estate, } /* Convert parameters needed by prepared statement to text form */ - p_values = convert_prep_stmt_params(fmstate, ctid, slot); + p_values = convert_prep_stmt_params(fmstate, ctid, slots, *numSlots); /* * Execute the prepared statement. */ if (!PQsendQueryPrepared(fmstate->conn, fmstate->p_name, - fmstate->p_nums, + fmstate->p_nums * (*numSlots), p_values, NULL, NULL, @@ -3696,9 +3842,10 @@ execute_foreign_modify(EState *estate, /* Check number of rows affected, and fetch RETURNING tuple if any */ if (fmstate->has_returning) { + Assert(*numSlots == 1); n_rows = PQntuples(res); if (n_rows > 0) - store_returning_result(fmstate, slot, res); + store_returning_result(fmstate, slots[0], res); } else n_rows = atoi(PQcmdTuples(res)); @@ -3708,10 +3855,12 @@ execute_foreign_modify(EState *estate, MemoryContextReset(fmstate->temp_cxt); + *numSlots = n_rows; + /* * Return NULL if nothing was inserted/updated/deleted on the remote end */ - return (n_rows > 0) ? slot : NULL; + return (n_rows > 0) ? slots : NULL; } /* @@ -3771,52 +3920,64 @@ prepare_foreign_modify(PgFdwModifyState *fmstate) static const char ** convert_prep_stmt_params(PgFdwModifyState *fmstate, ItemPointer tupleid, - TupleTableSlot *slot) + TupleTableSlot **slots, + int numSlots) { const char **p_values; + int i; + int j; int pindex = 0; MemoryContext oldcontext; oldcontext = MemoryContextSwitchTo(fmstate->temp_cxt); - p_values = (const char **) palloc(sizeof(char *) * fmstate->p_nums); + p_values = (const char **) palloc(sizeof(char *) * fmstate->p_nums * numSlots); + + /* ctid is provided only for UPDATE/DELETE, which don't allow batching */ + Assert(!(tupleid != NULL && numSlots > 1)); /* 1st parameter should be ctid, if it's in use */ if (tupleid != NULL) { + Assert(numSlots == 1); /* don't need set_transmission_modes for TID output */ p_values[pindex] = OutputFunctionCall(&fmstate->p_flinfo[pindex], PointerGetDatum(tupleid)); pindex++; } - /* get following parameters from slot */ - if (slot != NULL && fmstate->target_attrs != NIL) + /* get following parameters from slots */ + if (slots != NULL && fmstate->target_attrs != NIL) { int nestlevel; ListCell *lc; nestlevel = set_transmission_modes(); - foreach(lc, fmstate->target_attrs) + for (i = 0; i < numSlots; i++) { - int attnum = lfirst_int(lc); - Datum value; - bool isnull; + j = (tupleid != NULL) ? 1 : 0; + foreach(lc, fmstate->target_attrs) + { + int attnum = lfirst_int(lc); + Datum value; + bool isnull; - value = slot_getattr(slot, attnum, &isnull); - if (isnull) - p_values[pindex] = NULL; - else - p_values[pindex] = OutputFunctionCall(&fmstate->p_flinfo[pindex], - value); - pindex++; + value = slot_getattr(slots[i], attnum, &isnull); + if (isnull) + p_values[pindex] = NULL; + else + p_values[pindex] = OutputFunctionCall(&fmstate->p_flinfo[j], + value); + pindex++; + j++; + } } reset_transmission_modes(nestlevel); } - Assert(pindex == fmstate->p_nums); + Assert(pindex == fmstate->p_nums * numSlots); MemoryContextSwitchTo(oldcontext); @@ -3870,29 +4031,41 @@ finish_foreign_modify(PgFdwModifyState *fmstate) Assert(fmstate != NULL); /* If we created a prepared statement, destroy it */ - if (fmstate->p_name) - { - char sql[64]; - PGresult *res; - - snprintf(sql, sizeof(sql), "DEALLOCATE %s", fmstate->p_name); - - /* - * We don't use a PG_TRY block here, so be careful not to throw error - * without releasing the PGresult. - */ - res = pgfdw_exec_query(fmstate->conn, sql); - if (PQresultStatus(res) != PGRES_COMMAND_OK) - pgfdw_report_error(ERROR, res, fmstate->conn, true, sql); - PQclear(res); - fmstate->p_name = NULL; - } + deallocate_query(fmstate); /* Release remote connection */ ReleaseConnection(fmstate->conn); fmstate->conn = NULL; } +/* + * deallocate_query + * Deallocate a prepared statement for a foreign insert/update/delete + * operation + */ +static void +deallocate_query(PgFdwModifyState *fmstate) +{ + char sql[64]; + PGresult *res; + + /* do nothing if the query is not allocated */ + if (!fmstate->p_name) + return; + + snprintf(sql, sizeof(sql), "DEALLOCATE %s", fmstate->p_name); + + /* + * We don't use a PG_TRY block here, so be careful not to throw error + * without releasing the PGresult. + */ + res = pgfdw_exec_query(fmstate->conn, sql); + if (PQresultStatus(res) != PGRES_COMMAND_OK) + pgfdw_report_error(ERROR, res, fmstate->conn, true, sql); + PQclear(res); + fmstate->p_name = NULL; +} + /* * build_remote_returning * Build a RETURNING targetlist of a remote query for performing an @@ -6577,3 +6750,45 @@ find_em_expr_for_input_target(PlannerInfo *root, elog(ERROR, "could not find pathkey item to sort"); return NULL; /* keep compiler quiet */ } + +/* + * Determine batch size for a given foreign table. The option specified for + * a table has precedence. + */ +static int +get_batch_size_option(Relation rel) +{ + Oid foreigntableid = RelationGetRelid(rel); + ForeignTable *table; + ForeignServer *server; + List *options; + ListCell *lc; + + /* we use 1 by default, which means "no batching" */ + int batch_size = 1; + + /* + * Load options for table and server. We append server options after + * table options, because table options take precedence. + */ + table = GetForeignTable(foreigntableid); + server = GetForeignServer(table->serverid); + + options = NIL; + options = list_concat(options, table->options); + options = list_concat(options, server->options); + + /* See if either table or server specifies batch_size. */ + foreach(lc, options) + { + DefElem *def = (DefElem *) lfirst(lc); + + if (strcmp(def->defname, "batch_size") == 0) + { + batch_size = strtol(defGetString(def), NULL, 10); + break; + } + } + + return batch_size; +} diff --git a/contrib/postgres_fdw/postgres_fdw.h b/contrib/postgres_fdw/postgres_fdw.h index 19ea27a1bcdd0..1f67b4d9fd27f 100644 --- a/contrib/postgres_fdw/postgres_fdw.h +++ b/contrib/postgres_fdw/postgres_fdw.h @@ -161,7 +161,10 @@ extern void deparseInsertSql(StringInfo buf, RangeTblEntry *rte, Index rtindex, Relation rel, List *targetAttrs, bool doNothing, List *withCheckOptionList, List *returningList, - List **retrieved_attrs); + List **retrieved_attrs, int *values_end_len); +extern void rebuildInsertSql(StringInfo buf, char *orig_query, + int values_end_len, int num_cols, + int num_rows); extern void deparseUpdateSql(StringInfo buf, RangeTblEntry *rte, Index rtindex, Relation rel, List *targetAttrs, diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql index ebf6eb10a6167..28b82f5f9dc0c 100644 --- a/contrib/postgres_fdw/sql/postgres_fdw.sql +++ b/contrib/postgres_fdw/sql/postgres_fdw.sql @@ -2738,3 +2738,96 @@ COMMIT; -- should not be output because they should be closed at the end of -- the above transaction. SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; + +-- =================================================================== +-- batch insert +-- =================================================================== + +BEGIN; + +CREATE SERVER batch10 FOREIGN DATA WRAPPER postgres_fdw OPTIONS( batch_size '10' ); + +SELECT count(*) +FROM pg_foreign_server +WHERE srvname = 'batch10' +AND srvoptions @> array['batch_size=10']; + +ALTER SERVER batch10 OPTIONS( SET batch_size '20' ); + +SELECT count(*) +FROM pg_foreign_server +WHERE srvname = 'batch10' +AND srvoptions @> array['batch_size=10']; + +SELECT count(*) +FROM pg_foreign_server +WHERE srvname = 'batch10' +AND srvoptions @> array['batch_size=20']; + +CREATE FOREIGN TABLE table30 ( x int ) SERVER batch10 OPTIONS ( batch_size '30' ); + +SELECT COUNT(*) +FROM pg_foreign_table +WHERE ftrelid = 'table30'::regclass +AND ftoptions @> array['batch_size=30']; + +ALTER FOREIGN TABLE table30 OPTIONS ( SET batch_size '40'); + +SELECT COUNT(*) +FROM pg_foreign_table +WHERE ftrelid = 'table30'::regclass +AND ftoptions @> array['batch_size=30']; + +SELECT COUNT(*) +FROM pg_foreign_table +WHERE ftrelid = 'table30'::regclass +AND ftoptions @> array['batch_size=40']; + +ROLLBACK; + +CREATE TABLE batch_table ( x int ); + +CREATE FOREIGN TABLE ftable ( x int ) SERVER loopback OPTIONS ( table_name 'batch_table', batch_size '10' ); +EXPLAIN (VERBOSE, COSTS OFF) INSERT INTO ftable SELECT * FROM generate_series(1, 10) i; +INSERT INTO ftable SELECT * FROM generate_series(1, 10) i; +INSERT INTO ftable SELECT * FROM generate_series(11, 31) i; +INSERT INTO ftable VALUES (32); +INSERT INTO ftable VALUES (33), (34); +SELECT COUNT(*) FROM ftable; +TRUNCATE batch_table; +DROP FOREIGN TABLE ftable; + +-- Disable batch insert +CREATE FOREIGN TABLE ftable ( x int ) SERVER loopback OPTIONS ( table_name 'batch_table', batch_size '1' ); +EXPLAIN (VERBOSE, COSTS OFF) INSERT INTO ftable VALUES (1), (2); +INSERT INTO ftable VALUES (1), (2); +SELECT COUNT(*) FROM ftable; +DROP FOREIGN TABLE ftable; +DROP TABLE batch_table; + +-- Use partitioning +CREATE TABLE batch_table ( x int ) PARTITION BY HASH (x); + +CREATE TABLE batch_table_p0 (LIKE batch_table); +CREATE FOREIGN TABLE batch_table_p0f + PARTITION OF batch_table + FOR VALUES WITH (MODULUS 3, REMAINDER 0) + SERVER loopback + OPTIONS (table_name 'batch_table_p0', batch_size '10'); + +CREATE TABLE batch_table_p1 (LIKE batch_table); +CREATE FOREIGN TABLE batch_table_p1f + PARTITION OF batch_table + FOR VALUES WITH (MODULUS 3, REMAINDER 1) + SERVER loopback + OPTIONS (table_name 'batch_table_p1', batch_size '1'); + +CREATE TABLE batch_table_p2 + PARTITION OF batch_table + FOR VALUES WITH (MODULUS 3, REMAINDER 2); + +INSERT INTO batch_table SELECT * FROM generate_series(1, 66) i; +SELECT COUNT(*) FROM batch_table; + +-- Clean up +DROP TABLE batch_table CASCADE; diff --git a/doc/src/sgml/fdwhandler.sgml b/doc/src/sgml/fdwhandler.sgml index 9c9293414c581..854913ae5fc94 100644 --- a/doc/src/sgml/fdwhandler.sgml +++ b/doc/src/sgml/fdwhandler.sgml @@ -523,8 +523,9 @@ BeginForeignModify(ModifyTableState *mtstate, Begin executing a foreign table modification operation. This routine is called during executor startup. It should perform any initialization needed prior to the actual table modifications. Subsequently, - ExecForeignInsert, ExecForeignUpdate or - ExecForeignDelete will be called for each tuple to be + ExecForeignInsert/ExecForeignBatchInsert, + ExecForeignUpdate or + ExecForeignDelete will be called for tuple(s) to be inserted, updated, or deleted. @@ -614,6 +615,81 @@ ExecForeignInsert(EState *estate, +TupleTableSlot ** +ExecForeignBatchInsert(EState *estate, + ResultRelInfo *rinfo, + TupleTableSlot **slots, + TupleTableSlot *planSlots, + int *numSlots); + + + Insert multiple tuples in bulk into the foreign table. + The parameters are the same for ExecForeignInsert + except slots and planSlots contain + multiple tuples and *numSlots> specifies the number of + tuples in those arrays. + + + + The return value is an array of slots containing the data that was + actually inserted (this might differ from the data supplied, for + example as a result of trigger actions.) + The passed-in slots can be re-used for this purpose. + The number of successfully inserted tuples is returned in + *numSlots. + + + + The data in the returned slot is used only if the INSERT + statement involves a view + WITH CHECK OPTION; or if the foreign table has + an AFTER ROW trigger. Triggers require all columns, + but the FDW could choose to optimize away returning some or all columns + depending on the contents of the + WITH CHECK OPTION constraints. + + + + If the ExecForeignBatchInsert or + GetForeignModifyBatchSize pointer is set to + NULL, attempts to insert into the foreign table will + use ExecForeignInsert. + This function is not used if the INSERT has the + RETURNING> clause. + + + + Note that this function is also called when inserting routed tuples into + a foreign-table partition. See the callback functions + described below that allow the FDW to support that. + + + + +int +GetForeignModifyBatchSize(ResultRelInfo *rinfo); + + + Report the maximum number of tuples that a single + ExecForeignBatchInsert call can handle for + the specified foreign table. That is, The executor passes at most + the number of tuples that this function returns to + ExecForeignBatchInsert. + rinfo is the ResultRelInfo struct describing + the target foreign table. + The FDW is expected to provide a foreign server and/or foreign + table option for the user to set this value, or some hard-coded value. + + + + If the ExecForeignBatchInsert or + GetForeignModifyBatchSize pointer is set to + NULL, attempts to insert into the foreign table will + use ExecForeignInsert. + + + + TupleTableSlot * ExecForeignUpdate(EState *estate, ResultRelInfo *rinfo, @@ -741,8 +817,9 @@ BeginForeignInsert(ModifyTableState *mtstate, in both cases when it is the partition chosen for tuple routing and the target specified in a COPY FROM command. It should perform any initialization needed prior to the actual insertion. - Subsequently, ExecForeignInsert will be called for - each tuple to be inserted into the foreign table. + Subsequently, ExecForeignInsert or + ExecForeignBatchInsert will be called for + tuple(s) to be inserted into the foreign table. @@ -773,8 +850,8 @@ BeginForeignInsert(ModifyTableState *mtstate, Note that if the FDW does not support routable foreign-table partitions and/or executing COPY FROM on foreign tables, this - function or ExecForeignInsert subsequently called - must throw error as needed. + function or ExecForeignInsert/ExecForeignBatchInsert + subsequently called must throw error as needed. diff --git a/doc/src/sgml/postgres-fdw.sgml b/doc/src/sgml/postgres-fdw.sgml index 9adc8d12a9dd0..fb4c22ac69f9f 100644 --- a/doc/src/sgml/postgres-fdw.sgml +++ b/doc/src/sgml/postgres-fdw.sgml @@ -354,6 +354,19 @@ OPTIONS (ADD password_required 'false'); + + batch_size + + + This option specifies the number of rows postgres_fdw + should insert in each insert operation. It can be specified for a + foreign table or a foreign server. The option specified on a table + overrides an option specified for the server. + The default is 1. + + + + diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index 941731a0a9b73..1746cb87936ce 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -993,6 +993,23 @@ ExecInitRoutingInfo(ModifyTableState *mtstate, partRelInfo->ri_FdwRoutine->BeginForeignInsert != NULL) partRelInfo->ri_FdwRoutine->BeginForeignInsert(mtstate, partRelInfo); + /* + * Determine if the FDW supports batch insert and determine the batch + * size (a FDW may support batching, but it may be disabled for the + * server/table or for this particular query). + * + * If the FDW does not support batching, we set the batch size to 1. + */ + if (partRelInfo->ri_FdwRoutine != NULL && + partRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize && + partRelInfo->ri_FdwRoutine->ExecForeignBatchInsert) + partRelInfo->ri_BatchSize = + partRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize(partRelInfo); + else + partRelInfo->ri_BatchSize = 1; + + Assert(partRelInfo->ri_BatchSize >= 1); + partRelInfo->ri_CopyMultiInsertBuffer = NULL; /* diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 921e6954194ea..9c36860704aad 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -58,6 +58,13 @@ #include "utils/rel.h" +static void ExecBatchInsert(ModifyTableState *mtstate, + ResultRelInfo *resultRelInfo, + TupleTableSlot **slots, + TupleTableSlot **planSlots, + int numSlots, + EState *estate, + bool canSetTag); static bool ExecOnConflictUpdate(ModifyTableState *mtstate, ResultRelInfo *resultRelInfo, ItemPointer conflictTid, @@ -389,6 +396,7 @@ ExecInsert(ModifyTableState *mtstate, ModifyTable *node = (ModifyTable *) mtstate->ps.plan; OnConflictAction onconflict = node->onConflictAction; PartitionTupleRouting *proute = mtstate->mt_partition_tuple_routing; + MemoryContext oldContext; /* * If the input result relation is a partitioned table, find the leaf @@ -441,6 +449,55 @@ ExecInsert(ModifyTableState *mtstate, ExecComputeStoredGenerated(resultRelInfo, estate, slot, CMD_INSERT); + /* + * If the FDW supports batching, and batching is requested, accumulate + * rows and insert them in batches. Otherwise use the per-row inserts. + */ + if (resultRelInfo->ri_BatchSize > 1) + { + /* + * If a certain number of tuples have already been accumulated, + * or a tuple has come for a different relation than that for + * the accumulated tuples, perform the batch insert + */ + if (resultRelInfo->ri_NumSlots == resultRelInfo->ri_BatchSize) + { + ExecBatchInsert(mtstate, resultRelInfo, + resultRelInfo->ri_Slots, + resultRelInfo->ri_PlanSlots, + resultRelInfo->ri_NumSlots, + estate, canSetTag); + resultRelInfo->ri_NumSlots = 0; + } + + oldContext = MemoryContextSwitchTo(estate->es_query_cxt); + + if (resultRelInfo->ri_Slots == NULL) + { + resultRelInfo->ri_Slots = palloc(sizeof(TupleTableSlot *) * + resultRelInfo->ri_BatchSize); + resultRelInfo->ri_PlanSlots = palloc(sizeof(TupleTableSlot *) * + resultRelInfo->ri_BatchSize); + } + + resultRelInfo->ri_Slots[resultRelInfo->ri_NumSlots] = + MakeSingleTupleTableSlot(slot->tts_tupleDescriptor, + slot->tts_ops); + ExecCopySlot(resultRelInfo->ri_Slots[resultRelInfo->ri_NumSlots], + slot); + resultRelInfo->ri_PlanSlots[resultRelInfo->ri_NumSlots] = + MakeSingleTupleTableSlot(planSlot->tts_tupleDescriptor, + planSlot->tts_ops); + ExecCopySlot(resultRelInfo->ri_PlanSlots[resultRelInfo->ri_NumSlots], + planSlot); + + resultRelInfo->ri_NumSlots++; + + MemoryContextSwitchTo(oldContext); + + return NULL; + } + /* * insert into foreign table: let the FDW do it */ @@ -698,6 +755,70 @@ ExecInsert(ModifyTableState *mtstate, return result; } +/* ---------------------------------------------------------------- + * ExecBatchInsert + * + * Insert multiple tuples in an efficient way. + * Currently, this handles inserting into a foreign table without + * RETURNING clause. + * ---------------------------------------------------------------- + */ +static void +ExecBatchInsert(ModifyTableState *mtstate, + ResultRelInfo *resultRelInfo, + TupleTableSlot **slots, + TupleTableSlot **planSlots, + int numSlots, + EState *estate, + bool canSetTag) +{ + int i; + int numInserted = numSlots; + TupleTableSlot *slot = NULL; + TupleTableSlot **rslots; + + /* + * insert into foreign table: let the FDW do it + */ + rslots = resultRelInfo->ri_FdwRoutine->ExecForeignBatchInsert(estate, + resultRelInfo, + slots, + planSlots, + &numInserted); + + for (i = 0; i < numInserted; i++) + { + slot = rslots[i]; + + /* + * AFTER ROW Triggers or RETURNING expressions might reference the + * tableoid column, so (re-)initialize tts_tableOid before evaluating + * them. + */ + slot->tts_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc); + + /* AFTER ROW INSERT Triggers */ + ExecARInsertTriggers(estate, resultRelInfo, slot, NIL, + mtstate->mt_transition_capture); + + /* + * Check any WITH CHECK OPTION constraints from parent views. See the + * comment in ExecInsert. + */ + if (resultRelInfo->ri_WithCheckOptions != NIL) + ExecWithCheckOptions(WCO_VIEW_CHECK, resultRelInfo, slot, estate); + } + + if (canSetTag && numInserted > 0) + estate->es_processed += numInserted; + + for (i = 0; i < numSlots; i++) + { + ExecDropSingleTupleTableSlot(slots[i]); + ExecDropSingleTupleTableSlot(planSlots[i]); + } +} + /* ---------------------------------------------------------------- * ExecDelete * @@ -1937,6 +2058,9 @@ ExecModifyTable(PlanState *pstate) ItemPointerData tuple_ctid; HeapTupleData oldtupdata; HeapTuple oldtuple; + PartitionTupleRouting *proute = node->mt_partition_tuple_routing; + List *relinfos = NIL; + ListCell *lc; CHECK_FOR_INTERRUPTS(); @@ -2152,6 +2276,25 @@ ExecModifyTable(PlanState *pstate) return slot; } + /* + * Insert remaining tuples for batch insert. + */ + if (proute) + relinfos = estate->es_tuple_routing_result_relations; + else + relinfos = estate->es_opened_result_relations; + + foreach(lc, relinfos) + { + resultRelInfo = lfirst(lc); + if (resultRelInfo->ri_NumSlots > 0) + ExecBatchInsert(node, resultRelInfo, + resultRelInfo->ri_Slots, + resultRelInfo->ri_PlanSlots, + resultRelInfo->ri_NumSlots, + estate, node->canSetTag); + } + /* * We're done, but fire AFTER STATEMENT triggers before exiting. */ @@ -2650,6 +2793,23 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) } } + /* + * Determine if the FDW supports batch insert and determine the batch + * size (a FDW may support batching, but it may be disabled for the + * server/table). + */ + if (!resultRelInfo->ri_usesFdwDirectModify && + operation == CMD_INSERT && + resultRelInfo->ri_FdwRoutine != NULL && + resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize && + resultRelInfo->ri_FdwRoutine->ExecForeignBatchInsert) + resultRelInfo->ri_BatchSize = + resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize(resultRelInfo); + else + resultRelInfo->ri_BatchSize = 1; + + Assert(resultRelInfo->ri_BatchSize >= 1); + /* * Lastly, if this is not the primary (canSetTag) ModifyTable node, add it * to estate->es_auxmodifytables so that it will be run to completion by diff --git a/src/backend/nodes/list.c b/src/backend/nodes/list.c index c4eba6b053f86..dbf6b30233aa9 100644 --- a/src/backend/nodes/list.c +++ b/src/backend/nodes/list.c @@ -277,6 +277,21 @@ list_make4_impl(NodeTag t, ListCell datum1, ListCell datum2, return list; } +List * +list_make5_impl(NodeTag t, ListCell datum1, ListCell datum2, + ListCell datum3, ListCell datum4, ListCell datum5) +{ + List *list = new_list(t, 5); + + list->elements[0] = datum1; + list->elements[1] = datum2; + list->elements[2] = datum3; + list->elements[3] = datum4; + list->elements[4] = datum5; + check_list_invariants(list); + return list; +} + /* * Make room for a new head cell in the given (non-NIL) list. * diff --git a/src/include/foreign/fdwapi.h b/src/include/foreign/fdwapi.h index 2953499fb103c..248f78da45202 100644 --- a/src/include/foreign/fdwapi.h +++ b/src/include/foreign/fdwapi.h @@ -85,6 +85,14 @@ typedef TupleTableSlot *(*ExecForeignInsert_function) (EState *estate, TupleTableSlot *slot, TupleTableSlot *planSlot); +typedef TupleTableSlot **(*ExecForeignBatchInsert_function) (EState *estate, + ResultRelInfo *rinfo, + TupleTableSlot **slots, + TupleTableSlot **planSlots, + int *numSlots); + +typedef int (*GetForeignModifyBatchSize_function) (ResultRelInfo *rinfo); + typedef TupleTableSlot *(*ExecForeignUpdate_function) (EState *estate, ResultRelInfo *rinfo, TupleTableSlot *slot, @@ -209,6 +217,8 @@ typedef struct FdwRoutine PlanForeignModify_function PlanForeignModify; BeginForeignModify_function BeginForeignModify; ExecForeignInsert_function ExecForeignInsert; + ExecForeignBatchInsert_function ExecForeignBatchInsert; + GetForeignModifyBatchSize_function GetForeignModifyBatchSize; ExecForeignUpdate_function ExecForeignUpdate; ExecForeignDelete_function ExecForeignDelete; EndForeignModify_function EndForeignModify; diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 48c3f570fa995..d65099c94aaed 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -446,6 +446,12 @@ typedef struct ResultRelInfo /* true when modifying foreign table directly */ bool ri_usesFdwDirectModify; + /* batch insert stuff */ + int ri_NumSlots; /* number of slots in the array */ + int ri_BatchSize; /* max slots inserted in a single batch */ + TupleTableSlot **ri_Slots; /* input tuples for batch insert */ + TupleTableSlot **ri_PlanSlots; + /* list of WithCheckOption's to be checked */ List *ri_WithCheckOptions; diff --git a/src/include/nodes/pg_list.h b/src/include/nodes/pg_list.h index 710dcd37ef4bb..404e03f132d6b 100644 --- a/src/include/nodes/pg_list.h +++ b/src/include/nodes/pg_list.h @@ -213,6 +213,10 @@ list_length(const List *l) #define list_make4(x1,x2,x3,x4) \ list_make4_impl(T_List, list_make_ptr_cell(x1), list_make_ptr_cell(x2), \ list_make_ptr_cell(x3), list_make_ptr_cell(x4)) +#define list_make5(x1,x2,x3,x4,x5) \ + list_make5_impl(T_List, list_make_ptr_cell(x1), list_make_ptr_cell(x2), \ + list_make_ptr_cell(x3), list_make_ptr_cell(x4), \ + list_make_ptr_cell(x5)) #define list_make1_int(x1) \ list_make1_impl(T_IntList, list_make_int_cell(x1)) @@ -224,6 +228,10 @@ list_length(const List *l) #define list_make4_int(x1,x2,x3,x4) \ list_make4_impl(T_IntList, list_make_int_cell(x1), list_make_int_cell(x2), \ list_make_int_cell(x3), list_make_int_cell(x4)) +#define list_make5_int(x1,x2,x3,x4,x5) \ + list_make5_impl(T_IntList, list_make_int_cell(x1), list_make_int_cell(x2), \ + list_make_int_cell(x3), list_make_int_cell(x4), \ + list_make_int_cell(x5)) #define list_make1_oid(x1) \ list_make1_impl(T_OidList, list_make_oid_cell(x1)) @@ -235,6 +243,10 @@ list_length(const List *l) #define list_make4_oid(x1,x2,x3,x4) \ list_make4_impl(T_OidList, list_make_oid_cell(x1), list_make_oid_cell(x2), \ list_make_oid_cell(x3), list_make_oid_cell(x4)) +#define list_make5_oid(x1,x2,x3,x4,x5) \ + list_make5_impl(T_OidList, list_make_oid_cell(x1), list_make_oid_cell(x2), \ + list_make_oid_cell(x3), list_make_oid_cell(x4), \ + list_make_oid_cell(x5)) /* * Locate the n'th cell (counting from 0) of the list. @@ -520,6 +532,9 @@ extern List *list_make3_impl(NodeTag t, ListCell datum1, ListCell datum2, ListCell datum3); extern List *list_make4_impl(NodeTag t, ListCell datum1, ListCell datum2, ListCell datum3, ListCell datum4); +extern List *list_make5_impl(NodeTag t, ListCell datum1, ListCell datum2, + ListCell datum3, ListCell datum4, + ListCell datum5); extern pg_nodiscard List *lappend(List *list, void *datum); extern pg_nodiscard List *lappend_int(List *list, int datum); From 733d670073efd2c3a9df07c225006668009ab793 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Thu, 21 Jan 2021 10:56:03 +0900 Subject: [PATCH 147/240] Switch "cl /?" to "cl /help" in MSVC scripts for platform detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "cl /?" produces a different output if run on a real or a virtual drive (this can be set with a simple subst command), causing an error in the MSVC scripts if building on a virtual drive because the platform to use cannot be detected. "cl /help", on the contrary, produces a consistent output if used on a real or virtual drive. Changing to "/help" allows the compilation to work with a virtual drive as long as the top of the code repository is part of the drive, without impacting the build on real drives. Reported-by: Robert Grange Author: Juan José Santamaría Flecha Discussion: https://postgr.es/m/16825-c4f104bcebc67034@postgresql.org --- src/tools/msvc/Solution.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm index 59a42bea97a7f..2f28de0355ae9 100644 --- a/src/tools/msvc/Solution.pm +++ b/src/tools/msvc/Solution.pm @@ -62,7 +62,7 @@ sub DeterminePlatform if ($^O eq "MSWin32") { # Examine CL help output to determine if we are in 32 or 64-bit mode. - my $output = `cl /? 2>&1`; + my $output = `cl /help 2>&1`; $? >> 8 == 0 or die "cl command not found"; $self->{platform} = ($output =~ /^\/favor:<.+AMD64/m) ? 'x64' : 'Win32'; From 920f853dc948b98a5dc96580c4ee011a302e33e4 Mon Sep 17 00:00:00 2001 From: Tomas Vondra Date: Thu, 21 Jan 2021 03:23:24 +0100 Subject: [PATCH 148/240] Fix initialization of FDW batching in ExecInitModifyTable ExecInitModifyTable has to initialize batching for all result relations, not just the first one. Furthermore, when junk filters were necessary, the pointer pointed past the mtstate->resultRelInfo array. Per reports from multiple non-x86 animals (florican, locust, ...). Discussion: https://postgr.es/m/20200628151002.7x5laxwpgvkyiu3q@development --- src/backend/executor/nodeModifyTable.c | 31 +++++++++++++++++--------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 9c36860704aad..5d90337498371 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -2797,18 +2797,29 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) * Determine if the FDW supports batch insert and determine the batch * size (a FDW may support batching, but it may be disabled for the * server/table). + * + * We only do this for INSERT, so that for UPDATE/DELETE the batch + * size remains set to 0. */ - if (!resultRelInfo->ri_usesFdwDirectModify && - operation == CMD_INSERT && - resultRelInfo->ri_FdwRoutine != NULL && - resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize && - resultRelInfo->ri_FdwRoutine->ExecForeignBatchInsert) - resultRelInfo->ri_BatchSize = - resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize(resultRelInfo); - else - resultRelInfo->ri_BatchSize = 1; + if (operation == CMD_INSERT) + { + resultRelInfo = mtstate->resultRelInfo; + for (i = 0; i < nplans; i++) + { + if (!resultRelInfo->ri_usesFdwDirectModify && + resultRelInfo->ri_FdwRoutine != NULL && + resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize && + resultRelInfo->ri_FdwRoutine->ExecForeignBatchInsert) + resultRelInfo->ri_BatchSize = + resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize(resultRelInfo); + else + resultRelInfo->ri_BatchSize = 1; + + Assert(resultRelInfo->ri_BatchSize >= 1); - Assert(resultRelInfo->ri_BatchSize >= 1); + resultRelInfo++; + } + } /* * Lastly, if this is not the primary (canSetTag) ModifyTable node, add it From 55dc86eca70b1dc18a79c141b3567efed910329d Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 21 Jan 2021 15:37:23 -0500 Subject: [PATCH 149/240] Fix pull_varnos' miscomputation of relids set for a PlaceHolderVar. Previously, pull_varnos() took the relids of a PlaceHolderVar as being equal to the relids in its contents, but that fails to account for the possibility that we have to postpone evaluation of the PHV due to outer joins. This could result in a malformed plan. The known cases end up triggering the "failed to assign all NestLoopParams to plan nodes" sanity check in createplan.c, but other symptoms may be possible. The right value to use is the join level we actually intend to evaluate the PHV at. We can get that from the ph_eval_at field of the associated PlaceHolderInfo. However, there are some places that call pull_varnos() before the PlaceHolderInfos have been created; in that case, fall back to the conservative assumption that the PHV will be evaluated at its syntactic level. (In principle this might result in missing some legal optimization, but I'm not aware of any cases where it's an issue in practice.) Things are also a bit ticklish for calls occurring during deconstruct_jointree(), but AFAICS the ph_eval_at fields should have reached their final values by the time we need them. The main problem in making this work is that pull_varnos() has no way to get at the PlaceHolderInfos. We can fix that easily, if a bit tediously, in HEAD by passing it the planner "root" pointer. In the back branches that'd cause an unacceptable API/ABI break for extensions, so leave the existing entry points alone and add new ones with the additional parameter. (If an old entry point is called and encounters a PHV, it'll fall back to using the syntactic level, again possibly missing some valid optimization.) Back-patch to v12. The computation is surely also wrong before that, but it appears that we cannot reach a bad plan thanks to join order restrictions imposed on the subquery that the PlaceHolderVar came from. The error only became reachable when commit 4be058fe9 allowed trivial subqueries to be collapsed out completely, eliminating their join order restrictions. Per report from Stephan Springl. Discussion: https://postgr.es/m/171041.1610849523@sss.pgh.pa.us --- contrib/postgres_fdw/postgres_fdw.c | 3 +- src/backend/optimizer/path/clausesel.c | 12 ++-- src/backend/optimizer/path/costsize.c | 2 +- src/backend/optimizer/path/equivclass.c | 17 ++++-- src/backend/optimizer/path/indxpath.c | 61 ++++++++++++-------- src/backend/optimizer/path/pathkeys.c | 2 +- src/backend/optimizer/path/tidpath.c | 18 +++--- src/backend/optimizer/plan/analyzejoins.c | 2 +- src/backend/optimizer/plan/initsplan.c | 31 +++++----- src/backend/optimizer/plan/subselect.c | 4 +- src/backend/optimizer/prep/prepjointree.c | 40 ++++++++----- src/backend/optimizer/util/clauses.c | 4 +- src/backend/optimizer/util/inherit.c | 5 +- src/backend/optimizer/util/orclauses.c | 3 +- src/backend/optimizer/util/placeholder.c | 2 +- src/backend/optimizer/util/restrictinfo.c | 39 ++++++++----- src/backend/optimizer/util/var.c | 69 ++++++++++++++++------- src/backend/utils/adt/selfuncs.c | 4 +- src/include/optimizer/clauses.h | 2 +- src/include/optimizer/optimizer.h | 7 ++- src/include/optimizer/paths.h | 3 +- src/include/optimizer/planmain.h | 3 +- src/include/optimizer/restrictinfo.h | 7 ++- src/test/regress/expected/join.out | 36 ++++++++++++ src/test/regress/sql/join.sql | 16 ++++++ 25 files changed, 261 insertions(+), 131 deletions(-) diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index 9a31bbb86b2ac..8648be0b810f9 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -5882,7 +5882,8 @@ foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel, * RestrictInfos, so we must make our own. */ Assert(!IsA(expr, RestrictInfo)); - rinfo = make_restrictinfo(expr, + rinfo = make_restrictinfo(root, + expr, true, false, false, diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c index 4f5b870d1bc21..d263ecf08272b 100644 --- a/src/backend/optimizer/path/clausesel.c +++ b/src/backend/optimizer/path/clausesel.c @@ -227,7 +227,7 @@ clauselist_selectivity_ext(PlannerInfo *root, } else { - ok = (NumRelids(clause) == 1) && + ok = (NumRelids(root, clause) == 1) && (is_pseudo_constant_clause(lsecond(expr->args)) || (varonleft = false, is_pseudo_constant_clause(linitial(expr->args)))); @@ -609,7 +609,7 @@ bms_is_subset_singleton(const Bitmapset *s, int x) * restriction or join estimator. Subroutine for clause_selectivity(). */ static inline bool -treat_as_join_clause(Node *clause, RestrictInfo *rinfo, +treat_as_join_clause(PlannerInfo *root, Node *clause, RestrictInfo *rinfo, int varRelid, SpecialJoinInfo *sjinfo) { if (varRelid != 0) @@ -643,7 +643,7 @@ treat_as_join_clause(Node *clause, RestrictInfo *rinfo, if (rinfo) return (bms_membership(rinfo->clause_relids) == BMS_MULTIPLE); else - return (NumRelids(clause) > 1); + return (NumRelids(root, clause) > 1); } } @@ -860,7 +860,7 @@ clause_selectivity_ext(PlannerInfo *root, OpExpr *opclause = (OpExpr *) clause; Oid opno = opclause->opno; - if (treat_as_join_clause(clause, rinfo, varRelid, sjinfo)) + if (treat_as_join_clause(root, clause, rinfo, varRelid, sjinfo)) { /* Estimate selectivity for a join clause. */ s1 = join_selectivity(root, opno, @@ -896,7 +896,7 @@ clause_selectivity_ext(PlannerInfo *root, funcclause->funcid, funcclause->args, funcclause->inputcollid, - treat_as_join_clause(clause, rinfo, + treat_as_join_clause(root, clause, rinfo, varRelid, sjinfo), varRelid, jointype, @@ -907,7 +907,7 @@ clause_selectivity_ext(PlannerInfo *root, /* Use node specific selectivity calculation function */ s1 = scalararraysel(root, (ScalarArrayOpExpr *) clause, - treat_as_join_clause(clause, rinfo, + treat_as_join_clause(root, clause, rinfo, varRelid, sjinfo), varRelid, jointype, diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 380336518fed7..aab06c7d213ea 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -1858,7 +1858,7 @@ cost_incremental_sort(Path *path, * Check if the expression contains Var with "varno 0" so that we * don't call estimate_num_groups in that case. */ - if (bms_is_member(0, pull_varnos((Node *) member->em_expr))) + if (bms_is_member(0, pull_varnos(root, (Node *) member->em_expr))) { unknown_varno = true; break; diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c index ab6eaaead12ee..0188c1e9a1894 100644 --- a/src/backend/optimizer/path/equivclass.c +++ b/src/backend/optimizer/path/equivclass.c @@ -196,7 +196,8 @@ process_equivalence(PlannerInfo *root, ntest->location = -1; *p_restrictinfo = - make_restrictinfo((Expr *) ntest, + make_restrictinfo(root, + (Expr *) ntest, restrictinfo->is_pushed_down, restrictinfo->outerjoin_delayed, restrictinfo->pseudoconstant, @@ -716,7 +717,7 @@ get_eclass_for_sort_expr(PlannerInfo *root, /* * Get the precise set of nullable relids appearing in the expression. */ - expr_relids = pull_varnos((Node *) expr); + expr_relids = pull_varnos(root, (Node *) expr); nullable_relids = bms_intersect(nullable_relids, expr_relids); newem = add_eq_member(newec, copyObject(expr), expr_relids, @@ -1696,7 +1697,8 @@ create_join_clause(PlannerInfo *root, */ oldcontext = MemoryContextSwitchTo(root->planner_cxt); - rinfo = build_implied_join_equality(opno, + rinfo = build_implied_join_equality(root, + opno, ec->ec_collation, leftem->em_expr, rightem->em_expr, @@ -1996,7 +1998,8 @@ reconsider_outer_join_clause(PlannerInfo *root, RestrictInfo *rinfo, cur_em->em_datatype); if (!OidIsValid(eq_op)) continue; /* can't generate equality */ - newrinfo = build_implied_join_equality(eq_op, + newrinfo = build_implied_join_equality(root, + eq_op, cur_ec->ec_collation, innervar, cur_em->em_expr, @@ -2141,7 +2144,8 @@ reconsider_full_join_clause(PlannerInfo *root, RestrictInfo *rinfo) cur_em->em_datatype); if (OidIsValid(eq_op)) { - newrinfo = build_implied_join_equality(eq_op, + newrinfo = build_implied_join_equality(root, + eq_op, cur_ec->ec_collation, leftvar, cur_em->em_expr, @@ -2156,7 +2160,8 @@ reconsider_full_join_clause(PlannerInfo *root, RestrictInfo *rinfo) cur_em->em_datatype); if (OidIsValid(eq_op)) { - newrinfo = build_implied_join_equality(eq_op, + newrinfo = build_implied_join_equality(root, + eq_op, cur_ec->ec_collation, rightvar, cur_em->em_expr, diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 9c069a213f9b6..ff536e6b24ba4 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -153,7 +153,8 @@ static IndexClause *match_clause_to_indexcol(PlannerInfo *root, RestrictInfo *rinfo, int indexcol, IndexOptInfo *index); -static IndexClause *match_boolean_index_clause(RestrictInfo *rinfo, +static IndexClause *match_boolean_index_clause(PlannerInfo *root, + RestrictInfo *rinfo, int indexcol, IndexOptInfo *index); static IndexClause *match_opclause_to_indexcol(PlannerInfo *root, RestrictInfo *rinfo, @@ -169,13 +170,16 @@ static IndexClause *get_index_clause_from_support(PlannerInfo *root, int indexarg, int indexcol, IndexOptInfo *index); -static IndexClause *match_saopclause_to_indexcol(RestrictInfo *rinfo, +static IndexClause *match_saopclause_to_indexcol(PlannerInfo *root, + RestrictInfo *rinfo, int indexcol, IndexOptInfo *index); -static IndexClause *match_rowcompare_to_indexcol(RestrictInfo *rinfo, +static IndexClause *match_rowcompare_to_indexcol(PlannerInfo *root, + RestrictInfo *rinfo, int indexcol, IndexOptInfo *index); -static IndexClause *expand_indexqual_rowcompare(RestrictInfo *rinfo, +static IndexClause *expand_indexqual_rowcompare(PlannerInfo *root, + RestrictInfo *rinfo, int indexcol, IndexOptInfo *index, Oid expr_op, @@ -2305,7 +2309,7 @@ match_clause_to_indexcol(PlannerInfo *root, opfamily = index->opfamily[indexcol]; if (IsBooleanOpfamily(opfamily)) { - iclause = match_boolean_index_clause(rinfo, indexcol, index); + iclause = match_boolean_index_clause(root, rinfo, indexcol, index); if (iclause) return iclause; } @@ -2325,11 +2329,11 @@ match_clause_to_indexcol(PlannerInfo *root, } else if (IsA(clause, ScalarArrayOpExpr)) { - return match_saopclause_to_indexcol(rinfo, indexcol, index); + return match_saopclause_to_indexcol(root, rinfo, indexcol, index); } else if (IsA(clause, RowCompareExpr)) { - return match_rowcompare_to_indexcol(rinfo, indexcol, index); + return match_rowcompare_to_indexcol(root, rinfo, indexcol, index); } else if (index->amsearchnulls && IsA(clause, NullTest)) { @@ -2368,7 +2372,8 @@ match_clause_to_indexcol(PlannerInfo *root, * index's key, and if so, build a suitable IndexClause. */ static IndexClause * -match_boolean_index_clause(RestrictInfo *rinfo, +match_boolean_index_clause(PlannerInfo *root, + RestrictInfo *rinfo, int indexcol, IndexOptInfo *index) { @@ -2438,7 +2443,7 @@ match_boolean_index_clause(RestrictInfo *rinfo, IndexClause *iclause = makeNode(IndexClause); iclause->rinfo = rinfo; - iclause->indexquals = list_make1(make_simple_restrictinfo(op)); + iclause->indexquals = list_make1(make_simple_restrictinfo(root, op)); iclause->lossy = false; iclause->indexcol = indexcol; iclause->indexcols = NIL; @@ -2663,7 +2668,8 @@ get_index_clause_from_support(PlannerInfo *root, { Expr *clause = (Expr *) lfirst(lc); - indexquals = lappend(indexquals, make_simple_restrictinfo(clause)); + indexquals = lappend(indexquals, + make_simple_restrictinfo(root, clause)); } iclause->rinfo = rinfo; @@ -2684,7 +2690,8 @@ get_index_clause_from_support(PlannerInfo *root, * which see for comments. */ static IndexClause * -match_saopclause_to_indexcol(RestrictInfo *rinfo, +match_saopclause_to_indexcol(PlannerInfo *root, + RestrictInfo *rinfo, int indexcol, IndexOptInfo *index) { @@ -2703,7 +2710,7 @@ match_saopclause_to_indexcol(RestrictInfo *rinfo, return NULL; leftop = (Node *) linitial(saop->args); rightop = (Node *) lsecond(saop->args); - right_relids = pull_varnos(rightop); + right_relids = pull_varnos(root, rightop); expr_op = saop->opno; expr_coll = saop->inputcollid; @@ -2751,7 +2758,8 @@ match_saopclause_to_indexcol(RestrictInfo *rinfo, * is handled by expand_indexqual_rowcompare(). */ static IndexClause * -match_rowcompare_to_indexcol(RestrictInfo *rinfo, +match_rowcompare_to_indexcol(PlannerInfo *root, + RestrictInfo *rinfo, int indexcol, IndexOptInfo *index) { @@ -2796,14 +2804,14 @@ match_rowcompare_to_indexcol(RestrictInfo *rinfo, * These syntactic tests are the same as in match_opclause_to_indexcol() */ if (match_index_to_operand(leftop, indexcol, index) && - !bms_is_member(index_relid, pull_varnos(rightop)) && + !bms_is_member(index_relid, pull_varnos(root, rightop)) && !contain_volatile_functions(rightop)) { /* OK, indexkey is on left */ var_on_left = true; } else if (match_index_to_operand(rightop, indexcol, index) && - !bms_is_member(index_relid, pull_varnos(leftop)) && + !bms_is_member(index_relid, pull_varnos(root, leftop)) && !contain_volatile_functions(leftop)) { /* indexkey is on right, so commute the operator */ @@ -2822,7 +2830,8 @@ match_rowcompare_to_indexcol(RestrictInfo *rinfo, case BTLessEqualStrategyNumber: case BTGreaterEqualStrategyNumber: case BTGreaterStrategyNumber: - return expand_indexqual_rowcompare(rinfo, + return expand_indexqual_rowcompare(root, + rinfo, indexcol, index, expr_op, @@ -2856,7 +2865,8 @@ match_rowcompare_to_indexcol(RestrictInfo *rinfo, * but we split it out for comprehensibility. */ static IndexClause * -expand_indexqual_rowcompare(RestrictInfo *rinfo, +expand_indexqual_rowcompare(PlannerInfo *root, + RestrictInfo *rinfo, int indexcol, IndexOptInfo *index, Oid expr_op, @@ -2926,7 +2936,7 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo, if (expr_op == InvalidOid) break; /* operator is not usable */ } - if (bms_is_member(index->rel->relid, pull_varnos(constop))) + if (bms_is_member(index->rel->relid, pull_varnos(root, constop))) break; /* no good, Var on wrong side */ if (contain_volatile_functions(constop)) break; /* no good, volatile comparison value */ @@ -3036,7 +3046,8 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo, matching_cols); rc->rargs = list_truncate(copyObject(non_var_args), matching_cols); - iclause->indexquals = list_make1(make_simple_restrictinfo((Expr *) rc)); + iclause->indexquals = list_make1(make_simple_restrictinfo(root, + (Expr *) rc)); } else { @@ -3050,7 +3061,7 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo, copyObject(linitial(non_var_args)), InvalidOid, linitial_oid(clause->inputcollids)); - iclause->indexquals = list_make1(make_simple_restrictinfo(op)); + iclause->indexquals = list_make1(make_simple_restrictinfo(root, op)); } } @@ -3667,7 +3678,9 @@ relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel, * specified index column matches a boolean restriction clause. */ bool -indexcol_is_bool_constant_for_query(IndexOptInfo *index, int indexcol) +indexcol_is_bool_constant_for_query(PlannerInfo *root, + IndexOptInfo *index, + int indexcol) { ListCell *lc; @@ -3689,7 +3702,7 @@ indexcol_is_bool_constant_for_query(IndexOptInfo *index, int indexcol) continue; /* See if we can match the clause's expression to the index column */ - if (match_boolean_index_clause(rinfo, indexcol, index)) + if (match_boolean_index_clause(root, rinfo, indexcol, index)) return true; } @@ -3801,10 +3814,10 @@ match_index_to_operand(Node *operand, * index: the index of interest */ bool -is_pseudo_constant_for_index(Node *expr, IndexOptInfo *index) +is_pseudo_constant_for_index(PlannerInfo *root, Node *expr, IndexOptInfo *index) { /* pull_varnos is cheaper than volatility check, so do that first */ - if (bms_is_member(index->rel->relid, pull_varnos(expr))) + if (bms_is_member(index->rel->relid, pull_varnos(root, expr))) return false; /* no good, contains Var of table */ if (contain_volatile_functions(expr)) return false; /* no good, volatile comparison value */ diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c index 3ebc57a154567..bd9a176d7d37c 100644 --- a/src/backend/optimizer/path/pathkeys.c +++ b/src/backend/optimizer/path/pathkeys.c @@ -598,7 +598,7 @@ build_index_pathkeys(PlannerInfo *root, * should stop considering index columns; any lower-order sort * keys won't be useful either. */ - if (!indexcol_is_bool_constant_for_query(index, i)) + if (!indexcol_is_bool_constant_for_query(root, index, i)) break; } diff --git a/src/backend/optimizer/path/tidpath.c b/src/backend/optimizer/path/tidpath.c index 8ef04060570e9..0845b460e2c9a 100644 --- a/src/backend/optimizer/path/tidpath.c +++ b/src/backend/optimizer/path/tidpath.c @@ -123,7 +123,7 @@ IsTidEqualClause(RestrictInfo *rinfo, RelOptInfo *rel) * other side of the clause does. */ static bool -IsTidEqualAnyClause(RestrictInfo *rinfo, RelOptInfo *rel) +IsTidEqualAnyClause(PlannerInfo *root, RestrictInfo *rinfo, RelOptInfo *rel) { ScalarArrayOpExpr *node; Node *arg1, @@ -148,7 +148,7 @@ IsTidEqualAnyClause(RestrictInfo *rinfo, RelOptInfo *rel) IsCTIDVar((Var *) arg1, rel)) { /* The other argument must be a pseudoconstant */ - if (bms_is_member(rel->relid, pull_varnos(arg2)) || + if (bms_is_member(rel->relid, pull_varnos(root, arg2)) || contain_volatile_functions(arg2)) return false; @@ -190,7 +190,7 @@ IsCurrentOfClause(RestrictInfo *rinfo, RelOptInfo *rel) * (Using a List may seem a bit weird, but it simplifies the caller.) */ static List * -TidQualFromRestrictInfo(RestrictInfo *rinfo, RelOptInfo *rel) +TidQualFromRestrictInfo(PlannerInfo *root, RestrictInfo *rinfo, RelOptInfo *rel) { /* * We may ignore pseudoconstant clauses (they can't contain Vars, so could @@ -210,7 +210,7 @@ TidQualFromRestrictInfo(RestrictInfo *rinfo, RelOptInfo *rel) * Check all base cases. If we get a match, return the clause. */ if (IsTidEqualClause(rinfo, rel) || - IsTidEqualAnyClause(rinfo, rel) || + IsTidEqualAnyClause(root, rinfo, rel) || IsCurrentOfClause(rinfo, rel)) return list_make1(rinfo); @@ -227,7 +227,7 @@ TidQualFromRestrictInfo(RestrictInfo *rinfo, RelOptInfo *rel) * This function is just concerned with handling AND/OR recursion. */ static List * -TidQualFromRestrictInfoList(List *rlist, RelOptInfo *rel) +TidQualFromRestrictInfoList(PlannerInfo *root, List *rlist, RelOptInfo *rel) { List *rlst = NIL; ListCell *l; @@ -255,14 +255,14 @@ TidQualFromRestrictInfoList(List *rlist, RelOptInfo *rel) List *andargs = ((BoolExpr *) orarg)->args; /* Recurse in case there are sub-ORs */ - sublist = TidQualFromRestrictInfoList(andargs, rel); + sublist = TidQualFromRestrictInfoList(root, andargs, rel); } else { RestrictInfo *rinfo = castNode(RestrictInfo, orarg); Assert(!restriction_is_or_clause(rinfo)); - sublist = TidQualFromRestrictInfo(rinfo, rel); + sublist = TidQualFromRestrictInfo(root, rinfo, rel); } /* @@ -284,7 +284,7 @@ TidQualFromRestrictInfoList(List *rlist, RelOptInfo *rel) else { /* Not an OR clause, so handle base cases */ - rlst = TidQualFromRestrictInfo(rinfo, rel); + rlst = TidQualFromRestrictInfo(root, rinfo, rel); } /* @@ -390,7 +390,7 @@ create_tidscan_paths(PlannerInfo *root, RelOptInfo *rel) * If any suitable quals exist in the rel's baserestrict list, generate a * plain (unparameterized) TidPath with them. */ - tidquals = TidQualFromRestrictInfoList(rel->baserestrictinfo, rel); + tidquals = TidQualFromRestrictInfoList(root, rel->baserestrictinfo, rel); if (tidquals) { diff --git a/src/backend/optimizer/plan/analyzejoins.c b/src/backend/optimizer/plan/analyzejoins.c index 90460a69bdf4f..37eb64bcef372 100644 --- a/src/backend/optimizer/plan/analyzejoins.c +++ b/src/backend/optimizer/plan/analyzejoins.c @@ -231,7 +231,7 @@ join_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo) continue; /* it definitely doesn't reference innerrel */ if (bms_is_subset(phinfo->ph_eval_at, innerrel->relids)) return false; /* there isn't any other place to eval PHV */ - if (bms_overlap(pull_varnos((Node *) phinfo->ph_var->phexpr), + if (bms_overlap(pull_varnos(root, (Node *) phinfo->ph_var->phexpr), innerrel->relids)) return false; /* it does reference innerrel */ } diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index ac7dd5d4c8689..02f813cebdcb4 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -60,7 +60,8 @@ static SpecialJoinInfo *make_outerjoininfo(PlannerInfo *root, Relids left_rels, Relids right_rels, Relids inner_join_rels, JoinType jointype, List *clause); -static void compute_semijoin_info(SpecialJoinInfo *sjinfo, List *clause); +static void compute_semijoin_info(PlannerInfo *root, SpecialJoinInfo *sjinfo, + List *clause); static void distribute_qual_to_rels(PlannerInfo *root, Node *clause, bool below_outer_join, JoinType jointype, @@ -1196,7 +1197,7 @@ make_outerjoininfo(PlannerInfo *root, /* this always starts out false */ sjinfo->delay_upper_joins = false; - compute_semijoin_info(sjinfo, clause); + compute_semijoin_info(root, sjinfo, clause); /* If it's a full join, no need to be very smart */ if (jointype == JOIN_FULL) @@ -1210,7 +1211,7 @@ make_outerjoininfo(PlannerInfo *root, /* * Retrieve all relids mentioned within the join clause. */ - clause_relids = pull_varnos((Node *) clause); + clause_relids = pull_varnos(root, (Node *) clause); /* * For which relids is the clause strict, ie, it cannot succeed if the @@ -1390,7 +1391,7 @@ make_outerjoininfo(PlannerInfo *root, * SpecialJoinInfo; the rest may not be set yet. */ static void -compute_semijoin_info(SpecialJoinInfo *sjinfo, List *clause) +compute_semijoin_info(PlannerInfo *root, SpecialJoinInfo *sjinfo, List *clause) { List *semi_operators; List *semi_rhs_exprs; @@ -1454,7 +1455,7 @@ compute_semijoin_info(SpecialJoinInfo *sjinfo, List *clause) list_length(op->args) != 2) { /* No, but does it reference both sides? */ - all_varnos = pull_varnos((Node *) op); + all_varnos = pull_varnos(root, (Node *) op); if (!bms_overlap(all_varnos, sjinfo->syn_righthand) || bms_is_subset(all_varnos, sjinfo->syn_righthand)) { @@ -1475,8 +1476,8 @@ compute_semijoin_info(SpecialJoinInfo *sjinfo, List *clause) opno = op->opno; left_expr = linitial(op->args); right_expr = lsecond(op->args); - left_varnos = pull_varnos(left_expr); - right_varnos = pull_varnos(right_expr); + left_varnos = pull_varnos(root, left_expr); + right_varnos = pull_varnos(root, right_expr); all_varnos = bms_union(left_varnos, right_varnos); opinputtype = exprType(left_expr); @@ -1621,7 +1622,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, /* * Retrieve all relids mentioned within the clause. */ - relids = pull_varnos(clause); + relids = pull_varnos(root, clause); /* * In ordinary SQL, a WHERE or JOIN/ON clause can't reference any rels @@ -1835,7 +1836,8 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, /* * Build the RestrictInfo node itself. */ - restrictinfo = make_restrictinfo((Expr *) clause, + restrictinfo = make_restrictinfo(root, + (Expr *) clause, is_pushed_down, outerjoin_delayed, pseudoconstant, @@ -2309,7 +2311,7 @@ process_implied_equality(PlannerInfo *root, * * Retrieve all relids mentioned within the possibly-simplified clause. */ - relids = pull_varnos(clause); + relids = pull_varnos(root, clause); Assert(bms_is_subset(relids, qualscope)); /* @@ -2341,7 +2343,8 @@ process_implied_equality(PlannerInfo *root, /* * Build the RestrictInfo node itself. */ - restrictinfo = make_restrictinfo((Expr *) clause, + restrictinfo = make_restrictinfo(root, + (Expr *) clause, true, /* is_pushed_down */ false, /* outerjoin_delayed */ pseudoconstant, @@ -2407,7 +2410,8 @@ process_implied_equality(PlannerInfo *root, * caller's responsibility that left_ec/right_ec be set as necessary. */ RestrictInfo * -build_implied_join_equality(Oid opno, +build_implied_join_equality(PlannerInfo *root, + Oid opno, Oid collation, Expr *item1, Expr *item2, @@ -2433,7 +2437,8 @@ build_implied_join_equality(Oid opno, /* * Build the RestrictInfo node itself. */ - restrictinfo = make_restrictinfo(clause, + restrictinfo = make_restrictinfo(root, + clause, true, /* is_pushed_down */ false, /* outerjoin_delayed */ false, /* pseudoconstant */ diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 6d4cc1bcce4aa..54ef61bfb350d 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -1302,7 +1302,7 @@ convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink, * it's not gonna be a join. (Note that it won't have Vars referring to * the subquery, rather Params.) */ - upper_varnos = pull_varnos(sublink->testexpr); + upper_varnos = pull_varnos(root, sublink->testexpr); if (bms_is_empty(upper_varnos)) return NULL; @@ -1486,7 +1486,7 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink, * The ones <= rtoffset belong to the upper query; the ones > rtoffset do * not. */ - clause_varnos = pull_varnos(whereClause); + clause_varnos = pull_varnos(root, whereClause); upper_varnos = NULL; while ((varno = bms_first_member(clause_varnos)) >= 0) { diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c index f9ef96991df05..d961592e015e8 100644 --- a/src/backend/optimizer/prep/prepjointree.c +++ b/src/backend/optimizer/prep/prepjointree.c @@ -82,7 +82,8 @@ static void pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int childRToffset); static void make_setop_translation_list(Query *query, Index newvarno, AppendRelInfo *appinfo); -static bool is_simple_subquery(Query *subquery, RangeTblEntry *rte, +static bool is_simple_subquery(PlannerInfo *root, Query *subquery, + RangeTblEntry *rte, JoinExpr *lowest_outer_join); static Node *pull_up_simple_values(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte); @@ -95,7 +96,8 @@ static bool is_simple_union_all(Query *subquery); static bool is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, List *colTypes); static bool is_safe_append_member(Query *subquery); -static bool jointree_contains_lateral_outer_refs(Node *jtnode, bool restricted, +static bool jointree_contains_lateral_outer_refs(PlannerInfo *root, + Node *jtnode, bool restricted, Relids safe_upper_varnos); static void perform_pullup_replace_vars(PlannerInfo *root, pullup_replace_vars_context *rvcontext, @@ -744,7 +746,7 @@ pull_up_subqueries_recurse(PlannerInfo *root, Node *jtnode, * unless is_safe_append_member says so. */ if (rte->rtekind == RTE_SUBQUERY && - is_simple_subquery(rte->subquery, rte, lowest_outer_join) && + is_simple_subquery(root, rte->subquery, rte, lowest_outer_join) && (containing_appendrel == NULL || is_safe_append_member(rte->subquery))) return pull_up_simple_subquery(root, jtnode, rte, @@ -973,7 +975,7 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, * easier just to keep this "if" looking the same as the one in * pull_up_subqueries_recurse. */ - if (is_simple_subquery(subquery, rte, lowest_outer_join) && + if (is_simple_subquery(root, subquery, rte, lowest_outer_join) && (containing_appendrel == NULL || is_safe_append_member(subquery))) { /* good to go */ @@ -1398,7 +1400,7 @@ make_setop_translation_list(Query *query, Index newvarno, * lowest_outer_join is the lowest outer join above the subquery, or NULL. */ static bool -is_simple_subquery(Query *subquery, RangeTblEntry *rte, +is_simple_subquery(PlannerInfo *root, Query *subquery, RangeTblEntry *rte, JoinExpr *lowest_outer_join) { /* @@ -1477,7 +1479,8 @@ is_simple_subquery(Query *subquery, RangeTblEntry *rte, safe_upper_varnos = NULL; /* doesn't matter */ } - if (jointree_contains_lateral_outer_refs((Node *) subquery->jointree, + if (jointree_contains_lateral_outer_refs(root, + (Node *) subquery->jointree, restricted, safe_upper_varnos)) return false; @@ -1496,7 +1499,9 @@ is_simple_subquery(Query *subquery, RangeTblEntry *rte, */ if (lowest_outer_join != NULL) { - Relids lvarnos = pull_varnos_of_level((Node *) subquery->targetList, 1); + Relids lvarnos = pull_varnos_of_level(root, + (Node *) subquery->targetList, + 1); if (!bms_is_subset(lvarnos, safe_upper_varnos)) return false; @@ -1929,7 +1934,8 @@ is_safe_append_member(Query *subquery) * in safe_upper_varnos. */ static bool -jointree_contains_lateral_outer_refs(Node *jtnode, bool restricted, +jointree_contains_lateral_outer_refs(PlannerInfo *root, Node *jtnode, + bool restricted, Relids safe_upper_varnos) { if (jtnode == NULL) @@ -1944,7 +1950,8 @@ jointree_contains_lateral_outer_refs(Node *jtnode, bool restricted, /* First, recurse to check child joins */ foreach(l, f->fromlist) { - if (jointree_contains_lateral_outer_refs(lfirst(l), + if (jointree_contains_lateral_outer_refs(root, + lfirst(l), restricted, safe_upper_varnos)) return true; @@ -1952,7 +1959,7 @@ jointree_contains_lateral_outer_refs(Node *jtnode, bool restricted, /* Then check the top-level quals */ if (restricted && - !bms_is_subset(pull_varnos_of_level(f->quals, 1), + !bms_is_subset(pull_varnos_of_level(root, f->quals, 1), safe_upper_varnos)) return true; } @@ -1971,18 +1978,20 @@ jointree_contains_lateral_outer_refs(Node *jtnode, bool restricted, } /* Check the child joins */ - if (jointree_contains_lateral_outer_refs(j->larg, + if (jointree_contains_lateral_outer_refs(root, + j->larg, restricted, safe_upper_varnos)) return true; - if (jointree_contains_lateral_outer_refs(j->rarg, + if (jointree_contains_lateral_outer_refs(root, + j->rarg, restricted, safe_upper_varnos)) return true; /* Check the JOIN's qual clauses */ if (restricted && - !bms_is_subset(pull_varnos_of_level(j->quals, 1), + !bms_is_subset(pull_varnos_of_level(root, j->quals, 1), safe_upper_varnos)) return true; } @@ -2366,7 +2375,8 @@ pullup_replace_vars_callback(Var *var, * level-zero var must belong to the subquery. */ if ((rcon->target_rte->lateral ? - bms_overlap(pull_varnos((Node *) newnode), rcon->relids) : + bms_overlap(pull_varnos(rcon->root, (Node *) newnode), + rcon->relids) : contain_vars_of_level((Node *) newnode, 0)) && !contain_nonstrict_functions((Node *) newnode)) { @@ -2804,7 +2814,7 @@ reduce_outer_joins_pass2(Node *jtnode, overlap = list_intersection(local_nonnullable_vars, forced_null_vars); if (overlap != NIL && - bms_overlap(pull_varnos((Node *) overlap), + bms_overlap(pull_varnos(root, (Node *) overlap), right_state->relids)) jointype = JOIN_ANTI; } diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 51d26a0691566..d2470b7c6a7d6 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -1897,9 +1897,9 @@ is_pseudo_constant_clause_relids(Node *clause, Relids relids) * Returns the number of different relations referenced in 'clause'. */ int -NumRelids(Node *clause) +NumRelids(PlannerInfo *root, Node *clause) { - Relids varnos = pull_varnos(clause); + Relids varnos = pull_varnos(root, clause); int result = bms_num_members(varnos); bms_free(varnos); diff --git a/src/backend/optimizer/util/inherit.c b/src/backend/optimizer/util/inherit.c index 36d248beb5114..be1c9ddd96469 100644 --- a/src/backend/optimizer/util/inherit.c +++ b/src/backend/optimizer/util/inherit.c @@ -748,7 +748,8 @@ apply_child_basequals(PlannerInfo *root, RelOptInfo *parentrel, } /* reconstitute RestrictInfo with appropriate properties */ childquals = lappend(childquals, - make_restrictinfo((Expr *) onecq, + make_restrictinfo(root, + (Expr *) onecq, rinfo->is_pushed_down, rinfo->outerjoin_delayed, pseudoconstant, @@ -785,7 +786,7 @@ apply_child_basequals(PlannerInfo *root, RelOptInfo *parentrel, /* not likely that we'd see constants here, so no check */ childquals = lappend(childquals, - make_restrictinfo(qual, + make_restrictinfo(root, qual, true, false, false, security_level, NULL, NULL, NULL)); diff --git a/src/backend/optimizer/util/orclauses.c b/src/backend/optimizer/util/orclauses.c index a4de576fd8ad9..d559f33826883 100644 --- a/src/backend/optimizer/util/orclauses.c +++ b/src/backend/optimizer/util/orclauses.c @@ -268,7 +268,8 @@ consider_new_or_clause(PlannerInfo *root, RelOptInfo *rel, * Build a RestrictInfo from the new OR clause. We can assume it's valid * as a base restriction clause. */ - or_rinfo = make_restrictinfo(orclause, + or_rinfo = make_restrictinfo(root, + orclause, true, false, false, diff --git a/src/backend/optimizer/util/placeholder.c b/src/backend/optimizer/util/placeholder.c index 2f21455c7bc47..1c4202d864cef 100644 --- a/src/backend/optimizer/util/placeholder.c +++ b/src/backend/optimizer/util/placeholder.c @@ -98,7 +98,7 @@ find_placeholder_info(PlannerInfo *root, PlaceHolderVar *phv, * ph_eval_at. If no referenced rels are within the syntactic scope, * force evaluation at the syntactic location. */ - rels_used = pull_varnos((Node *) phv->phexpr); + rels_used = pull_varnos(root, (Node *) phv->phexpr); phinfo->ph_lateral = bms_difference(rels_used, phv->phrels); if (bms_is_empty(phinfo->ph_lateral)) phinfo->ph_lateral = NULL; /* make it exactly NULL if empty */ diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c index 221e1caa68153..eb113d94c1e10 100644 --- a/src/backend/optimizer/util/restrictinfo.c +++ b/src/backend/optimizer/util/restrictinfo.c @@ -21,7 +21,8 @@ #include "optimizer/restrictinfo.h" -static RestrictInfo *make_restrictinfo_internal(Expr *clause, +static RestrictInfo *make_restrictinfo_internal(PlannerInfo *root, + Expr *clause, Expr *orclause, bool is_pushed_down, bool outerjoin_delayed, @@ -30,7 +31,8 @@ static RestrictInfo *make_restrictinfo_internal(Expr *clause, Relids required_relids, Relids outer_relids, Relids nullable_relids); -static Expr *make_sub_restrictinfos(Expr *clause, +static Expr *make_sub_restrictinfos(PlannerInfo *root, + Expr *clause, bool is_pushed_down, bool outerjoin_delayed, bool pseudoconstant, @@ -56,7 +58,8 @@ static Expr *make_sub_restrictinfos(Expr *clause, * later. */ RestrictInfo * -make_restrictinfo(Expr *clause, +make_restrictinfo(PlannerInfo *root, + Expr *clause, bool is_pushed_down, bool outerjoin_delayed, bool pseudoconstant, @@ -70,7 +73,8 @@ make_restrictinfo(Expr *clause, * above each subclause of the top-level AND/OR structure. */ if (is_orclause(clause)) - return (RestrictInfo *) make_sub_restrictinfos(clause, + return (RestrictInfo *) make_sub_restrictinfos(root, + clause, is_pushed_down, outerjoin_delayed, pseudoconstant, @@ -82,7 +86,8 @@ make_restrictinfo(Expr *clause, /* Shouldn't be an AND clause, else AND/OR flattening messed up */ Assert(!is_andclause(clause)); - return make_restrictinfo_internal(clause, + return make_restrictinfo_internal(root, + clause, NULL, is_pushed_down, outerjoin_delayed, @@ -99,7 +104,8 @@ make_restrictinfo(Expr *clause, * Common code for the main entry points and the recursive cases. */ static RestrictInfo * -make_restrictinfo_internal(Expr *clause, +make_restrictinfo_internal(PlannerInfo *root, + Expr *clause, Expr *orclause, bool is_pushed_down, bool outerjoin_delayed, @@ -137,8 +143,8 @@ make_restrictinfo_internal(Expr *clause, */ if (is_opclause(clause) && list_length(((OpExpr *) clause)->args) == 2) { - restrictinfo->left_relids = pull_varnos(get_leftop(clause)); - restrictinfo->right_relids = pull_varnos(get_rightop(clause)); + restrictinfo->left_relids = pull_varnos(root, get_leftop(clause)); + restrictinfo->right_relids = pull_varnos(root, get_rightop(clause)); restrictinfo->clause_relids = bms_union(restrictinfo->left_relids, restrictinfo->right_relids); @@ -165,7 +171,7 @@ make_restrictinfo_internal(Expr *clause, restrictinfo->left_relids = NULL; restrictinfo->right_relids = NULL; /* and get the total relid set the hard way */ - restrictinfo->clause_relids = pull_varnos((Node *) clause); + restrictinfo->clause_relids = pull_varnos(root, (Node *) clause); } /* required_relids defaults to clause_relids */ @@ -225,7 +231,8 @@ make_restrictinfo_internal(Expr *clause, * contained rels. */ static Expr * -make_sub_restrictinfos(Expr *clause, +make_sub_restrictinfos(PlannerInfo *root, + Expr *clause, bool is_pushed_down, bool outerjoin_delayed, bool pseudoconstant, @@ -241,7 +248,8 @@ make_sub_restrictinfos(Expr *clause, foreach(temp, ((BoolExpr *) clause)->args) orlist = lappend(orlist, - make_sub_restrictinfos(lfirst(temp), + make_sub_restrictinfos(root, + lfirst(temp), is_pushed_down, outerjoin_delayed, pseudoconstant, @@ -249,7 +257,8 @@ make_sub_restrictinfos(Expr *clause, NULL, outer_relids, nullable_relids)); - return (Expr *) make_restrictinfo_internal(clause, + return (Expr *) make_restrictinfo_internal(root, + clause, make_orclause(orlist), is_pushed_down, outerjoin_delayed, @@ -266,7 +275,8 @@ make_sub_restrictinfos(Expr *clause, foreach(temp, ((BoolExpr *) clause)->args) andlist = lappend(andlist, - make_sub_restrictinfos(lfirst(temp), + make_sub_restrictinfos(root, + lfirst(temp), is_pushed_down, outerjoin_delayed, pseudoconstant, @@ -277,7 +287,8 @@ make_sub_restrictinfos(Expr *clause, return make_andclause(andlist); } else - return (Expr *) make_restrictinfo_internal(clause, + return (Expr *) make_restrictinfo_internal(root, + clause, NULL, is_pushed_down, outerjoin_delayed, diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c index 19b2bba707766..e307d6fbb0720 100644 --- a/src/backend/optimizer/util/var.c +++ b/src/backend/optimizer/util/var.c @@ -23,6 +23,7 @@ #include "access/sysattr.h" #include "nodes/nodeFuncs.h" #include "optimizer/optimizer.h" +#include "optimizer/placeholder.h" #include "optimizer/prep.h" #include "parser/parsetree.h" #include "rewrite/rewriteManip.h" @@ -31,6 +32,7 @@ typedef struct { Relids varnos; + PlannerInfo *root; int sublevels_up; } pull_varnos_context; @@ -92,11 +94,12 @@ static Relids alias_relid_set(Query *query, Relids relids); * SubPlan, we only need to look at the parameters passed to the subplan. */ Relids -pull_varnos(Node *node) +pull_varnos(PlannerInfo *root, Node *node) { pull_varnos_context context; context.varnos = NULL; + context.root = root; context.sublevels_up = 0; /* @@ -117,11 +120,12 @@ pull_varnos(Node *node) * Only Vars of the specified level are considered. */ Relids -pull_varnos_of_level(Node *node, int levelsup) +pull_varnos_of_level(PlannerInfo *root, Node *node, int levelsup) { pull_varnos_context context; context.varnos = NULL; + context.root = root; context.sublevels_up = levelsup; /* @@ -159,33 +163,56 @@ pull_varnos_walker(Node *node, pull_varnos_context *context) } if (IsA(node, PlaceHolderVar)) { - /* - * A PlaceHolderVar acts as a variable of its syntactic scope, or - * lower than that if it references only a subset of the rels in its - * syntactic scope. It might also contain lateral references, but we - * should ignore such references when computing the set of varnos in - * an expression tree. Also, if the PHV contains no variables within - * its syntactic scope, it will be forced to be evaluated exactly at - * the syntactic scope, so take that as the relid set. - */ PlaceHolderVar *phv = (PlaceHolderVar *) node; - pull_varnos_context subcontext; - subcontext.varnos = NULL; - subcontext.sublevels_up = context->sublevels_up; - (void) pull_varnos_walker((Node *) phv->phexpr, &subcontext); + /* + * If a PlaceHolderVar is not of the target query level, ignore it, + * instead recursing into its expression to see if it contains any + * vars that are of the target level. + */ if (phv->phlevelsup == context->sublevels_up) { - subcontext.varnos = bms_int_members(subcontext.varnos, - phv->phrels); - if (bms_is_empty(subcontext.varnos)) + /* + * Ideally, the PHV's contribution to context->varnos is its + * ph_eval_at set. However, this code can be invoked before + * that's been computed. If we cannot find a PlaceHolderInfo, + * fall back to the conservative assumption that the PHV will be + * evaluated at its syntactic level (phv->phrels). + * + * There is a second hazard: this code is also used to examine + * qual clauses during deconstruct_jointree, when we may have a + * PlaceHolderInfo but its ph_eval_at value is not yet final, so + * that theoretically we could obtain a relid set that's smaller + * than we'd see later on. That should never happen though, + * because we deconstruct the jointree working upwards. Any outer + * join that forces delay of evaluation of a given qual clause + * will be processed before we examine that clause here, so the + * ph_eval_at value should have been updated to include it. + */ + PlaceHolderInfo *phinfo = NULL; + + if (phv->phlevelsup == 0) + { + ListCell *lc; + + foreach(lc, context->root->placeholder_list) + { + phinfo = (PlaceHolderInfo *) lfirst(lc); + if (phinfo->phid == phv->phid) + break; + phinfo = NULL; + } + } + if (phinfo != NULL) + context->varnos = bms_add_members(context->varnos, + phinfo->ph_eval_at); + else context->varnos = bms_add_members(context->varnos, phv->phrels); + return false; /* don't recurse into expression */ } - context->varnos = bms_join(context->varnos, subcontext.varnos); - return false; } - if (IsA(node, Query)) + else if (IsA(node, Query)) { /* Recurse into RTE subquery or not-yet-planned sublink subquery */ bool result; diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index d5e61664bc614..47ca4ddbb5250 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -2206,7 +2206,7 @@ rowcomparesel(PlannerInfo *root, /* * Otherwise, it's a join if there's more than one relation used. */ - is_join_clause = (NumRelids((Node *) opargs) > 1); + is_join_clause = (NumRelids(root, (Node *) opargs) > 1); } if (is_join_clause) @@ -4771,7 +4771,7 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid, * membership. Note that when varRelid isn't zero, only vars of that * relation are considered "real" vars. */ - varnos = pull_varnos(basenode); + varnos = pull_varnos(root, basenode); onerel = NULL; diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h index da3fc4df105e9..0673887a852c0 100644 --- a/src/include/optimizer/clauses.h +++ b/src/include/optimizer/clauses.h @@ -46,7 +46,7 @@ extern Var *find_forced_null_var(Node *clause); extern bool is_pseudo_constant_clause(Node *clause); extern bool is_pseudo_constant_clause_relids(Node *clause, Relids relids); -extern int NumRelids(Node *clause); +extern int NumRelids(PlannerInfo *root, Node *clause); extern void CommuteOpExpr(OpExpr *clause); diff --git a/src/include/optimizer/optimizer.h b/src/include/optimizer/optimizer.h index 6235933ca4a2f..d587952b7d687 100644 --- a/src/include/optimizer/optimizer.h +++ b/src/include/optimizer/optimizer.h @@ -97,7 +97,8 @@ extern double clamp_row_est(double nrows); /* in path/indxpath.c: */ -extern bool is_pseudo_constant_for_index(Node *expr, IndexOptInfo *index); +extern bool is_pseudo_constant_for_index(PlannerInfo *root, Node *expr, + IndexOptInfo *index); /* in plan/planner.c: */ @@ -188,8 +189,8 @@ extern SortGroupClause *get_sortgroupref_clause_noerr(Index sortref, #define PVC_RECURSE_PLACEHOLDERS 0x0020 /* recurse into PlaceHolderVar * arguments */ -extern Bitmapset *pull_varnos(Node *node); -extern Bitmapset *pull_varnos_of_level(Node *node, int levelsup); +extern Bitmapset *pull_varnos(PlannerInfo *root, Node *node); +extern Bitmapset *pull_varnos_of_level(PlannerInfo *root, Node *node, int levelsup); extern void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos); extern List *pull_vars_of_level(Node *node, int levelsup); extern bool contain_var_clause(Node *node); diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h index 2d51cbecaa3c6..035d3e1206984 100644 --- a/src/include/optimizer/paths.h +++ b/src/include/optimizer/paths.h @@ -75,7 +75,8 @@ extern void create_index_paths(PlannerInfo *root, RelOptInfo *rel); extern bool relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel, List *restrictlist, List *exprlist, List *oprlist); -extern bool indexcol_is_bool_constant_for_query(IndexOptInfo *index, +extern bool indexcol_is_bool_constant_for_query(PlannerInfo *root, + IndexOptInfo *index, int indexcol); extern bool match_index_to_operand(Node *operand, int indexcol, IndexOptInfo *index); diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h index 777655210b63f..bf1adfc52acee 100644 --- a/src/include/optimizer/planmain.h +++ b/src/include/optimizer/planmain.h @@ -87,7 +87,8 @@ extern RestrictInfo *process_implied_equality(PlannerInfo *root, Index security_level, bool below_outer_join, bool both_const); -extern RestrictInfo *build_implied_join_equality(Oid opno, +extern RestrictInfo *build_implied_join_equality(PlannerInfo *root, + Oid opno, Oid collation, Expr *item1, Expr *item2, diff --git a/src/include/optimizer/restrictinfo.h b/src/include/optimizer/restrictinfo.h index 266faaf07c3dd..0165ffde37be5 100644 --- a/src/include/optimizer/restrictinfo.h +++ b/src/include/optimizer/restrictinfo.h @@ -18,10 +18,11 @@ /* Convenience macro for the common case of a valid-everywhere qual */ -#define make_simple_restrictinfo(clause) \ - make_restrictinfo(clause, true, false, false, 0, NULL, NULL, NULL) +#define make_simple_restrictinfo(root, clause) \ + make_restrictinfo(root, clause, true, false, false, 0, NULL, NULL, NULL) -extern RestrictInfo *make_restrictinfo(Expr *clause, +extern RestrictInfo *make_restrictinfo(PlannerInfo *root, + Expr *clause, bool is_pushed_down, bool outerjoin_delayed, bool pseudoconstant, diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out index 81b42c601b471..5c7528c0293eb 100644 --- a/src/test/regress/expected/join.out +++ b/src/test/regress/expected/join.out @@ -4756,6 +4756,42 @@ where ss.stringu2 !~* ss.case1; (1 row) rollback; +-- test case to expose miscomputation of required relid set for a PHV +explain (verbose, costs off) +select i8.*, ss.v, t.unique2 + from int8_tbl i8 + left join int4_tbl i4 on i4.f1 = 1 + left join lateral (select i4.f1 + 1 as v) as ss on true + left join tenk1 t on t.unique2 = ss.v +where q2 = 456; + QUERY PLAN +------------------------------------------------------------- + Nested Loop Left Join + Output: i8.q1, i8.q2, ((i4.f1 + 1)), t.unique2 + -> Nested Loop Left Join + Output: i8.q1, i8.q2, (i4.f1 + 1) + -> Seq Scan on public.int8_tbl i8 + Output: i8.q1, i8.q2 + Filter: (i8.q2 = 456) + -> Seq Scan on public.int4_tbl i4 + Output: i4.f1 + Filter: (i4.f1 = 1) + -> Index Only Scan using tenk1_unique2 on public.tenk1 t + Output: t.unique2 + Index Cond: (t.unique2 = ((i4.f1 + 1))) +(13 rows) + +select i8.*, ss.v, t.unique2 + from int8_tbl i8 + left join int4_tbl i4 on i4.f1 = 1 + left join lateral (select i4.f1 + 1 as v) as ss on true + left join tenk1 t on t.unique2 = ss.v +where q2 = 456; + q1 | q2 | v | unique2 +-----+-----+---+--------- + 123 | 456 | | +(1 row) + -- bug #8444: we've historically allowed duplicate aliases within aliased JOINs select * from int8_tbl x join (int4_tbl x cross join int4_tbl y) j on q1 = f1; -- error diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql index 9887fe0c0b3ef..6a209a27aa087 100644 --- a/src/test/regress/sql/join.sql +++ b/src/test/regress/sql/join.sql @@ -1696,6 +1696,22 @@ where ss.stringu2 !~* ss.case1; rollback; +-- test case to expose miscomputation of required relid set for a PHV +explain (verbose, costs off) +select i8.*, ss.v, t.unique2 + from int8_tbl i8 + left join int4_tbl i4 on i4.f1 = 1 + left join lateral (select i4.f1 + 1 as v) as ss on true + left join tenk1 t on t.unique2 = ss.v +where q2 = 456; + +select i8.*, ss.v, t.unique2 + from int8_tbl i8 + left join int4_tbl i4 on i4.f1 = 1 + left join lateral (select i4.f1 + 1 as v) as ss on true + left join tenk1 t on t.unique2 = ss.v +where q2 = 456; + -- bug #8444: we've historically allowed duplicate aliases within aliased JOINs select * from From 27a48e5a16ff2227ddf44ee717d9bcd89d22a7aa Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 21 Jan 2021 16:10:18 -0500 Subject: [PATCH 150/240] Improve new wording of libpq's connection failure messages. "connection to server so-and-so failed:" seems clearer than the previous wording "could not connect to so-and-so:" (introduced by 52a10224e), because the latter suggests a network-level connection failure. We're now prefixing this string to all types of connection failures, for instance authentication failures; so we need wording that doesn't imply a low-level error. Per discussion with Robert Haas. Discussion: https://postgr.es/m/CA+TgmobssJ6rS22dspWnu-oDxXevGmhMD8VcRBjmj-b9UDqRjw@mail.gmail.com --- src/bin/pg_dump/t/002_pg_dump.pl | 2 +- .../ecpg/test/expected/connect-test5.stderr | 4 +-- src/interfaces/ecpg/test/pg_regress_ecpg.c | 8 ++--- src/interfaces/libpq/fe-connect.c | 31 ++++++++++--------- 4 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl index 2b501166b80f5..a9bbb80e63996 100644 --- a/src/bin/pg_dump/t/002_pg_dump.pl +++ b/src/bin/pg_dump/t/002_pg_dump.pl @@ -3460,7 +3460,7 @@ command_fails_like( [ 'pg_dump', '-p', "$port", 'qqq' ], - qr/pg_dump: error: connection to database "qqq" failed: could not connect to .*: FATAL: database "qqq" does not exist/, + qr/pg_dump: error: connection to database "qqq" failed: connection to server .* failed: FATAL: database "qqq" does not exist/, 'connecting to a non-existent database'); ######################################### diff --git a/src/interfaces/ecpg/test/expected/connect-test5.stderr b/src/interfaces/ecpg/test/expected/connect-test5.stderr index 4dbf2c0fc4626..db3cd9c2285db 100644 --- a/src/interfaces/ecpg/test/expected/connect-test5.stderr +++ b/src/interfaces/ecpg/test/expected/connect-test5.stderr @@ -36,7 +36,7 @@ [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ECPGconnect: opening database on port for user regress_ecpg_user2 [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ECPGconnect: could not open database: could not connect: FATAL: database "regress_ecpg_user2" does not exist +[NO_PID]: ECPGconnect: could not open database: connection to server failed: FATAL: database "regress_ecpg_user2" does not exist [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ecpg_finish: connection main closed @@ -73,7 +73,7 @@ [NO_PID]: sqlca: code: -220, state: 08003 [NO_PID]: ECPGconnect: opening database on port for user regress_ecpg_user2 [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ECPGconnect: could not open database: could not connect: FATAL: database "regress_ecpg_user2" does not exist +[NO_PID]: ECPGconnect: could not open database: connection to server failed: FATAL: database "regress_ecpg_user2" does not exist [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ecpg_finish: connection main closed diff --git a/src/interfaces/ecpg/test/pg_regress_ecpg.c b/src/interfaces/ecpg/test/pg_regress_ecpg.c index 8d43fd65bad68..15f588a802309 100644 --- a/src/interfaces/ecpg/test/pg_regress_ecpg.c +++ b/src/interfaces/ecpg/test/pg_regress_ecpg.c @@ -80,7 +80,7 @@ ecpg_filter_source(const char *sourcefile, const char *outfile) } /* - * Remove the details of "could not connect to ...: " error messages + * Remove the details of connection failure error messages * in a test result file, since the target host/pathname and/or port * can vary. Rewrite the result file in-place. * @@ -113,15 +113,15 @@ ecpg_filter_stderr(const char *resultfile, const char *tmpfile) while (pg_get_line_buf(s, &linebuf)) { - char *p1 = strstr(linebuf.data, "could not connect to "); + char *p1 = strstr(linebuf.data, "connection to server "); if (p1) { - char *p2 = strstr(p1, ": "); + char *p2 = strstr(p1, "failed: "); if (p2) { - memmove(p1 + 17, p2, strlen(p2) + 1); + memmove(p1 + 21, p2, strlen(p2) + 1); /* we don't bother to fix up linebuf.len */ } } diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 2b78ed8ec3e34..8ca0583aa908d 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -1668,17 +1668,16 @@ getHostaddr(PGconn *conn, char *host_addr, int host_addr_len) host_addr[0] = '\0'; } -/* ---------- - * emitCouldNotConnect - - * Speculatively append "could not connect to ...: " to conn->errorMessage - * once we've identified the current connection target address. This ensures - * that any subsequent error message will be properly attributed to the - * server we couldn't connect to. conn->raddr must be valid, and the result - * of getHostaddr() must be supplied. - * ---------- +/* + * emitHostIdentityInfo - + * Speculatively append "connection to server so-and-so failed: " to + * conn->errorMessage once we've identified the current connection target + * address. This ensures that any subsequent error message will be properly + * attributed to the server we couldn't connect to. conn->raddr must be + * valid, and the result of getHostaddr() must be supplied. */ static void -emitCouldNotConnect(PGconn *conn, const char *host_addr) +emitHostIdentityInfo(PGconn *conn, const char *host_addr) { #ifdef HAVE_UNIX_SOCKETS if (IS_AF_UNIX(conn->raddr.addr.ss_family)) @@ -1690,7 +1689,7 @@ emitCouldNotConnect(PGconn *conn, const char *host_addr) service, sizeof(service), NI_NUMERICSERV); appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not connect to socket \"%s\": "), + libpq_gettext("connection to server on socket \"%s\" failed: "), service); } else @@ -1717,12 +1716,12 @@ emitCouldNotConnect(PGconn *conn, const char *host_addr) host_addr[0] && strcmp(displayed_host, host_addr) != 0) appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not connect to host \"%s\" (%s), port %s: "), + libpq_gettext("connection to server at \"%s\" (%s), port %s failed: "), displayed_host, host_addr, displayed_port); else appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not connect to host \"%s\", port %s: "), + libpq_gettext("connection to server at \"%s\", port %s failed: "), displayed_host, displayed_port); } @@ -2524,7 +2523,7 @@ PQconnectPoll(PGconn *conn) conn->try_next_addr = true; goto keep_going; } - emitCouldNotConnect(conn, host_addr); + emitHostIdentityInfo(conn, host_addr); appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not create socket: %s\n"), SOCK_STRERROR(errorno, sebuf, sizeof(sebuf))); @@ -2534,9 +2533,11 @@ PQconnectPoll(PGconn *conn) /* * Once we've identified a target address, all errors * except the preceding socket()-failure case should be - * prefixed with "could not connect to : ". + * prefixed with host-identity information. (If the + * connection succeeds, the contents of conn->errorMessage + * won't matter, so this is harmless.) */ - emitCouldNotConnect(conn, host_addr); + emitHostIdentityInfo(conn, host_addr); /* * Select socket options: no delay of outgoing data for From af0e79c8f4f4c3c2306855045c0d02a6be6485f0 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Fri, 22 Jan 2021 09:26:27 +0900 Subject: [PATCH 151/240] Move SSL information callback earlier to capture more information The callback for retrieving state change information during connection setup was only installed when the connection was mostly set up, and thus didn't provide much information and missed all the details related to the handshake. This also extends the callback with SSL_state_string_long() to print more information about the state change within the SSL object handled. While there, fix some comments which were incorrectly referring to the callback and its previous location in fe-secure.c. Author: Daniel Gustafsson Discussion: https://postgr.es/m/232CF476-94E1-42F1-9408-719E2AEC5491@yesql.se --- src/backend/libpq/be-secure-openssl.c | 26 ++++++++++++++---------- src/interfaces/libpq/fe-secure-openssl.c | 2 +- src/interfaces/libpq/fe-secure.c | 6 ------ 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c index 0494ad7ded918..1e2ecc6e7ab74 100644 --- a/src/backend/libpq/be-secure-openssl.c +++ b/src/backend/libpq/be-secure-openssl.c @@ -381,6 +381,9 @@ be_tls_open_server(Port *port) return -1; } + /* set up debugging/info callback */ + SSL_CTX_set_info_callback(SSL_context, info_cb); + if (!(port->ssl = SSL_new(SSL_context))) { ereport(COMMERROR, @@ -562,9 +565,6 @@ be_tls_open_server(Port *port) port->peer_cert_valid = true; } - /* set up debugging/info callback */ - SSL_CTX_set_info_callback(SSL_context, info_cb); - return 0; } @@ -999,39 +999,43 @@ verify_cb(int ok, X509_STORE_CTX *ctx) static void info_cb(const SSL *ssl, int type, int args) { + const char *desc; + + desc = SSL_state_string_long(ssl); + switch (type) { case SSL_CB_HANDSHAKE_START: ereport(DEBUG4, - (errmsg_internal("SSL: handshake start"))); + (errmsg_internal("SSL: handshake start: \"%s\"", desc))); break; case SSL_CB_HANDSHAKE_DONE: ereport(DEBUG4, - (errmsg_internal("SSL: handshake done"))); + (errmsg_internal("SSL: handshake done: \"%s\"", desc))); break; case SSL_CB_ACCEPT_LOOP: ereport(DEBUG4, - (errmsg_internal("SSL: accept loop"))); + (errmsg_internal("SSL: accept loop: \"%s\"", desc))); break; case SSL_CB_ACCEPT_EXIT: ereport(DEBUG4, - (errmsg_internal("SSL: accept exit (%d)", args))); + (errmsg_internal("SSL: accept exit (%d): \"%s\"", args, desc))); break; case SSL_CB_CONNECT_LOOP: ereport(DEBUG4, - (errmsg_internal("SSL: connect loop"))); + (errmsg_internal("SSL: connect loop: \"%s\"", desc))); break; case SSL_CB_CONNECT_EXIT: ereport(DEBUG4, - (errmsg_internal("SSL: connect exit (%d)", args))); + (errmsg_internal("SSL: connect exit (%d): \"%s\"", args, desc))); break; case SSL_CB_READ_ALERT: ereport(DEBUG4, - (errmsg_internal("SSL: read alert (0x%04x)", args))); + (errmsg_internal("SSL: read alert (0x%04x): \"%s\"", args, desc))); break; case SSL_CB_WRITE_ALERT: ereport(DEBUG4, - (errmsg_internal("SSL: write alert (0x%04x)", args))); + (errmsg_internal("SSL: write alert (0x%04x): \"%s\"", args, desc))); break; } } diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c index 075f754e1fb61..5b4a4157d5ce8 100644 --- a/src/interfaces/libpq/fe-secure-openssl.c +++ b/src/interfaces/libpq/fe-secure-openssl.c @@ -14,7 +14,7 @@ * NOTES * * We don't provide informational callbacks here (like - * info_cb() in be-secure.c), since there's no good mechanism to + * info_cb() in be-secure-openssl.c), since there's no good mechanism to * display such information to the user. * *------------------------------------------------------------------------- diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c index 67b1e78512973..00b87bdc96d7e 100644 --- a/src/interfaces/libpq/fe-secure.c +++ b/src/interfaces/libpq/fe-secure.c @@ -13,12 +13,6 @@ * IDENTIFICATION * src/interfaces/libpq/fe-secure.c * - * NOTES - * - * We don't provide informational callbacks here (like - * info_cb() in be-secure.c), since there's no good mechanism to - * display such information to the user. - * *------------------------------------------------------------------------- */ From 29ad6595ef7f568ca11dd9219c0d23048bdda513 Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Fri, 22 Jan 2021 11:10:42 +0200 Subject: [PATCH 152/240] doc: Copy-edit the "Overview of PostgreSQL Internals" chapter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rephrase a few sentences to be more concise. Refer to the postmaster process as "postmaster", not "postgres". This originally said "postmaster process", but was changed to "postgres process" in commit 5266f221a2, when we merged the "postmaster" and "postgres" commands, and "postmaster" became just a symlink. That was a case of overzealous search & replace, because the process is still called "postmaster". Author: Erik Rijkers and Jürgen Purtz Discussion: https://www.postgresql.org/message-id/aa31f359-1168-ded5-53d0-0ed228bfe097%40iki.fi --- doc/src/sgml/arch-dev.sgml | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/doc/src/sgml/arch-dev.sgml b/doc/src/sgml/arch-dev.sgml index ade0ad97d8e17..e56a13283fa9e 100644 --- a/doc/src/sgml/arch-dev.sgml +++ b/doc/src/sgml/arch-dev.sgml @@ -7,7 +7,7 @@ Author This chapter originated as part of - , Stefan Simkovics' + Stefan Simkovics' Master's Thesis prepared at Vienna University of Technology under the direction of O.Univ.Prof.Dr. Georg Gottlob and Univ.Ass. Mag. Katrin Seyr. @@ -17,10 +17,7 @@ This chapter gives an overview of the internal structure of the backend of PostgreSQL. After having read the following sections you should have an idea of how a query - is processed. This chapter does not aim to provide a detailed - description of the internal operation of - PostgreSQL, as such a document would be - very extensive. Rather, this chapter is intended to help the reader + is processed. This chapter is intended to help the reader understand the general sequence of operations that occur within the backend from the point at which a query is received, to the point at which the results are returned to the client. @@ -30,8 +27,8 @@ The Path of a Query - Here we give a short overview of the stages a query has to pass in - order to obtain a result. + Here we give a short overview of the stages a query has to pass + to obtain a result. @@ -125,10 +122,10 @@ use a supervisor process (also master process) that spawns a new server process every time a connection is requested. This supervisor - process is called postgres and listens at a + process is called postmaster and listens at a specified TCP/IP port for incoming connections. Whenever a request - for a connection is detected the postgres - process spawns a new server process. The server tasks + for a connection is detected the postmaster + process spawns a new server process. The server processes communicate with each other using semaphores and shared memory to ensure data integrity throughout concurrent data access. @@ -230,7 +227,7 @@ A detailed description of bison or the grammar rules given in gram.y would be - beyond the scope of this paper. There are many books and + beyond the scope of this manual. There are many books and documents dealing with flex and bison. You should be familiar with bison before you start to study the @@ -343,8 +340,8 @@ In some situations, examining each possible way in which a query - can be executed would take an excessive amount of time and memory - space. In particular, this occurs when executing queries + can be executed would take an excessive amount of time and memory. + In particular, this occurs when executing queries involving large numbers of join operations. In order to determine a reasonable (not necessarily optimal) query plan in a reasonable amount of time, PostgreSQL uses a Genetic @@ -411,7 +408,7 @@ merge join: Each relation is sorted on the join attributes before the join starts. Then the two relations are scanned in parallel, and matching rows are combined to form - join rows. This kind of join is more + join rows. This kind of join is attractive because each relation has to be scanned only once. The required sorting might be achieved either by an explicit sort step, or by scanning the relation in the proper order using an @@ -442,7 +439,7 @@ If the query uses fewer than relations, a near-exhaustive search is conducted to find the best join sequence. The planner preferentially considers joins between any - two relations for which there exist a corresponding join clause in the + two relations for which there exists a corresponding join clause in the WHERE qualification (i.e., for which a restriction like where rel1.attr1=rel2.attr2 exists). Join pairs with no join clause are considered only when there From 09418bed67a7d5d5a8c9c3070f4c9048455a5389 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Fri, 22 Jan 2021 11:58:21 +0100 Subject: [PATCH 153/240] Remove bogus tracepoint Calls to LWLockWaitForVar() fired the TRACE_POSTGRESQL_LWLOCK_ACQUIRE tracepoint, but LWLockWaitForVar() never actually acquires the LWLock. (Probably a copy/paste bug in 68a2e52bbaf.) Remove it. Author: Craig Ringer Discussion: https://www.postgresql.org/message-id/flat/CAGRY4nxJo+-HCC2i5H93ttSZ4gZO-FSddCwvkb-qAfQ1zdXd1w@mail.gmail.com --- src/backend/storage/lmgr/lwlock.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c index db7e59f8b70b6..8cb6a6f042ad8 100644 --- a/src/backend/storage/lmgr/lwlock.c +++ b/src/backend/storage/lmgr/lwlock.c @@ -1725,8 +1725,6 @@ LWLockWaitForVar(LWLock *lock, uint64 *valptr, uint64 oldval, uint64 *newval) /* Now loop back and check the status of the lock again. */ } - TRACE_POSTGRESQL_LWLOCK_ACQUIRE(T_NAME(lock), LW_EXCLUSIVE); - /* * Fix the process wait semaphore's count for any absorbed wakeups. */ From 0a9ae44288d122c12aa0862b032ae892942da452 Mon Sep 17 00:00:00 2001 From: Magnus Hagander Date: Fri, 22 Jan 2021 12:49:53 +0100 Subject: [PATCH 154/240] Remove reference to ftp servers from documentation It's been a long time since we used ftp, but there was a single reference left in the docs. Author: Daniel Gustafsson Discussion: https://postgr.es/m/6880D602-7286-46EC-8A03-14E3248FEC7A@yesql.se --- doc/src/sgml/install-windows.sgml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/src/sgml/install-windows.sgml b/doc/src/sgml/install-windows.sgml index 844ef2cbd29af..47e5f7c8ae43b 100644 --- a/doc/src/sgml/install-windows.sgml +++ b/doc/src/sgml/install-windows.sgml @@ -257,7 +257,8 @@ $ENV{MSBFLAGS}="/m"; - The obsolete winflex binaries distributed on the PostgreSQL FTP site + The obsolete winflex binaries distributed in the + downloads section of the PostgreSQL web site and referenced in older documentation will fail with flex: fatal internal error, exec failed on 64-bit Windows hosts. Use Flex from MSYS instead. From ab66645628d38a7047996b294b213f3048f7ef9b Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 22 Jan 2021 11:29:43 -0500 Subject: [PATCH 155/240] Doc: remove misleading claim in documentation of PQreset(). This text claimed that the reconnection would occur "to the same server", but there is no such guarantee in the code, nor would insisting on that be an improvement. Back-patch to v10 where multi-host connection strings were added. Discussion: https://postgr.es/m/1095901.1611268376@sss.pgh.pa.us --- doc/src/sgml/libpq.sgml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 2bb3bf77e432d..b22cb38ca3b29 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -645,8 +645,8 @@ void PQreset(PGconn *conn); This function will close the connection - to the server and attempt to reestablish a new - connection to the same server, using all the same + to the server and attempt to establish a new + connection, using all the same parameters previously used. This might be useful for error recovery if a working connection is lost. @@ -669,7 +669,7 @@ PostgresPollingStatusType PQresetPoll(PGconn *conn); These functions will close the connection to the server and attempt to - reestablish a new connection to the same server, using all the same + establish a new connection, using all the same parameters previously used. This can be useful for error recovery if a working connection is lost. They differ from (above) in that they act in a nonblocking manner. These functions suffer from the same From 7cd9765f9bd3397b8d4d0f507021ef848b6d48d2 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 22 Jan 2021 16:26:22 -0500 Subject: [PATCH 156/240] Re-allow DISTINCT in pl/pgsql expressions. I'd omitted this from the grammar in commit c9d529848, figuring that it wasn't worth supporting. However we already have one complaint, so it seems that judgment was wrong. It doesn't require a huge amount of code, so add it back. (I'm still drawing the line at UNION/INTERSECT/EXCEPT though: those'd require an unreasonable amount of grammar refactoring, and the single-result-row restriction makes them near useless anyway.) Also rethink the documentation: this behavior is a property of all pl/pgsql expressions, not just assignments. Discussion: https://postgr.es/m/20210122134106.e94c5cd7@mail.verfriemelt.org --- doc/src/sgml/plpgsql.sgml | 32 ++++++++++++++------------ src/backend/parser/analyze.c | 29 ++++++++++++++++++++---- src/backend/parser/gram.y | 44 +++++++++++++++++++++++------------- 3 files changed, 70 insertions(+), 35 deletions(-) diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml index 45d3e43ed14e9..9d41967ad3a18 100644 --- a/doc/src/sgml/plpgsql.sgml +++ b/doc/src/sgml/plpgsql.sgml @@ -917,6 +917,24 @@ PREPARE statement_name(integer, integer) AS SELECT $1 they are useful to know when trying to diagnose a problem. More information appears in . + + + Since an expression is converted to a + SELECT command, it can contain the same clauses + that an ordinary SELECT would, except that it + cannot include a top-level UNION, + INTERSECT, or EXCEPT clause. + Thus for example one could test whether a table is non-empty with + +IF count(*) > 0 FROM my_table THEN ... + + since the expression + between IF and THEN is parsed as + though it were SELECT count(*) > 0 FROM my_table. + The SELECT must produce a single column, and not + more than one row. (If it produces no rows, the result is taken as + NULL.) + @@ -973,20 +991,6 @@ my_array[1:3] := array[1,2,3]; complex_array[n].realpart = 12.3; - - - It's useful to know that what follows the assignment operator is - essentially treated as a SELECT command; as long - as it returns a single row and column, it will work. Thus for example - one can write something like - -total_sales := sum(quantity) from sales; - - This provides an effect similar to the single-row SELECT - ... INTO syntax described in - . However, that syntax - is more portable. - diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 28e192f51c851..65483892252f3 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -2466,7 +2466,7 @@ transformPLAssignStmt(ParseState *pstate, PLAssignStmt *stmt) /* * The rest mostly matches transformSelectStmt, except that we needn't - * consider WITH or DISTINCT, and we build a targetlist our own way. + * consider WITH or INTO, and we build a targetlist our own way. */ qry->commandType = CMD_SELECT; pstate->p_is_insert = false; @@ -2590,10 +2590,29 @@ transformPLAssignStmt(ParseState *pstate, PLAssignStmt *stmt) EXPR_KIND_GROUP_BY, false /* allow SQL92 rules */ ); - /* No DISTINCT clause */ - Assert(!sstmt->distinctClause); - qry->distinctClause = NIL; - qry->hasDistinctOn = false; + if (sstmt->distinctClause == NIL) + { + qry->distinctClause = NIL; + qry->hasDistinctOn = false; + } + else if (linitial(sstmt->distinctClause) == NULL) + { + /* We had SELECT DISTINCT */ + qry->distinctClause = transformDistinctClause(pstate, + &qry->targetList, + qry->sortClause, + false); + qry->hasDistinctOn = false; + } + else + { + /* We had SELECT DISTINCT ON */ + qry->distinctClause = transformDistinctOnClause(pstate, + sstmt->distinctClause, + &qry->targetList, + qry->sortClause); + qry->hasDistinctOn = true; + } /* transform LIMIT */ qry->limitOffset = transformLimitClause(pstate, sstmt->limitOffset, diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 31c95443a5bf4..7574d545e0e02 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -389,7 +389,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); OptTableElementList TableElementList OptInherit definition OptTypedTableElementList TypedTableElementList reloptions opt_reloptions - OptWith distinct_clause opt_definition func_args func_args_list + OptWith opt_definition func_args func_args_list func_args_with_defaults func_args_with_defaults_list aggr_args aggr_args_list func_as createfunc_opt_list alterfunc_opt_list @@ -401,6 +401,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); name_list role_list from_clause from_list opt_array_bounds qualified_name_list any_name any_name_list type_name_list any_operator expr_list attrs + distinct_clause opt_distinct_clause target_list opt_target_list insert_column_list set_target_list set_clause_list set_clause def_list operator_def_list indirection opt_indirection @@ -11260,6 +11261,11 @@ select_clause: * As with select_no_parens, simple_select cannot have outer parentheses, * but can have parenthesized subclauses. * + * It might appear that we could fold the first two alternatives into one + * by using opt_distinct_clause. However, that causes a shift/reduce conflict + * against INSERT ... SELECT ... ON CONFLICT. We avoid the ambiguity by + * requiring SELECT DISTINCT [ON] to be followed by a non-empty target_list. + * * Note that sort clauses cannot be included at this level --- SQL requires * SELECT foo UNION SELECT bar ORDER BY baz * to be parsed as @@ -11497,8 +11503,13 @@ opt_all_clause: | /*EMPTY*/ ; +opt_distinct_clause: + distinct_clause { $$ = $1; } + | opt_all_clause { $$ = NIL; } + ; + opt_sort_clause: - sort_clause { $$ = $1;} + sort_clause { $$ = $1; } | /*EMPTY*/ { $$ = NIL; } ; @@ -15065,32 +15076,33 @@ role_list: RoleSpec * Therefore the returned struct is a SelectStmt. *****************************************************************************/ -PLpgSQL_Expr: opt_target_list +PLpgSQL_Expr: opt_distinct_clause opt_target_list from_clause where_clause group_clause having_clause window_clause opt_sort_clause opt_select_limit opt_for_locking_clause { SelectStmt *n = makeNode(SelectStmt); - n->targetList = $1; - n->fromClause = $2; - n->whereClause = $3; - n->groupClause = $4; - n->havingClause = $5; - n->windowClause = $6; - n->sortClause = $7; - if ($8) + n->distinctClause = $1; + n->targetList = $2; + n->fromClause = $3; + n->whereClause = $4; + n->groupClause = $5; + n->havingClause = $6; + n->windowClause = $7; + n->sortClause = $8; + if ($9) { - n->limitOffset = $8->limitOffset; - n->limitCount = $8->limitCount; + n->limitOffset = $9->limitOffset; + n->limitCount = $9->limitCount; if (!n->sortClause && - $8->limitOption == LIMIT_OPTION_WITH_TIES) + $9->limitOption == LIMIT_OPTION_WITH_TIES) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("WITH TIES cannot be specified without ORDER BY clause"))); - n->limitOption = $8->limitOption; + n->limitOption = $9->limitOption; } - n->lockingClause = $9; + n->lockingClause = $10; $$ = (Node *) n; } ; From 58cd8dca3de0b3c7d378a412eca1f7289b5e4978 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 22 Jan 2021 16:52:31 -0500 Subject: [PATCH 157/240] Avoid redundantly prefixing PQerrorMessage for a connection failure. libpq's error messages for connection failures pretty well stand on their own, especially since commits 52a10224e/27a48e5a1. Prefixing them with 'could not connect to database "foo"' or the like is just redundant, and perhaps even misleading if the specific database name isn't relevant to the failure. (When it is, we trust that the backend's error message will include the DB name.) Indeed, psql hasn't used any such prefix in a long time. So, make all our other programs and documentation examples agree with psql's practice. Discussion: https://postgr.es/m/1094524.1611266589@sss.pgh.pa.us --- contrib/oid2name/oid2name.c | 3 +-- contrib/vacuumlo/vacuumlo.c | 3 +-- doc/src/sgml/libpq.sgml | 13 +++++-------- doc/src/sgml/lobj.sgml | 3 +-- src/bin/pg_dump/pg_backup_db.c | 6 ++---- src/bin/pg_dump/pg_dumpall.c | 3 +-- src/bin/pg_dump/t/002_pg_dump.pl | 2 +- src/bin/pg_upgrade/server.c | 8 ++++---- src/bin/pgbench/pgbench.c | 3 +-- src/bin/pgbench/t/001_pgbench_with_server.pl | 2 +- src/bin/scripts/common.c | 3 +-- src/interfaces/ecpg/ecpglib/connect.c | 3 ++- .../ecpg/test/expected/connect-test5.stderr | 6 ++---- src/test/examples/testlibpq.c | 3 +-- src/test/examples/testlibpq2.c | 3 +-- src/test/examples/testlibpq3.c | 3 +-- src/test/examples/testlibpq4.c | 3 +-- src/test/examples/testlo.c | 3 +-- src/test/examples/testlo64.c | 3 +-- src/test/isolation/isolationtester.c | 2 +- src/tools/findoidjoins/findoidjoins.c | 2 +- 21 files changed, 31 insertions(+), 49 deletions(-) diff --git a/contrib/oid2name/oid2name.c b/contrib/oid2name/oid2name.c index 5a884e29049f8..65cce4999366b 100644 --- a/contrib/oid2name/oid2name.c +++ b/contrib/oid2name/oid2name.c @@ -347,8 +347,7 @@ sql_conn(struct options *my_opts) /* check to see that the backend connection was successfully made */ if (PQstatus(conn) == CONNECTION_BAD) { - pg_log_error("could not connect to database %s: %s", - my_opts->dbname, PQerrorMessage(conn)); + pg_log_error("%s", PQerrorMessage(conn)); PQfinish(conn); exit(1); } diff --git a/contrib/vacuumlo/vacuumlo.c b/contrib/vacuumlo/vacuumlo.c index cdc2c02b8e825..dcb95c4320470 100644 --- a/contrib/vacuumlo/vacuumlo.c +++ b/contrib/vacuumlo/vacuumlo.c @@ -124,8 +124,7 @@ vacuumlo(const char *database, const struct _param *param) /* check to see that the backend connection was successfully made */ if (PQstatus(conn) == CONNECTION_BAD) { - pg_log_error("connection to database \"%s\" failed: %s", - database, PQerrorMessage(conn)); + pg_log_error("%s", PQerrorMessage(conn)); PQfinish(conn); return -1; } diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index b22cb38ca3b29..b7a82453f0da1 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -6837,8 +6837,8 @@ main(void) if (PQstatus(conn) != CONNECTION_OK) { - fprintf(stderr, "Connection to database failed: %s", - PQerrorMessage(conn)); + /* PQerrorMessage's result includes a trailing newline */ + fprintf(stderr, "%s", PQerrorMessage(conn)); PQfinish(conn); return 1; } @@ -8296,8 +8296,7 @@ main(int argc, char **argv) /* Check to see that the backend connection was successfully made */ if (PQstatus(conn) != CONNECTION_OK) { - fprintf(stderr, "Connection to database failed: %s", - PQerrorMessage(conn)); + fprintf(stderr, "%s", PQerrorMessage(conn)); exit_nicely(conn); } @@ -8466,8 +8465,7 @@ main(int argc, char **argv) /* Check to see that the backend connection was successfully made */ if (PQstatus(conn) != CONNECTION_OK) { - fprintf(stderr, "Connection to database failed: %s", - PQerrorMessage(conn)); + fprintf(stderr, "%s", PQerrorMessage(conn)); exit_nicely(conn); } @@ -8694,8 +8692,7 @@ main(int argc, char **argv) /* Check to see that the backend connection was successfully made */ if (PQstatus(conn) != CONNECTION_OK) { - fprintf(stderr, "Connection to database failed: %s", - PQerrorMessage(conn)); + fprintf(stderr, "%s", PQerrorMessage(conn)); exit_nicely(conn); } diff --git a/doc/src/sgml/lobj.sgml b/doc/src/sgml/lobj.sgml index 413eda50af370..6d46da42e27b1 100644 --- a/doc/src/sgml/lobj.sgml +++ b/doc/src/sgml/lobj.sgml @@ -939,8 +939,7 @@ main(int argc, char **argv) /* check to see that the backend connection was successfully made */ if (PQstatus(conn) != CONNECTION_OK) { - fprintf(stderr, "Connection to database failed: %s", - PQerrorMessage(conn)); + fprintf(stderr, "%s", PQerrorMessage(conn)); exit_nicely(conn); } diff --git a/src/bin/pg_dump/pg_backup_db.c b/src/bin/pg_dump/pg_backup_db.c index 5ba43441f50aa..2856c16e853db 100644 --- a/src/bin/pg_dump/pg_backup_db.c +++ b/src/bin/pg_dump/pg_backup_db.c @@ -188,12 +188,10 @@ ConnectDatabase(Archive *AHX, if (PQstatus(AH->connection) == CONNECTION_BAD) { if (isReconnect) - fatal("reconnection to database \"%s\" failed: %s", - PQdb(AH->connection) ? PQdb(AH->connection) : "", + fatal("reconnection failed: %s", PQerrorMessage(AH->connection)); else - fatal("connection to database \"%s\" failed: %s", - PQdb(AH->connection) ? PQdb(AH->connection) : "", + fatal("%s", PQerrorMessage(AH->connection)); } diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c index 85d08ad660376..007a3d0f9a372 100644 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.c @@ -1768,8 +1768,7 @@ connectDatabase(const char *dbname, const char *connection_string, { if (fail_on_error) { - pg_log_error("could not connect to database \"%s\": %s", - dbname, PQerrorMessage(conn)); + pg_log_error("%s", PQerrorMessage(conn)); exit_nicely(1); } else diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl index a9bbb80e63996..798884da36b12 100644 --- a/src/bin/pg_dump/t/002_pg_dump.pl +++ b/src/bin/pg_dump/t/002_pg_dump.pl @@ -3460,7 +3460,7 @@ command_fails_like( [ 'pg_dump', '-p', "$port", 'qqq' ], - qr/pg_dump: error: connection to database "qqq" failed: connection to server .* failed: FATAL: database "qqq" does not exist/, + qr/pg_dump: error: connection to server .* failed: FATAL: database "qqq" does not exist/, 'connecting to a non-existent database'); ######################################### diff --git a/src/bin/pg_upgrade/server.c b/src/bin/pg_upgrade/server.c index 31b1425202915..7fed0ae1086dc 100644 --- a/src/bin/pg_upgrade/server.c +++ b/src/bin/pg_upgrade/server.c @@ -30,8 +30,7 @@ connectToServer(ClusterInfo *cluster, const char *db_name) if (conn == NULL || PQstatus(conn) != CONNECTION_OK) { - pg_log(PG_REPORT, "connection to database failed: %s", - PQerrorMessage(conn)); + pg_log(PG_REPORT, "%s", PQerrorMessage(conn)); if (conn) PQfinish(conn); @@ -50,6 +49,8 @@ connectToServer(ClusterInfo *cluster, const char *db_name) * get_db_conn() * * get database connection, using named database + standard params for cluster + * + * Caller must check for connection failure! */ static PGconn * get_db_conn(ClusterInfo *cluster, const char *db_name) @@ -294,8 +295,7 @@ start_postmaster(ClusterInfo *cluster, bool report_and_exit_on_error) if ((conn = get_db_conn(cluster, "template1")) == NULL || PQstatus(conn) != CONNECTION_OK) { - pg_log(PG_REPORT, "\nconnection to database failed: %s", - PQerrorMessage(conn)); + pg_log(PG_REPORT, "\n%s", PQerrorMessage(conn)); if (conn) PQfinish(conn); if (cluster == &old_cluster) diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index f7da3e1f62692..1be1ad3d6d959 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -1225,8 +1225,7 @@ doConnect(void) /* check to see that the backend connection was successfully made */ if (PQstatus(conn) == CONNECTION_BAD) { - pg_log_error("connection to database \"%s\" failed: %s", - dbName, PQerrorMessage(conn)); + pg_log_error("%s", PQerrorMessage(conn)); PQfinish(conn); return NULL; } diff --git a/src/bin/pgbench/t/001_pgbench_with_server.pl b/src/bin/pgbench/t/001_pgbench_with_server.pl index 61b671d54fd66..daffc18e52194 100644 --- a/src/bin/pgbench/t/001_pgbench_with_server.pl +++ b/src/bin/pgbench/t/001_pgbench_with_server.pl @@ -90,7 +90,7 @@ sub pgbench 1, [qr{^$}], [ - qr{connection to database "no-such-database" failed}, + qr{connection to server .* failed}, qr{FATAL: database "no-such-database" does not exist} ], 'no such database'); diff --git a/src/bin/scripts/common.c b/src/bin/scripts/common.c index 13ac531695064..21ef297e6eb65 100644 --- a/src/bin/scripts/common.c +++ b/src/bin/scripts/common.c @@ -150,8 +150,7 @@ connectDatabase(const ConnParams *cparams, const char *progname, PQfinish(conn); return NULL; } - pg_log_error("could not connect to database %s: %s", - cparams->dbname, PQerrorMessage(conn)); + pg_log_error("%s", PQerrorMessage(conn)); exit(1); } diff --git a/src/interfaces/ecpg/ecpglib/connect.c b/src/interfaces/ecpg/ecpglib/connect.c index 1cb52116f95d7..6b0a3067e6c12 100644 --- a/src/interfaces/ecpg/ecpglib/connect.c +++ b/src/interfaces/ecpg/ecpglib/connect.c @@ -652,7 +652,8 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p const char *errmsg = PQerrorMessage(this->connection); const char *db = realname ? realname : ecpg_gettext(""); - ecpg_log("ECPGconnect: could not open database: %s\n", errmsg); + /* PQerrorMessage's result already has a trailing newline */ + ecpg_log("ECPGconnect: %s", errmsg); ecpg_finish(this); #ifdef ENABLE_THREAD_SAFETY diff --git a/src/interfaces/ecpg/test/expected/connect-test5.stderr b/src/interfaces/ecpg/test/expected/connect-test5.stderr index db3cd9c2285db..a15f3443204f0 100644 --- a/src/interfaces/ecpg/test/expected/connect-test5.stderr +++ b/src/interfaces/ecpg/test/expected/connect-test5.stderr @@ -36,8 +36,7 @@ [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ECPGconnect: opening database on port for user regress_ecpg_user2 [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ECPGconnect: could not open database: connection to server failed: FATAL: database "regress_ecpg_user2" does not exist - +[NO_PID]: ECPGconnect: connection to server failed: FATAL: database "regress_ecpg_user2" does not exist [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ecpg_finish: connection main closed [NO_PID]: sqlca: code: 0, state: 00000 @@ -73,8 +72,7 @@ [NO_PID]: sqlca: code: -220, state: 08003 [NO_PID]: ECPGconnect: opening database on port for user regress_ecpg_user2 [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ECPGconnect: could not open database: connection to server failed: FATAL: database "regress_ecpg_user2" does not exist - +[NO_PID]: ECPGconnect: connection to server failed: FATAL: database "regress_ecpg_user2" does not exist [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ecpg_finish: connection main closed [NO_PID]: sqlca: code: 0, state: 00000 diff --git a/src/test/examples/testlibpq.c b/src/test/examples/testlibpq.c index 18c98083de94d..0372781eaf27b 100644 --- a/src/test/examples/testlibpq.c +++ b/src/test/examples/testlibpq.c @@ -43,8 +43,7 @@ main(int argc, char **argv) /* Check to see that the backend connection was successfully made */ if (PQstatus(conn) != CONNECTION_OK) { - fprintf(stderr, "Connection to database failed: %s", - PQerrorMessage(conn)); + fprintf(stderr, "%s", PQerrorMessage(conn)); exit_nicely(conn); } diff --git a/src/test/examples/testlibpq2.c b/src/test/examples/testlibpq2.c index 511246763a6b8..6337b315a4299 100644 --- a/src/test/examples/testlibpq2.c +++ b/src/test/examples/testlibpq2.c @@ -72,8 +72,7 @@ main(int argc, char **argv) /* Check to see that the backend connection was successfully made */ if (PQstatus(conn) != CONNECTION_OK) { - fprintf(stderr, "Connection to database failed: %s", - PQerrorMessage(conn)); + fprintf(stderr, "%s", PQerrorMessage(conn)); exit_nicely(conn); } diff --git a/src/test/examples/testlibpq3.c b/src/test/examples/testlibpq3.c index dda45af859ab5..4f7b791388975 100644 --- a/src/test/examples/testlibpq3.c +++ b/src/test/examples/testlibpq3.c @@ -138,8 +138,7 @@ main(int argc, char **argv) /* Check to see that the backend connection was successfully made */ if (PQstatus(conn) != CONNECTION_OK) { - fprintf(stderr, "Connection to database failed: %s", - PQerrorMessage(conn)); + fprintf(stderr, "%s", PQerrorMessage(conn)); exit_nicely(conn); } diff --git a/src/test/examples/testlibpq4.c b/src/test/examples/testlibpq4.c index df8e454b5dfcf..dd11bbc46dc3d 100644 --- a/src/test/examples/testlibpq4.c +++ b/src/test/examples/testlibpq4.c @@ -29,8 +29,7 @@ check_prepare_conn(PGconn *conn, const char *dbName) /* check to see that the backend connection was successfully made */ if (PQstatus(conn) != CONNECTION_OK) { - fprintf(stderr, "Connection to database \"%s\" failed: %s", - dbName, PQerrorMessage(conn)); + fprintf(stderr, "%s", PQerrorMessage(conn)); exit(1); } diff --git a/src/test/examples/testlo.c b/src/test/examples/testlo.c index fa8da58e1b379..6d91681bcf829 100644 --- a/src/test/examples/testlo.c +++ b/src/test/examples/testlo.c @@ -225,8 +225,7 @@ main(int argc, char **argv) /* check to see that the backend connection was successfully made */ if (PQstatus(conn) != CONNECTION_OK) { - fprintf(stderr, "Connection to database failed: %s", - PQerrorMessage(conn)); + fprintf(stderr, "%s", PQerrorMessage(conn)); exit_nicely(conn); } diff --git a/src/test/examples/testlo64.c b/src/test/examples/testlo64.c index 6334171163ae2..23e910944683f 100644 --- a/src/test/examples/testlo64.c +++ b/src/test/examples/testlo64.c @@ -249,8 +249,7 @@ main(int argc, char **argv) /* check to see that the backend connection was successfully made */ if (PQstatus(conn) != CONNECTION_OK) { - fprintf(stderr, "Connection to database failed: %s", - PQerrorMessage(conn)); + fprintf(stderr, "%s", PQerrorMessage(conn)); exit_nicely(conn); } diff --git a/src/test/isolation/isolationtester.c b/src/test/isolation/isolationtester.c index f80261c022950..0a73d38daeb39 100644 --- a/src/test/isolation/isolationtester.c +++ b/src/test/isolation/isolationtester.c @@ -167,7 +167,7 @@ main(int argc, char **argv) conns[i] = PQconnectdb(conninfo); if (PQstatus(conns[i]) != CONNECTION_OK) { - fprintf(stderr, "Connection %d to database failed: %s", + fprintf(stderr, "Connection %d failed: %s", i, PQerrorMessage(conns[i])); exit(1); } diff --git a/src/tools/findoidjoins/findoidjoins.c b/src/tools/findoidjoins/findoidjoins.c index a42c8a34da2fc..f882c8b0ef244 100644 --- a/src/tools/findoidjoins/findoidjoins.c +++ b/src/tools/findoidjoins/findoidjoins.c @@ -44,7 +44,7 @@ main(int argc, char **argv) conn = PQconnectdb(sql.data); if (PQstatus(conn) == CONNECTION_BAD) { - fprintf(stderr, "connection error: %s\n", PQerrorMessage(conn)); + fprintf(stderr, "%s", PQerrorMessage(conn)); exit(EXIT_FAILURE); } From 50bebc1ae1804e0ddf86b667122d3f8b22fa19b7 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 22 Jan 2021 18:58:25 -0500 Subject: [PATCH 158/240] Doc: improve directions for building on macOS. In light of recent discussions, we should instruct people to install Apple's command line tools; installing Xcode is secondary. Also, fix sample command for finding out the default sysroot, as we now know that the command originally recommended can give a result that doesn't match your OS version. Also document the workaround to use if you really don't want configure to select a sysroot at all. Discussion: https://postgr.es/m/20210119111625.20435-1-james.hilliard1@gmail.com --- doc/src/sgml/installation.sgml | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml index 0ac1cb999992f..a53389b728e39 100644 --- a/doc/src/sgml/installation.sgml +++ b/doc/src/sgml/installation.sgml @@ -2353,6 +2353,17 @@ make MAX_CONNECTIONS=5 check installation on + + To build PostgreSQL from source + on macOS, you will need to install Apple's + command line developer tools, which can be done by issuing + +xcode-select --install + + (note that this will pop up a GUI dialog window for confirmation). + You may or may not wish to also install Xcode. + + On recent macOS releases, it's necessary to embed the sysroot path in the include switches used to @@ -2369,7 +2380,7 @@ make PG_SYSROOT=/desired/path all To find out the appropriate path on your machine, run -xcodebuild -version -sdk macosx Path +xcrun --show-sdk-path Note that building an extension using a different sysroot version than was used to build the core server is not really recommended; in the @@ -2383,6 +2394,19 @@ xcodebuild -version -sdk macosx Path ./configure ... PG_SYSROOT=/desired/path + This would primarily be useful to cross-compile for some other + macOS version. There is no guarantee that the resulting executables + will run on the current host. + + + + To suppress the options altogether, use + +./configure ... PG_SYSROOT=none + + (any nonexistent pathname will work). This might be useful if you wish + to build with a non-Apple compiler, but beware that that case is not + tested or supported by the PostgreSQL developers. From 3fc81ce459e1696f7e5e5b3b8229409413bf64b4 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 22 Jan 2021 19:25:39 -0500 Subject: [PATCH 159/240] Suppress bison warning in ecpg grammar. opt_distinct_clause is only used in PLpgSQL_Expr, which ecpg ignores, so it needs to ignore opt_distinct_clause too. My oversight in 7cd9765f9; reported by Bruce Momjian. Discussion: https://postgr.es/m/E1l33wr-0005sJ-9n@gemulon.postgresql.org --- src/interfaces/ecpg/preproc/parse.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/interfaces/ecpg/preproc/parse.pl b/src/interfaces/ecpg/preproc/parse.pl index a84243fc8f0e7..e46d2a589b432 100644 --- a/src/interfaces/ecpg/preproc/parse.pl +++ b/src/interfaces/ecpg/preproc/parse.pl @@ -71,6 +71,7 @@ 'type_function_name' => 'ignore', 'ColLabel' => 'ignore', 'Sconst' => 'ignore', + 'opt_distinct_clause' => 'ignore', 'PLpgSQL_Expr' => 'ignore', 'PLAssignStmt' => 'ignore', 'plassign_target' => 'ignore', From a8ed6bb8f4cf259b95c1bff5da09a8f4c79dca46 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Sat, 23 Jan 2021 11:33:04 +0900 Subject: [PATCH 160/240] Introduce SHA1 implementations in the cryptohash infrastructure With this commit, SHA1 goes through the implementation provided by OpenSSL via EVP when building the backend with it, and uses as fallback implementation KAME which was located in pgcrypto and already shaped for an integration with a set of init, update and final routines. Structures and routines have been renamed to make things consistent with the fallback implementations of MD5 and SHA2. uuid-ossp has used for ages a shortcut with pgcrypto to fetch a copy of SHA1 if needed. This was built depending on the build options within ./configure, so this cleans up some code and removes the build dependency between pgcrypto and uuid-ossp. Note that this will help with the refactoring of HMAC, as pgcrypto offers the option to use MD5, SHA1 or SHA2, so only the second option was missing to make that possible. Author: Michael Paquier Reviewed-by: Heikki Linnakangas Discussion: https://postgr.es/m/X9HXKTgrvJvYO7Oh@paquier.xyz --- configure | 19 +- configure.ac | 24 +- contrib/pgcrypto/Makefile | 2 +- contrib/pgcrypto/internal.c | 34 +- contrib/pgcrypto/sha1.c | 331 ---------------- contrib/uuid-ossp/.gitignore | 1 - contrib/uuid-ossp/Makefile | 6 - contrib/uuid-ossp/uuid-ossp.c | 27 +- src/Makefile.global.in | 1 - src/common/Makefile | 1 + src/common/cryptohash.c | 11 + src/common/cryptohash_openssl.c | 3 + src/common/sha1.c | 369 ++++++++++++++++++ .../pgcrypto/sha1.h => src/common/sha1_int.h | 44 ++- src/include/common/cryptohash.h | 1 + src/include/common/sha1.h | 19 + src/tools/msvc/Mkvcbuild.pm | 9 +- src/tools/pgindent/typedefs.list | 1 + 18 files changed, 479 insertions(+), 424 deletions(-) delete mode 100644 contrib/pgcrypto/sha1.c create mode 100644 src/common/sha1.c rename contrib/pgcrypto/sha1.h => src/common/sha1_int.h (71%) create mode 100644 src/include/common/sha1.h diff --git a/configure b/configure index 8af4b990218cc..e202697bbfade 100755 --- a/configure +++ b/configure @@ -705,7 +705,6 @@ XML2_LIBS XML2_CFLAGS XML2_CONFIG with_libxml -UUID_EXTRA_OBJS with_uuid with_readline with_systemd @@ -8303,30 +8302,26 @@ if test "$with_ossp_uuid" = yes ; then with_uuid=ossp fi -if test "$with_uuid" = bsd ; then +if test "$with_uuid" != no ; then + if test "$with_uuid" = bsd ; then $as_echo "#define HAVE_UUID_BSD 1" >>confdefs.h - UUID_EXTRA_OBJS="sha1.o" -elif test "$with_uuid" = e2fs ; then + elif test "$with_uuid" = e2fs ; then $as_echo "#define HAVE_UUID_E2FS 1" >>confdefs.h - UUID_EXTRA_OBJS="sha1.o" -elif test "$with_uuid" = ossp ; then + elif test "$with_uuid" = ossp ; then $as_echo "#define HAVE_UUID_OSSP 1" >>confdefs.h - UUID_EXTRA_OBJS="" -elif test "$with_uuid" = no ; then - UUID_EXTRA_OBJS="" -else - as_fn_error $? "--with-uuid must specify one of bsd, e2fs, or ossp" "$LINENO" 5 + else + as_fn_error $? "--with-uuid must specify one of bsd, e2fs, or ossp" "$LINENO" 5 + fi fi - # # XML # diff --git a/configure.ac b/configure.ac index 868a94c9ba972..a5ad072ee4abf 100644 --- a/configure.ac +++ b/configure.ac @@ -919,22 +919,18 @@ if test "$with_ossp_uuid" = yes ; then with_uuid=ossp fi -if test "$with_uuid" = bsd ; then - AC_DEFINE([HAVE_UUID_BSD], 1, [Define to 1 if you have BSD UUID support.]) - UUID_EXTRA_OBJS="sha1.o" -elif test "$with_uuid" = e2fs ; then - AC_DEFINE([HAVE_UUID_E2FS], 1, [Define to 1 if you have E2FS UUID support.]) - UUID_EXTRA_OBJS="sha1.o" -elif test "$with_uuid" = ossp ; then - AC_DEFINE([HAVE_UUID_OSSP], 1, [Define to 1 if you have OSSP UUID support.]) - UUID_EXTRA_OBJS="" -elif test "$with_uuid" = no ; then - UUID_EXTRA_OBJS="" -else - AC_MSG_ERROR([--with-uuid must specify one of bsd, e2fs, or ossp]) +if test "$with_uuid" != no ; then + if test "$with_uuid" = bsd ; then + AC_DEFINE([HAVE_UUID_BSD], 1, [Define to 1 if you have BSD UUID support.]) + elif test "$with_uuid" = e2fs ; then + AC_DEFINE([HAVE_UUID_E2FS], 1, [Define to 1 if you have E2FS UUID support.]) + elif test "$with_uuid" = ossp ; then + AC_DEFINE([HAVE_UUID_OSSP], 1, [Define to 1 if you have OSSP UUID support.]) + else + AC_MSG_ERROR([--with-uuid must specify one of bsd, e2fs, or ossp]) + fi fi AC_SUBST(with_uuid) -AC_SUBST(UUID_EXTRA_OBJS) # diff --git a/contrib/pgcrypto/Makefile b/contrib/pgcrypto/Makefile index d881e85add8c7..316a26e58deee 100644 --- a/contrib/pgcrypto/Makefile +++ b/contrib/pgcrypto/Makefile @@ -1,6 +1,6 @@ # contrib/pgcrypto/Makefile -INT_SRCS = sha1.c internal.c internal-sha2.c blf.c rijndael.c \ +INT_SRCS = internal.c internal-sha2.c blf.c rijndael.c \ pgp-mpi-internal.c imath.c INT_TESTS = sha2 diff --git a/contrib/pgcrypto/internal.c b/contrib/pgcrypto/internal.c index 79ce5135992d4..ef6ce2fb1ef94 100644 --- a/contrib/pgcrypto/internal.c +++ b/contrib/pgcrypto/internal.c @@ -36,18 +36,10 @@ #include "blf.h" #include "px.h" #include "rijndael.h" -#include "sha1.h" #include "common/cryptohash.h" #include "common/md5.h" - -#ifndef SHA1_DIGEST_LENGTH -#ifdef SHA1_RESULTLEN -#define SHA1_DIGEST_LENGTH SHA1_RESULTLEN -#else -#define SHA1_DIGEST_LENGTH 20 -#endif -#endif +#include "common/sha1.h" #define SHA1_BLOCK_SIZE 64 #define MD5_BLOCK_SIZE 64 @@ -144,34 +136,36 @@ int_sha1_block_len(PX_MD *h) static void int_sha1_update(PX_MD *h, const uint8 *data, unsigned dlen) { - SHA1_CTX *ctx = (SHA1_CTX *) h->p.ptr; + pg_cryptohash_ctx *ctx = (pg_cryptohash_ctx *) h->p.ptr; - SHA1Update(ctx, data, dlen); + if (pg_cryptohash_update(ctx, data, dlen) < 0) + elog(ERROR, "could not update %s context", "SHA1"); } static void int_sha1_reset(PX_MD *h) { - SHA1_CTX *ctx = (SHA1_CTX *) h->p.ptr; + pg_cryptohash_ctx *ctx = (pg_cryptohash_ctx *) h->p.ptr; - SHA1Init(ctx); + if (pg_cryptohash_init(ctx) < 0) + elog(ERROR, "could not initialize %s context", "SHA1"); } static void int_sha1_finish(PX_MD *h, uint8 *dst) { - SHA1_CTX *ctx = (SHA1_CTX *) h->p.ptr; + pg_cryptohash_ctx *ctx = (pg_cryptohash_ctx *) h->p.ptr; - SHA1Final(dst, ctx); + if (pg_cryptohash_final(ctx, dst) < 0) + elog(ERROR, "could not finalize %s context", "SHA1"); } static void int_sha1_free(PX_MD *h) { - SHA1_CTX *ctx = (SHA1_CTX *) h->p.ptr; + pg_cryptohash_ctx *ctx = (pg_cryptohash_ctx *) h->p.ptr; - px_memset(ctx, 0, sizeof(*ctx)); - pfree(ctx); + pg_cryptohash_free(ctx); pfree(h); } @@ -199,9 +193,9 @@ init_md5(PX_MD *md) static void init_sha1(PX_MD *md) { - SHA1_CTX *ctx; + pg_cryptohash_ctx *ctx; - ctx = palloc0(sizeof(*ctx)); + ctx = pg_cryptohash_create(PG_SHA1); md->p.ptr = ctx; diff --git a/contrib/pgcrypto/sha1.c b/contrib/pgcrypto/sha1.c deleted file mode 100644 index 64671ac64d9a5..0000000000000 --- a/contrib/pgcrypto/sha1.c +++ /dev/null @@ -1,331 +0,0 @@ -/* $KAME: sha1.c,v 1.3 2000/02/22 14:01:18 itojun Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * contrib/pgcrypto/sha1.c - */ -/* - * FIPS pub 180-1: Secure Hash Algorithm (SHA-1) - * based on: http://www.itl.nist.gov/fipspubs/fip180-1.htm - * implemented by Jun-ichiro itojun Itoh - */ - -#include "postgres.h" - -#include - -#include "sha1.h" - -/* constant table */ -static uint32 _K[] = {0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6}; - -#define K(t) _K[(t) / 20] - -#define F0(b, c, d) (((b) & (c)) | ((~(b)) & (d))) -#define F1(b, c, d) (((b) ^ (c)) ^ (d)) -#define F2(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d))) -#define F3(b, c, d) (((b) ^ (c)) ^ (d)) - -#define S(n, x) (((x) << (n)) | ((x) >> (32 - (n)))) - -#define H(n) (ctxt->h.b32[(n)]) -#define COUNT (ctxt->count) -#define BCOUNT (ctxt->c.b64[0] / 8) -#define W(n) (ctxt->m.b32[(n)]) - -#define PUTPAD(x) \ -do { \ - ctxt->m.b8[(COUNT % 64)] = (x); \ - COUNT++; \ - COUNT %= 64; \ - if (COUNT % 64 == 0) \ - sha1_step(ctxt); \ -} while (0) - -static void sha1_step(struct sha1_ctxt *); - -static void -sha1_step(struct sha1_ctxt *ctxt) -{ - uint32 a, - b, - c, - d, - e; - size_t t, - s; - uint32 tmp; - -#ifndef WORDS_BIGENDIAN - struct sha1_ctxt tctxt; - - memmove(&tctxt.m.b8[0], &ctxt->m.b8[0], 64); - ctxt->m.b8[0] = tctxt.m.b8[3]; - ctxt->m.b8[1] = tctxt.m.b8[2]; - ctxt->m.b8[2] = tctxt.m.b8[1]; - ctxt->m.b8[3] = tctxt.m.b8[0]; - ctxt->m.b8[4] = tctxt.m.b8[7]; - ctxt->m.b8[5] = tctxt.m.b8[6]; - ctxt->m.b8[6] = tctxt.m.b8[5]; - ctxt->m.b8[7] = tctxt.m.b8[4]; - ctxt->m.b8[8] = tctxt.m.b8[11]; - ctxt->m.b8[9] = tctxt.m.b8[10]; - ctxt->m.b8[10] = tctxt.m.b8[9]; - ctxt->m.b8[11] = tctxt.m.b8[8]; - ctxt->m.b8[12] = tctxt.m.b8[15]; - ctxt->m.b8[13] = tctxt.m.b8[14]; - ctxt->m.b8[14] = tctxt.m.b8[13]; - ctxt->m.b8[15] = tctxt.m.b8[12]; - ctxt->m.b8[16] = tctxt.m.b8[19]; - ctxt->m.b8[17] = tctxt.m.b8[18]; - ctxt->m.b8[18] = tctxt.m.b8[17]; - ctxt->m.b8[19] = tctxt.m.b8[16]; - ctxt->m.b8[20] = tctxt.m.b8[23]; - ctxt->m.b8[21] = tctxt.m.b8[22]; - ctxt->m.b8[22] = tctxt.m.b8[21]; - ctxt->m.b8[23] = tctxt.m.b8[20]; - ctxt->m.b8[24] = tctxt.m.b8[27]; - ctxt->m.b8[25] = tctxt.m.b8[26]; - ctxt->m.b8[26] = tctxt.m.b8[25]; - ctxt->m.b8[27] = tctxt.m.b8[24]; - ctxt->m.b8[28] = tctxt.m.b8[31]; - ctxt->m.b8[29] = tctxt.m.b8[30]; - ctxt->m.b8[30] = tctxt.m.b8[29]; - ctxt->m.b8[31] = tctxt.m.b8[28]; - ctxt->m.b8[32] = tctxt.m.b8[35]; - ctxt->m.b8[33] = tctxt.m.b8[34]; - ctxt->m.b8[34] = tctxt.m.b8[33]; - ctxt->m.b8[35] = tctxt.m.b8[32]; - ctxt->m.b8[36] = tctxt.m.b8[39]; - ctxt->m.b8[37] = tctxt.m.b8[38]; - ctxt->m.b8[38] = tctxt.m.b8[37]; - ctxt->m.b8[39] = tctxt.m.b8[36]; - ctxt->m.b8[40] = tctxt.m.b8[43]; - ctxt->m.b8[41] = tctxt.m.b8[42]; - ctxt->m.b8[42] = tctxt.m.b8[41]; - ctxt->m.b8[43] = tctxt.m.b8[40]; - ctxt->m.b8[44] = tctxt.m.b8[47]; - ctxt->m.b8[45] = tctxt.m.b8[46]; - ctxt->m.b8[46] = tctxt.m.b8[45]; - ctxt->m.b8[47] = tctxt.m.b8[44]; - ctxt->m.b8[48] = tctxt.m.b8[51]; - ctxt->m.b8[49] = tctxt.m.b8[50]; - ctxt->m.b8[50] = tctxt.m.b8[49]; - ctxt->m.b8[51] = tctxt.m.b8[48]; - ctxt->m.b8[52] = tctxt.m.b8[55]; - ctxt->m.b8[53] = tctxt.m.b8[54]; - ctxt->m.b8[54] = tctxt.m.b8[53]; - ctxt->m.b8[55] = tctxt.m.b8[52]; - ctxt->m.b8[56] = tctxt.m.b8[59]; - ctxt->m.b8[57] = tctxt.m.b8[58]; - ctxt->m.b8[58] = tctxt.m.b8[57]; - ctxt->m.b8[59] = tctxt.m.b8[56]; - ctxt->m.b8[60] = tctxt.m.b8[63]; - ctxt->m.b8[61] = tctxt.m.b8[62]; - ctxt->m.b8[62] = tctxt.m.b8[61]; - ctxt->m.b8[63] = tctxt.m.b8[60]; -#endif - - a = H(0); - b = H(1); - c = H(2); - d = H(3); - e = H(4); - - for (t = 0; t < 20; t++) - { - s = t & 0x0f; - if (t >= 16) - W(s) = S(1, W((s + 13) & 0x0f) ^ W((s + 8) & 0x0f) ^ W((s + 2) & 0x0f) ^ W(s)); - tmp = S(5, a) + F0(b, c, d) + e + W(s) + K(t); - e = d; - d = c; - c = S(30, b); - b = a; - a = tmp; - } - for (t = 20; t < 40; t++) - { - s = t & 0x0f; - W(s) = S(1, W((s + 13) & 0x0f) ^ W((s + 8) & 0x0f) ^ W((s + 2) & 0x0f) ^ W(s)); - tmp = S(5, a) + F1(b, c, d) + e + W(s) + K(t); - e = d; - d = c; - c = S(30, b); - b = a; - a = tmp; - } - for (t = 40; t < 60; t++) - { - s = t & 0x0f; - W(s) = S(1, W((s + 13) & 0x0f) ^ W((s + 8) & 0x0f) ^ W((s + 2) & 0x0f) ^ W(s)); - tmp = S(5, a) + F2(b, c, d) + e + W(s) + K(t); - e = d; - d = c; - c = S(30, b); - b = a; - a = tmp; - } - for (t = 60; t < 80; t++) - { - s = t & 0x0f; - W(s) = S(1, W((s + 13) & 0x0f) ^ W((s + 8) & 0x0f) ^ W((s + 2) & 0x0f) ^ W(s)); - tmp = S(5, a) + F3(b, c, d) + e + W(s) + K(t); - e = d; - d = c; - c = S(30, b); - b = a; - a = tmp; - } - - H(0) = H(0) + a; - H(1) = H(1) + b; - H(2) = H(2) + c; - H(3) = H(3) + d; - H(4) = H(4) + e; - - memset(&ctxt->m.b8[0], 0, 64); -} - -/*------------------------------------------------------------*/ - -void -sha1_init(struct sha1_ctxt *ctxt) -{ - memset(ctxt, 0, sizeof(struct sha1_ctxt)); - H(0) = 0x67452301; - H(1) = 0xefcdab89; - H(2) = 0x98badcfe; - H(3) = 0x10325476; - H(4) = 0xc3d2e1f0; -} - -void -sha1_pad(struct sha1_ctxt *ctxt) -{ - size_t padlen; /* pad length in bytes */ - size_t padstart; - - PUTPAD(0x80); - - padstart = COUNT % 64; - padlen = 64 - padstart; - if (padlen < 8) - { - memset(&ctxt->m.b8[padstart], 0, padlen); - COUNT += padlen; - COUNT %= 64; - sha1_step(ctxt); - padstart = COUNT % 64; /* should be 0 */ - padlen = 64 - padstart; /* should be 64 */ - } - memset(&ctxt->m.b8[padstart], 0, padlen - 8); - COUNT += (padlen - 8); - COUNT %= 64; -#ifdef WORDS_BIGENDIAN - PUTPAD(ctxt->c.b8[0]); - PUTPAD(ctxt->c.b8[1]); - PUTPAD(ctxt->c.b8[2]); - PUTPAD(ctxt->c.b8[3]); - PUTPAD(ctxt->c.b8[4]); - PUTPAD(ctxt->c.b8[5]); - PUTPAD(ctxt->c.b8[6]); - PUTPAD(ctxt->c.b8[7]); -#else - PUTPAD(ctxt->c.b8[7]); - PUTPAD(ctxt->c.b8[6]); - PUTPAD(ctxt->c.b8[5]); - PUTPAD(ctxt->c.b8[4]); - PUTPAD(ctxt->c.b8[3]); - PUTPAD(ctxt->c.b8[2]); - PUTPAD(ctxt->c.b8[1]); - PUTPAD(ctxt->c.b8[0]); -#endif -} - -void -sha1_loop(struct sha1_ctxt *ctxt, const uint8 *input0, size_t len) -{ - const uint8 *input; - size_t gaplen; - size_t gapstart; - size_t off; - size_t copysiz; - - input = (const uint8 *) input0; - off = 0; - - while (off < len) - { - gapstart = COUNT % 64; - gaplen = 64 - gapstart; - - copysiz = (gaplen < len - off) ? gaplen : len - off; - memmove(&ctxt->m.b8[gapstart], &input[off], copysiz); - COUNT += copysiz; - COUNT %= 64; - ctxt->c.b64[0] += copysiz * 8; - if (COUNT % 64 == 0) - sha1_step(ctxt); - off += copysiz; - } -} - -void -sha1_result(struct sha1_ctxt *ctxt, uint8 *digest0) -{ - uint8 *digest; - - digest = (uint8 *) digest0; - sha1_pad(ctxt); -#ifdef WORDS_BIGENDIAN - memmove(digest, &ctxt->h.b8[0], 20); -#else - digest[0] = ctxt->h.b8[3]; - digest[1] = ctxt->h.b8[2]; - digest[2] = ctxt->h.b8[1]; - digest[3] = ctxt->h.b8[0]; - digest[4] = ctxt->h.b8[7]; - digest[5] = ctxt->h.b8[6]; - digest[6] = ctxt->h.b8[5]; - digest[7] = ctxt->h.b8[4]; - digest[8] = ctxt->h.b8[11]; - digest[9] = ctxt->h.b8[10]; - digest[10] = ctxt->h.b8[9]; - digest[11] = ctxt->h.b8[8]; - digest[12] = ctxt->h.b8[15]; - digest[13] = ctxt->h.b8[14]; - digest[14] = ctxt->h.b8[13]; - digest[15] = ctxt->h.b8[12]; - digest[16] = ctxt->h.b8[19]; - digest[17] = ctxt->h.b8[18]; - digest[18] = ctxt->h.b8[17]; - digest[19] = ctxt->h.b8[16]; -#endif -} diff --git a/contrib/uuid-ossp/.gitignore b/contrib/uuid-ossp/.gitignore index d7260edc610ab..5dcb3ff972350 100644 --- a/contrib/uuid-ossp/.gitignore +++ b/contrib/uuid-ossp/.gitignore @@ -1,4 +1,3 @@ -/sha1.c # Generated subdirectories /log/ /results/ diff --git a/contrib/uuid-ossp/Makefile b/contrib/uuid-ossp/Makefile index 0859a5397c97d..c42edf5f1a0c1 100644 --- a/contrib/uuid-ossp/Makefile +++ b/contrib/uuid-ossp/Makefile @@ -2,7 +2,6 @@ MODULE_big = uuid-ossp OBJS = \ - $(UUID_EXTRA_OBJS) \ $(WIN32RES) \ uuid-ossp.o @@ -19,8 +18,6 @@ pgcrypto_src = $(top_srcdir)/contrib/pgcrypto PG_CPPFLAGS = -I$(pgcrypto_src) -EXTRA_CLEAN = sha1.c - ifdef USE_PGXS PG_CONFIG = pg_config PGXS := $(shell $(PG_CONFIG) --pgxs) @@ -31,6 +28,3 @@ top_builddir = ../.. include $(top_builddir)/src/Makefile.global include $(top_srcdir)/contrib/contrib-global.mk endif - -sha1.c: % : $(pgcrypto_src)/% - rm -f $@ && $(LN_S) $< . diff --git a/contrib/uuid-ossp/uuid-ossp.c b/contrib/uuid-ossp/uuid-ossp.c index 049efc979ff6b..49a4a5926455c 100644 --- a/contrib/uuid-ossp/uuid-ossp.c +++ b/contrib/uuid-ossp/uuid-ossp.c @@ -15,6 +15,7 @@ #include "fmgr.h" #include "common/cryptohash.h" +#include "common/sha1.h" #include "port/pg_bswap.h" #include "utils/builtins.h" #include "utils/uuid.h" @@ -40,15 +41,6 @@ #undef uuid_hash -/* - * Some BSD variants offer sha1 implementation but Linux does not, so we use - * a copy from pgcrypto. Not needed with OSSP, though. - */ -#ifndef HAVE_UUID_OSSP -#include "sha1.h" -#endif - - /* Check our UUID length against OSSP's; better both be 16 */ #if defined(HAVE_UUID_OSSP) && (UUID_LEN != UUID_LEN_BIN) #error UUID length mismatch @@ -338,13 +330,18 @@ uuid_generate_internal(int v, unsigned char *ns, const char *ptr, int len) } else { - SHA1_CTX ctx; - unsigned char sha1result[SHA1_RESULTLEN]; + pg_cryptohash_ctx *ctx = pg_cryptohash_create(PG_SHA1); + unsigned char sha1result[SHA1_DIGEST_LENGTH]; + + if (pg_cryptohash_init(ctx) < 0) + elog(ERROR, "could not initialize %s context", "SHA1"); + if (pg_cryptohash_update(ctx, ns, sizeof(uu)) < 0 || + pg_cryptohash_update(ctx, (unsigned char *) ptr, len) < 0) + elog(ERROR, "could not update %s context", "SHA1"); + if (pg_cryptohash_final(ctx, sha1result) < 0) + elog(ERROR, "could not finalize %s context", "SHA1"); + pg_cryptohash_free(ctx); - SHA1Init(&ctx); - SHA1Update(&ctx, ns, sizeof(uu)); - SHA1Update(&ctx, (unsigned char *) ptr, len); - SHA1Final(sha1result, &ctx); memcpy(&uu, sha1result, sizeof(uu)); } diff --git a/src/Makefile.global.in b/src/Makefile.global.in index 7ca1e9aac5945..9a1688c97cb80 100644 --- a/src/Makefile.global.in +++ b/src/Makefile.global.in @@ -289,7 +289,6 @@ LIBS = @LIBS@ LDAP_LIBS_FE = @LDAP_LIBS_FE@ LDAP_LIBS_BE = @LDAP_LIBS_BE@ UUID_LIBS = @UUID_LIBS@ -UUID_EXTRA_OBJS = @UUID_EXTRA_OBJS@ LLVM_LIBS=@LLVM_LIBS@ LD = @LD@ with_gnu_ld = @with_gnu_ld@ diff --git a/src/common/Makefile b/src/common/Makefile index 93eb27a2aa4e0..1a1d0d3406c33 100644 --- a/src/common/Makefile +++ b/src/common/Makefile @@ -88,6 +88,7 @@ else OBJS_COMMON += \ cryptohash.o \ md5.o \ + sha1.o \ sha2.o endif diff --git a/src/common/cryptohash.c b/src/common/cryptohash.c index efedadd6263d2..5b2c050d799c3 100644 --- a/src/common/cryptohash.c +++ b/src/common/cryptohash.c @@ -25,6 +25,7 @@ #include "common/cryptohash.h" #include "md5_int.h" +#include "sha1_int.h" #include "sha2_int.h" /* @@ -47,6 +48,7 @@ struct pg_cryptohash_ctx union { pg_md5_ctx md5; + pg_sha1_ctx sha1; pg_sha224_ctx sha224; pg_sha256_ctx sha256; pg_sha384_ctx sha384; @@ -97,6 +99,9 @@ pg_cryptohash_init(pg_cryptohash_ctx *ctx) case PG_MD5: pg_md5_init(&ctx->data.md5); break; + case PG_SHA1: + pg_sha1_init(&ctx->data.sha1); + break; case PG_SHA224: pg_sha224_init(&ctx->data.sha224); break; @@ -132,6 +137,9 @@ pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len) case PG_MD5: pg_md5_update(&ctx->data.md5, data, len); break; + case PG_SHA1: + pg_sha1_update(&ctx->data.sha1, data, len); + break; case PG_SHA224: pg_sha224_update(&ctx->data.sha224, data, len); break; @@ -167,6 +175,9 @@ pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest) case PG_MD5: pg_md5_final(&ctx->data.md5, dest); break; + case PG_SHA1: + pg_sha1_final(&ctx->data.sha1, dest); + break; case PG_SHA224: pg_sha224_final(&ctx->data.sha224, dest); break; diff --git a/src/common/cryptohash_openssl.c b/src/common/cryptohash_openssl.c index 551ec392b60f3..006e867403e9c 100644 --- a/src/common/cryptohash_openssl.c +++ b/src/common/cryptohash_openssl.c @@ -131,6 +131,9 @@ pg_cryptohash_init(pg_cryptohash_ctx *ctx) case PG_MD5: status = EVP_DigestInit_ex(ctx->evpctx, EVP_md5(), NULL); break; + case PG_SHA1: + status = EVP_DigestInit_ex(ctx->evpctx, EVP_sha1(), NULL); + break; case PG_SHA224: status = EVP_DigestInit_ex(ctx->evpctx, EVP_sha224(), NULL); break; diff --git a/src/common/sha1.c b/src/common/sha1.c new file mode 100644 index 0000000000000..f8ed4d6808699 --- /dev/null +++ b/src/common/sha1.c @@ -0,0 +1,369 @@ +/*------------------------------------------------------------------------- + * + * sha1.c + * Implements the SHA1 Secure Hash Algorithm + * + * Fallback implementation of SHA1, as specified in RFC 3174. + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/common/sha1.c + * + *------------------------------------------------------------------------- + */ + +/* $KAME: sha1.c,v 1.3 2000/02/22 14:01:18 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * FIPS pub 180-1: Secure Hash Algorithm (SHA-1) + * based on: http://www.itl.nist.gov/fipspubs/fip180-1.htm + * implemented by Jun-ichiro itojun Itoh + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include + +#include "sha1_int.h" + +/* constant table */ +static uint32 _K[] = {0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6}; + +#define K(t) _K[(t) / 20] + +#define F0(b, c, d) (((b) & (c)) | ((~(b)) & (d))) +#define F1(b, c, d) (((b) ^ (c)) ^ (d)) +#define F2(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d))) +#define F3(b, c, d) (((b) ^ (c)) ^ (d)) + +#define S(n, x) (((x) << (n)) | ((x) >> (32 - (n)))) + +#define H(n) (ctx->h.b32[(n)]) +#define COUNT (ctx->count) +#define BCOUNT (ctx->c.b64[0] / 8) +#define W(n) (ctx->m.b32[(n)]) + +#define PUTPAD(x) \ +do { \ + ctx->m.b8[(COUNT % 64)] = (x); \ + COUNT++; \ + COUNT %= 64; \ + if (COUNT % 64 == 0) \ + sha1_step(ctx); \ +} while (0) + +static void +sha1_step(pg_sha1_ctx *ctx) +{ + uint32 a, + b, + c, + d, + e; + size_t t, + s; + uint32 tmp; + +#ifndef WORDS_BIGENDIAN + pg_sha1_ctx tctx; + + memmove(&tctx.m.b8[0], &ctx->m.b8[0], 64); + ctx->m.b8[0] = tctx.m.b8[3]; + ctx->m.b8[1] = tctx.m.b8[2]; + ctx->m.b8[2] = tctx.m.b8[1]; + ctx->m.b8[3] = tctx.m.b8[0]; + ctx->m.b8[4] = tctx.m.b8[7]; + ctx->m.b8[5] = tctx.m.b8[6]; + ctx->m.b8[6] = tctx.m.b8[5]; + ctx->m.b8[7] = tctx.m.b8[4]; + ctx->m.b8[8] = tctx.m.b8[11]; + ctx->m.b8[9] = tctx.m.b8[10]; + ctx->m.b8[10] = tctx.m.b8[9]; + ctx->m.b8[11] = tctx.m.b8[8]; + ctx->m.b8[12] = tctx.m.b8[15]; + ctx->m.b8[13] = tctx.m.b8[14]; + ctx->m.b8[14] = tctx.m.b8[13]; + ctx->m.b8[15] = tctx.m.b8[12]; + ctx->m.b8[16] = tctx.m.b8[19]; + ctx->m.b8[17] = tctx.m.b8[18]; + ctx->m.b8[18] = tctx.m.b8[17]; + ctx->m.b8[19] = tctx.m.b8[16]; + ctx->m.b8[20] = tctx.m.b8[23]; + ctx->m.b8[21] = tctx.m.b8[22]; + ctx->m.b8[22] = tctx.m.b8[21]; + ctx->m.b8[23] = tctx.m.b8[20]; + ctx->m.b8[24] = tctx.m.b8[27]; + ctx->m.b8[25] = tctx.m.b8[26]; + ctx->m.b8[26] = tctx.m.b8[25]; + ctx->m.b8[27] = tctx.m.b8[24]; + ctx->m.b8[28] = tctx.m.b8[31]; + ctx->m.b8[29] = tctx.m.b8[30]; + ctx->m.b8[30] = tctx.m.b8[29]; + ctx->m.b8[31] = tctx.m.b8[28]; + ctx->m.b8[32] = tctx.m.b8[35]; + ctx->m.b8[33] = tctx.m.b8[34]; + ctx->m.b8[34] = tctx.m.b8[33]; + ctx->m.b8[35] = tctx.m.b8[32]; + ctx->m.b8[36] = tctx.m.b8[39]; + ctx->m.b8[37] = tctx.m.b8[38]; + ctx->m.b8[38] = tctx.m.b8[37]; + ctx->m.b8[39] = tctx.m.b8[36]; + ctx->m.b8[40] = tctx.m.b8[43]; + ctx->m.b8[41] = tctx.m.b8[42]; + ctx->m.b8[42] = tctx.m.b8[41]; + ctx->m.b8[43] = tctx.m.b8[40]; + ctx->m.b8[44] = tctx.m.b8[47]; + ctx->m.b8[45] = tctx.m.b8[46]; + ctx->m.b8[46] = tctx.m.b8[45]; + ctx->m.b8[47] = tctx.m.b8[44]; + ctx->m.b8[48] = tctx.m.b8[51]; + ctx->m.b8[49] = tctx.m.b8[50]; + ctx->m.b8[50] = tctx.m.b8[49]; + ctx->m.b8[51] = tctx.m.b8[48]; + ctx->m.b8[52] = tctx.m.b8[55]; + ctx->m.b8[53] = tctx.m.b8[54]; + ctx->m.b8[54] = tctx.m.b8[53]; + ctx->m.b8[55] = tctx.m.b8[52]; + ctx->m.b8[56] = tctx.m.b8[59]; + ctx->m.b8[57] = tctx.m.b8[58]; + ctx->m.b8[58] = tctx.m.b8[57]; + ctx->m.b8[59] = tctx.m.b8[56]; + ctx->m.b8[60] = tctx.m.b8[63]; + ctx->m.b8[61] = tctx.m.b8[62]; + ctx->m.b8[62] = tctx.m.b8[61]; + ctx->m.b8[63] = tctx.m.b8[60]; +#endif + + a = H(0); + b = H(1); + c = H(2); + d = H(3); + e = H(4); + + for (t = 0; t < 20; t++) + { + s = t & 0x0f; + if (t >= 16) + W(s) = S(1, W((s + 13) & 0x0f) ^ W((s + 8) & 0x0f) ^ W((s + 2) & 0x0f) ^ W(s)); + tmp = S(5, a) + F0(b, c, d) + e + W(s) + K(t); + e = d; + d = c; + c = S(30, b); + b = a; + a = tmp; + } + for (t = 20; t < 40; t++) + { + s = t & 0x0f; + W(s) = S(1, W((s + 13) & 0x0f) ^ W((s + 8) & 0x0f) ^ W((s + 2) & 0x0f) ^ W(s)); + tmp = S(5, a) + F1(b, c, d) + e + W(s) + K(t); + e = d; + d = c; + c = S(30, b); + b = a; + a = tmp; + } + for (t = 40; t < 60; t++) + { + s = t & 0x0f; + W(s) = S(1, W((s + 13) & 0x0f) ^ W((s + 8) & 0x0f) ^ W((s + 2) & 0x0f) ^ W(s)); + tmp = S(5, a) + F2(b, c, d) + e + W(s) + K(t); + e = d; + d = c; + c = S(30, b); + b = a; + a = tmp; + } + for (t = 60; t < 80; t++) + { + s = t & 0x0f; + W(s) = S(1, W((s + 13) & 0x0f) ^ W((s + 8) & 0x0f) ^ W((s + 2) & 0x0f) ^ W(s)); + tmp = S(5, a) + F3(b, c, d) + e + W(s) + K(t); + e = d; + d = c; + c = S(30, b); + b = a; + a = tmp; + } + + H(0) = H(0) + a; + H(1) = H(1) + b; + H(2) = H(2) + c; + H(3) = H(3) + d; + H(4) = H(4) + e; + + memset(&ctx->m.b8[0], 0, 64); +} + +static void +sha1_pad(pg_sha1_ctx *ctx) +{ + size_t padlen; /* pad length in bytes */ + size_t padstart; + + PUTPAD(0x80); + + padstart = COUNT % 64; + padlen = 64 - padstart; + if (padlen < 8) + { + memset(&ctx->m.b8[padstart], 0, padlen); + COUNT += padlen; + COUNT %= 64; + sha1_step(ctx); + padstart = COUNT % 64; /* should be 0 */ + padlen = 64 - padstart; /* should be 64 */ + } + memset(&ctx->m.b8[padstart], 0, padlen - 8); + COUNT += (padlen - 8); + COUNT %= 64; +#ifdef WORDS_BIGENDIAN + PUTPAD(ctx->c.b8[0]); + PUTPAD(ctx->c.b8[1]); + PUTPAD(ctx->c.b8[2]); + PUTPAD(ctx->c.b8[3]); + PUTPAD(ctx->c.b8[4]); + PUTPAD(ctx->c.b8[5]); + PUTPAD(ctx->c.b8[6]); + PUTPAD(ctx->c.b8[7]); +#else + PUTPAD(ctx->c.b8[7]); + PUTPAD(ctx->c.b8[6]); + PUTPAD(ctx->c.b8[5]); + PUTPAD(ctx->c.b8[4]); + PUTPAD(ctx->c.b8[3]); + PUTPAD(ctx->c.b8[2]); + PUTPAD(ctx->c.b8[1]); + PUTPAD(ctx->c.b8[0]); +#endif +} + +static void +sha1_result(uint8 *digest0, pg_sha1_ctx *ctx) +{ + uint8 *digest; + + digest = (uint8 *) digest0; + +#ifdef WORDS_BIGENDIAN + memmove(digest, &ctx->h.b8[0], 20); +#else + digest[0] = ctx->h.b8[3]; + digest[1] = ctx->h.b8[2]; + digest[2] = ctx->h.b8[1]; + digest[3] = ctx->h.b8[0]; + digest[4] = ctx->h.b8[7]; + digest[5] = ctx->h.b8[6]; + digest[6] = ctx->h.b8[5]; + digest[7] = ctx->h.b8[4]; + digest[8] = ctx->h.b8[11]; + digest[9] = ctx->h.b8[10]; + digest[10] = ctx->h.b8[9]; + digest[11] = ctx->h.b8[8]; + digest[12] = ctx->h.b8[15]; + digest[13] = ctx->h.b8[14]; + digest[14] = ctx->h.b8[13]; + digest[15] = ctx->h.b8[12]; + digest[16] = ctx->h.b8[19]; + digest[17] = ctx->h.b8[18]; + digest[18] = ctx->h.b8[17]; + digest[19] = ctx->h.b8[16]; +#endif +} + +/* External routines for this SHA1 implementation */ + +/* + * pg_sha1_init + * + * Initialize a SHA1 context. + */ +void +pg_sha1_init(pg_sha1_ctx *ctx) +{ + memset(ctx, 0, sizeof(pg_sha1_ctx)); + H(0) = 0x67452301; + H(1) = 0xefcdab89; + H(2) = 0x98badcfe; + H(3) = 0x10325476; + H(4) = 0xc3d2e1f0; +} + +/* + * pg_sha1_update + * + * Update a SHA1 context. + */ +void +pg_sha1_update(pg_sha1_ctx *ctx, const uint8 *data, size_t len) +{ + const uint8 *input; + size_t gaplen; + size_t gapstart; + size_t off; + size_t copysiz; + + input = (const uint8 *) data; + off = 0; + + while (off < len) + { + gapstart = COUNT % 64; + gaplen = 64 - gapstart; + + copysiz = (gaplen < len - off) ? gaplen : len - off; + memmove(&ctx->m.b8[gapstart], &input[off], copysiz); + COUNT += copysiz; + COUNT %= 64; + ctx->c.b64[0] += copysiz * 8; + if (COUNT % 64 == 0) + sha1_step(ctx); + off += copysiz; + } +} + +/* + * pg_sha1_final + * + * Finalize a SHA1 context. + */ +void +pg_sha1_final(pg_sha1_ctx *ctx, uint8 *dest) +{ + sha1_pad(ctx); + sha1_result(dest, ctx); +} diff --git a/contrib/pgcrypto/sha1.h b/src/common/sha1_int.h similarity index 71% rename from contrib/pgcrypto/sha1.h rename to src/common/sha1_int.h index 4300694a34806..7f458a6127403 100644 --- a/contrib/pgcrypto/sha1.h +++ b/src/common/sha1_int.h @@ -1,4 +1,17 @@ -/* contrib/pgcrypto/sha1.h */ +/*------------------------------------------------------------------------- + * + * sha1_int.h + * Internal headers for fallback implementation of SHA1 + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/common/sha1_int.h + * + *------------------------------------------------------------------------- + */ + /* $KAME: sha1.h,v 1.4 2000/02/22 14:01:18 itojun Exp $ */ /* @@ -35,10 +48,12 @@ * implemented by Jun-ichiro itojun Itoh */ -#ifndef _NETINET6_SHA1_H_ -#define _NETINET6_SHA1_H_ +#ifndef PG_SHA1_INT_H +#define PG_SHA1_INT_H + +#include "common/sha1.h" -struct sha1_ctxt +typedef struct { union { @@ -56,20 +71,11 @@ struct sha1_ctxt uint32 b32[16]; } m; uint8 count; -}; - -extern void sha1_init(struct sha1_ctxt *); -extern void sha1_pad(struct sha1_ctxt *); -extern void sha1_loop(struct sha1_ctxt *, const uint8 *, size_t); -extern void sha1_result(struct sha1_ctxt *, uint8 *); - -/* compatibility with other SHA1 source codes */ -typedef struct sha1_ctxt SHA1_CTX; - -#define SHA1Init(x) sha1_init((x)) -#define SHA1Update(x, y, z) sha1_loop((x), (y), (z)) -#define SHA1Final(x, y) sha1_result((y), (x)) +} pg_sha1_ctx; -#define SHA1_RESULTLEN (160/8) +/* Interface routines for SHA1 */ +extern void pg_sha1_init(pg_sha1_ctx *ctx); +extern void pg_sha1_update(pg_sha1_ctx *ctx, const uint8 *data, size_t len); +extern void pg_sha1_final(pg_sha1_ctx *ctx, uint8 *dest); -#endif /* _NETINET6_SHA1_H_ */ +#endif /* PG_SHA1_INT_H */ diff --git a/src/include/common/cryptohash.h b/src/include/common/cryptohash.h index 3ecaf62113514..32d7784ca5b63 100644 --- a/src/include/common/cryptohash.h +++ b/src/include/common/cryptohash.h @@ -19,6 +19,7 @@ typedef enum { PG_MD5 = 0, + PG_SHA1, PG_SHA224, PG_SHA256, PG_SHA384, diff --git a/src/include/common/sha1.h b/src/include/common/sha1.h new file mode 100644 index 0000000000000..a61bc47dedaa2 --- /dev/null +++ b/src/include/common/sha1.h @@ -0,0 +1,19 @@ +/*------------------------------------------------------------------------- + * + * sha1.h + * Constants related to SHA1. + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/sha1.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_SHA1_H +#define PG_SHA1_H + +/* Size of result generated by SHA1 computation */ +#define SHA1_DIGEST_LENGTH 20 + +#endif /* PG_SHA1_H */ diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm index 5634b2d40c02f..7213e65e08b1a 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -136,6 +136,7 @@ sub mkvcbuild { push(@pgcommonallfiles, 'cryptohash.c'); push(@pgcommonallfiles, 'md5.c'); + push(@pgcommonallfiles, 'sha1.c'); push(@pgcommonallfiles, 'sha2.c'); } @@ -465,10 +466,10 @@ sub mkvcbuild else { $pgcrypto->AddFiles( - 'contrib/pgcrypto', 'sha1.c', - 'internal.c', 'internal-sha2.c', - 'blf.c', 'rijndael.c', - 'pgp-mpi-internal.c', 'imath.c'); + 'contrib/pgcrypto', 'internal.c', + 'internal-sha2.c', 'blf.c', + 'rijndael.c', 'pgp-mpi-internal.c', + 'imath.c'); } $pgcrypto->AddReference($postgres); $pgcrypto->AddLibrary('ws2_32.lib'); diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 943142ced8c19..721b230bf2924 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -3214,6 +3214,7 @@ pg_md5_ctx pg_on_exit_callback pg_re_flags pg_saslprep_rc +pg_sha1_ctx pg_sha224_ctx pg_sha256_ctx pg_sha384_ctx From 68d1c339417ea2e8df42e11db57472fcdbfe6a55 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 23 Jan 2021 15:08:39 -0500 Subject: [PATCH 161/240] Update ecpg's connect-test1 for connection-failure message changes. I should have updated this in commits 52a10224e and follow-ons, but I missed it because it's not run by default, and none of the buildfarm runs it either. Maybe we should try to improve that situation. Discussion: https://postgr.es/m/CAH2-Wz=j9SRW=s5BV4-3k+=tr4N3A03in+gTuVA09vNF+-iHjA@mail.gmail.com --- .../test/expected/connect-test1-minGW32.stderr | 15 +++++---------- .../ecpg/test/expected/connect-test1.stderr | 15 +++++---------- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/src/interfaces/ecpg/test/expected/connect-test1-minGW32.stderr b/src/interfaces/ecpg/test/expected/connect-test1-minGW32.stderr index 853453d980ece..c5b5248eb2704 100644 --- a/src/interfaces/ecpg/test/expected/connect-test1-minGW32.stderr +++ b/src/interfaces/ecpg/test/expected/connect-test1-minGW32.stderr @@ -16,8 +16,7 @@ [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ECPGconnect: opening database on localhost port for user regress_ecpg_user2 [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ECPGconnect: could not open database: FATAL: database "regress_ecpg_user2" does not exist - +[NO_PID]: ECPGconnect: connection to server failed: FATAL: database "regress_ecpg_user2" does not exist [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ecpg_finish: connection main closed [NO_PID]: sqlca: code: 0, state: 00000 @@ -31,8 +30,7 @@ [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ECPGconnect: opening database on localhost port for user regress_ecpg_user2 [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ECPGconnect: could not open database: FATAL: database "regress_ecpg_user2" does not exist - +[NO_PID]: ECPGconnect: connection to server failed: FATAL: database "regress_ecpg_user2" does not exist [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ecpg_finish: connection (null) closed [NO_PID]: sqlca: code: 0, state: 00000 @@ -54,8 +52,7 @@ [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ECPGconnect: opening database nonexistent on localhost port for user regress_ecpg_user1 [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ECPGconnect: could not open database: FATAL: database "nonexistent" does not exist - +[NO_PID]: ECPGconnect: connection to server failed: FATAL: database "nonexistent" does not exist [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ecpg_finish: connection nonexistent closed [NO_PID]: sqlca: code: 0, state: 00000 @@ -65,10 +62,8 @@ [NO_PID]: sqlca: code: -220, state: 08003 [NO_PID]: ECPGconnect: opening database ecpg2_regression on localhost port for user regress_ecpg_user1 [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ECPGconnect: could not open database: could not connect to server: Connection refused (0x0000274D/10061) - Is the server running on host "localhost" and accepting - TCP/IP connections on port 20? - +[NO_PID]: ECPGconnect: connection to server failed: Connection refused (0x0000274D/10061) + Is the server running on that host and accepting TCP/IP connections? [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ecpg_finish: connection ecpg2_regression closed [NO_PID]: sqlca: code: 0, state: 00000 diff --git a/src/interfaces/ecpg/test/expected/connect-test1.stderr b/src/interfaces/ecpg/test/expected/connect-test1.stderr index 1986fc54adc27..073951c0edd7a 100644 --- a/src/interfaces/ecpg/test/expected/connect-test1.stderr +++ b/src/interfaces/ecpg/test/expected/connect-test1.stderr @@ -16,8 +16,7 @@ [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ECPGconnect: opening database on localhost port for user regress_ecpg_user2 [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ECPGconnect: could not open database: FATAL: database "regress_ecpg_user2" does not exist - +[NO_PID]: ECPGconnect: connection to server failed: FATAL: database "regress_ecpg_user2" does not exist [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ecpg_finish: connection main closed [NO_PID]: sqlca: code: 0, state: 00000 @@ -31,8 +30,7 @@ [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ECPGconnect: opening database on localhost port for user regress_ecpg_user2 [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ECPGconnect: could not open database: FATAL: database "regress_ecpg_user2" does not exist - +[NO_PID]: ECPGconnect: connection to server failed: FATAL: database "regress_ecpg_user2" does not exist [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ecpg_finish: connection (null) closed [NO_PID]: sqlca: code: 0, state: 00000 @@ -54,8 +52,7 @@ [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ECPGconnect: opening database nonexistent on localhost port for user regress_ecpg_user1 [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ECPGconnect: could not open database: FATAL: database "nonexistent" does not exist - +[NO_PID]: ECPGconnect: connection to server failed: FATAL: database "nonexistent" does not exist [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ecpg_finish: connection nonexistent closed [NO_PID]: sqlca: code: 0, state: 00000 @@ -65,10 +62,8 @@ [NO_PID]: sqlca: code: -220, state: 08003 [NO_PID]: ECPGconnect: opening database ecpg2_regression on 127.0.0.1 port for user regress_ecpg_user1 [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ECPGconnect: could not open database: could not connect to server: Connection refused - Is the server running on host "127.0.0.1" and accepting - TCP/IP connections on port 20? - +[NO_PID]: ECPGconnect: connection to server failed: Connection refused + Is the server running on that host and accepting TCP/IP connections? [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ecpg_finish: connection ecpg2_regression closed [NO_PID]: sqlca: code: 0, state: 00000 From 183bbd1b6d4376f1b04c02b7a20b55019f6d84f4 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 23 Jan 2021 15:50:51 -0500 Subject: [PATCH 162/240] Doc: update example connection-failure messages in the documentation. Now that the dust has more or less settled on 52a10224e and follow-ons, make sure the examples in the documentation are up-to-date. --- doc/src/sgml/runtime.sgml | 22 ++++++++++++---------- doc/src/sgml/start.sgml | 13 ++++++------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml index 283352d3a4abe..bf877c0e0c1a0 100644 --- a/doc/src/sgml/runtime.sgml +++ b/doc/src/sgml/runtime.sgml @@ -629,9 +629,8 @@ DETAIL: Failed system call was semget(5440126, 17, 03600). -psql: could not connect to server: Connection refused - Is the server running on host "server.joe.com" and accepting - TCP/IP connections on port 5432? +psql: error: connection to server at "server.joe.com" (123.123.123.123), port 5432 failed: Connection refused + Is the server running on that host and accepting TCP/IP connections? This is the generic I couldn't find a server to talk to failure. It looks like the above when TCP/IP @@ -640,19 +639,22 @@ psql: could not connect to server: Connection refused - Alternatively, you'll get this when attempting Unix-domain socket + Alternatively, you might get this when attempting Unix-domain socket communication to a local server: -psql: could not connect to server: No such file or directory - Is the server running locally and accepting - connections on Unix domain socket "/tmp/.s.PGSQL.5432"? +psql: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed: No such file or directory + Is the server running locally and accepting connections on that socket? + If the server is indeed running, check that the client's idea of the + socket path (here /tmp) agrees with the server's + setting. - The last line is useful in verifying that the client is trying to + A connection failure message always shows the server address or socket + path name, which is useful in verifying that the client is trying to connect to the right place. If there is in fact no server - running there, the kernel error message will typically be either + listening there, the kernel error message will typically be either Connection refused or No such file or directory, as illustrated. (It is important to realize that @@ -663,7 +665,7 @@ psql: could not connect to server: No such file or directory linkend="client-authentication-problems"/>.) Other error messages such as Connection timed out might indicate more fundamental problems, like lack of network - connectivity. + connectivity, or a firewall blocking the connection. diff --git a/doc/src/sgml/start.sgml b/doc/src/sgml/start.sgml index 9bb5c1a6d5d1f..f4ae1d0fcf781 100644 --- a/doc/src/sgml/start.sgml +++ b/doc/src/sgml/start.sgml @@ -176,19 +176,18 @@ createdb: command not found Another response could be this: -createdb: could not connect to database postgres: could not connect to server: No such file or directory - Is the server running locally and accepting - connections on Unix domain socket "/tmp/.s.PGSQL.5432"? +createdb: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed: No such file or directory + Is the server running locally and accepting connections on that socket? - This means that the server was not started, or it was not started - where createdb expected it. Again, check the + This means that the server was not started, or it is not listening + where createdb expects to contact it. Again, check the installation instructions or consult the administrator. Another response could be this: -createdb: could not connect to database postgres: FATAL: role "joe" does not exist +createdb: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed: FATAL: role "joe" does not exist where your own login name is mentioned. This will happen if the administrator has not created a PostgreSQL user account @@ -208,7 +207,7 @@ createdb: could not connect to database postgres: FATAL: role "joe" does not ex If you have a user account but it does not have the privileges required to create a database, you will see the following: -createdb: database creation failed: ERROR: permission denied to create database +createdb: error: database creation failed: ERROR: permission denied to create database Not every user has authorization to create new databases. If PostgreSQL refuses to create databases From 39b66a91bdebb00af71a2c6218412ecfc89a0e13 Mon Sep 17 00:00:00 2001 From: Tomas Vondra Date: Sun, 24 Jan 2021 00:24:50 +0100 Subject: [PATCH 163/240] Fix COPY FREEZE with CLOBBER_CACHE_ALWAYS This adds code omitted from commit 7db0cd2145 by accident, which had two consequences. Firstly, only rows inserted by heap_multi_insert were frozen as expected when running COPY FREEZE, while heap_insert left rows unfrozen. That however includes rows in TOAST tables, so a lot of data might have been left unfrozen. Secondly, page might have been left partially empty after relcache invalidation. This addresses both of those issues. Discussion: https://postgr.es/m/CABOikdN-ptGv0mZntrK2Q8OtfUuAjqaYMGmkdU1dCKFtUxVLrg@mail.gmail.com --- src/backend/access/heap/heapam.c | 78 +++++++++++++++++++++++++++++++- src/backend/access/heap/hio.c | 22 ++++----- 2 files changed, 88 insertions(+), 12 deletions(-) diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index faffbb18658d7..d107e14690c7e 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -1880,8 +1880,12 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid, TransactionId xid = GetCurrentTransactionId(); HeapTuple heaptup; Buffer buffer; + Page page = NULL; Buffer vmbuffer = InvalidBuffer; + bool starting_with_empty_page; bool all_visible_cleared = false; + bool all_frozen_set = false; + uint8 vmstatus = 0; /* * Fill in tuple header fields and toast the tuple if necessary. @@ -1894,11 +1898,36 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid, /* * Find buffer to insert this tuple into. If the page is all visible, * this will also pin the requisite visibility map page. + * + * Also pin visibility map page if COPY FREEZE inserts tuples into an + * empty page. See all_frozen_set below. */ buffer = RelationGetBufferForTuple(relation, heaptup->t_len, InvalidBuffer, options, bistate, &vmbuffer, NULL); + + /* + * If we're inserting frozen entry into an empty page, + * set visibility map bits and PageAllVisible() hint. + * + * If we're inserting frozen entry into already all_frozen page, + * preserve this state. + */ + if (options & HEAP_INSERT_FROZEN) + { + page = BufferGetPage(buffer); + + starting_with_empty_page = PageGetMaxOffsetNumber(page) == 0; + + if (visibilitymap_pin_ok(BufferGetBlockNumber(buffer), vmbuffer)) + vmstatus = visibilitymap_get_status(relation, + BufferGetBlockNumber(buffer), &vmbuffer); + + if ((starting_with_empty_page || vmstatus & VISIBILITYMAP_ALL_FROZEN)) + all_frozen_set = true; + } + /* * We're about to do the actual insert -- but check for conflict first, to * avoid possibly having to roll back work we've just done. @@ -1922,7 +1951,14 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid, RelationPutHeapTuple(relation, buffer, heaptup, (options & HEAP_INSERT_SPECULATIVE) != 0); - if (PageIsAllVisible(BufferGetPage(buffer))) + /* + * If the page is all visible, need to clear that, unless we're only + * going to add further frozen rows to it. + * + * If we're only adding already frozen rows to a page that was empty or + * marked as all visible, mark it as all-visible. + */ + if (PageIsAllVisible(BufferGetPage(buffer)) && !(options & HEAP_INSERT_FROZEN)) { all_visible_cleared = true; PageClearAllVisible(BufferGetPage(buffer)); @@ -1930,6 +1966,13 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid, ItemPointerGetBlockNumber(&(heaptup->t_self)), vmbuffer, VISIBILITYMAP_VALID_BITS); } + else if (all_frozen_set) + { + /* We only ever set all_frozen_set after reading the page. */ + Assert(page); + + PageSetAllVisible(page); + } /* * XXX Should we set PageSetPrunable on this page ? @@ -1977,6 +2020,8 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid, xlrec.flags = 0; if (all_visible_cleared) xlrec.flags |= XLH_INSERT_ALL_VISIBLE_CLEARED; + if (all_frozen_set) + xlrec.flags = XLH_INSERT_ALL_FROZEN_SET; if (options & HEAP_INSERT_SPECULATIVE) xlrec.flags |= XLH_INSERT_IS_SPECULATIVE; Assert(ItemPointerGetBlockNumber(&heaptup->t_self) == BufferGetBlockNumber(buffer)); @@ -2025,6 +2070,29 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid, END_CRIT_SECTION(); + /* + * If we've frozen everything on the page, update the visibilitymap. + * We're already holding pin on the vmbuffer. + * + * No need to update the visibilitymap if it had all_frozen bit set + * before this insertion. + */ + if (all_frozen_set && ((vmstatus & VISIBILITYMAP_ALL_FROZEN) == 0)) + { + Assert(PageIsAllVisible(page)); + Assert(visibilitymap_pin_ok(BufferGetBlockNumber(buffer), vmbuffer)); + + /* + * It's fine to use InvalidTransactionId here - this is only used + * when HEAP_INSERT_FROZEN is specified, which intentionally + * violates visibility rules. + */ + visibilitymap_set(relation, BufferGetBlockNumber(buffer), buffer, + InvalidXLogRecPtr, vmbuffer, + InvalidTransactionId, + VISIBILITYMAP_ALL_VISIBLE | VISIBILITYMAP_ALL_FROZEN); + } + UnlockReleaseBuffer(buffer); if (vmbuffer != InvalidBuffer) ReleaseBuffer(vmbuffer); @@ -8708,6 +8776,10 @@ heap_xlog_insert(XLogReaderState *record) ItemPointerSetBlockNumber(&target_tid, blkno); ItemPointerSetOffsetNumber(&target_tid, xlrec->offnum); + /* check that the mutually exclusive flags are not both set */ + Assert (!((xlrec->flags & XLH_INSERT_ALL_VISIBLE_CLEARED) && + (xlrec->flags & XLH_INSERT_ALL_FROZEN_SET))); + /* * The visibility map may need to be fixed even if the heap page is * already up-to-date. @@ -8925,6 +8997,10 @@ heap_xlog_multi_insert(XLogReaderState *record) if (xlrec->flags & XLH_INSERT_ALL_VISIBLE_CLEARED) PageClearAllVisible(page); + /* XLH_INSERT_ALL_FROZEN_SET implies that all tuples are visible */ + if (xlrec->flags & XLH_INSERT_ALL_FROZEN_SET) + PageSetAllVisible(page); + MarkBufferDirty(buffer); } if (BufferIsValid(buffer)) diff --git a/src/backend/access/heap/hio.c b/src/backend/access/heap/hio.c index 2d23b3ef71945..fb7ad0bab47ac 100644 --- a/src/backend/access/heap/hio.c +++ b/src/backend/access/heap/hio.c @@ -396,19 +396,19 @@ RelationGetBufferForTuple(Relation relation, Size len, * target. */ targetBlock = GetPageWithFreeSpace(relation, len + saveFreeSpace); + } - /* - * If the FSM knows nothing of the rel, try the last page before we - * give up and extend. This avoids one-tuple-per-page syndrome during - * bootstrapping or in a recently-started system. - */ - if (targetBlock == InvalidBlockNumber) - { - BlockNumber nblocks = RelationGetNumberOfBlocks(relation); + /* + * If the FSM knows nothing of the rel, try the last page before we + * give up and extend. This avoids one-tuple-per-page syndrome during + * bootstrapping or in a recently-started system. + */ + if (targetBlock == InvalidBlockNumber) + { + BlockNumber nblocks = RelationGetNumberOfBlocks(relation); - if (nblocks > 0) - targetBlock = nblocks - 1; - } + if (nblocks > 0) + targetBlock = nblocks - 1; } loop: From 7e57255f6189380d545e1df6a6b38827b213e3da Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 23 Jan 2021 22:40:46 -0500 Subject: [PATCH 164/240] Doc: clean up contrib/pageinspect's GIST function documentation. I came to fix the overwidth-PDF-page warnings seen in the buildfarm, but stayed long enough to copy-edit some nearby text. --- doc/src/sgml/pageinspect.sgml | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/doc/src/sgml/pageinspect.sgml b/doc/src/sgml/pageinspect.sgml index 0cad08a8a7e32..a0be779940d66 100644 --- a/doc/src/sgml/pageinspect.sgml +++ b/doc/src/sgml/pageinspect.sgml @@ -685,9 +685,9 @@ test=# SELECT first_tid, nbytes, tids[0:5] AS some_tids - gist_page_opaque_info returns information about - a GiST index opaque area, like the NSN, rightlink and - page type. + gist_page_opaque_info returns information from + a GiST index page's opaque area, such as the NSN, + rightlink and page type. For example: test=# SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 2)); @@ -702,7 +702,7 @@ test=# SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 2)); - gist_page_items(page bytea, index oid) returns setof record + gist_page_items(page bytea, index_oid regclass) returns setof record gist_page_items @@ -711,7 +711,7 @@ test=# SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 2)); gist_page_items returns information about - the data stored in a page of GiST index. For example: + the data stored in a page of a GiST index. For example: test=# SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 0), 'test_gist_idx'); itemoffset | ctid | itemlen | keys @@ -739,19 +739,21 @@ test=# SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 0), 'test_gis - Same as gist_page_items, but returns the key data as a raw - bytea blob. For example: + Same as gist_page_items, but returns the key data + as a raw bytea blob. Since it does not attempt to decode + the key, it does not need to know which index is involved. For + example: test=# SELECT * FROM gist_page_items_bytea(get_raw_page('test_gist_idx', 0)); itemoffset | ctid | itemlen | key_data -------------+-----------+---------+------------------------------------------------------------------------------------ - 1 | (1,65535) | 40 | \x00000100ffff28000000000000c064400000000000c06440000000000000f03f000000000000f03f - 2 | (2,65535) | 40 | \x00000200ffff28000000000000c074400000000000c074400000000000e064400000000000e06440 - 3 | (3,65535) | 40 | \x00000300ffff28000000000000207f400000000000207f400000000000d074400000000000d07440 - 4 | (4,65535) | 40 | \x00000400ffff28000000000000c084400000000000c084400000000000307f400000000000307f40 - 5 | (5,65535) | 40 | \x00000500ffff28000000000000f089400000000000f089400000000000c884400000000000c88440 - 6 | (6,65535) | 40 | \x00000600ffff28000000000000208f400000000000208f400000000000f889400000000000f88940 - 7 | (7,65535) | 40 | \x00000700ffff28000000000000408f400000000000408f400000000000288f400000000000288f40 +------------+-----------+---------+-------------------------------------------&zwsp;----------------------------------------- + 1 | (1,65535) | 40 | \x00000100ffff28000000000000c0644000000000&zwsp;00c06440000000000000f03f000000000000f03f + 2 | (2,65535) | 40 | \x00000200ffff28000000000000c0744000000000&zwsp;00c074400000000000e064400000000000e06440 + 3 | (3,65535) | 40 | \x00000300ffff28000000000000207f4000000000&zwsp;00207f400000000000d074400000000000d07440 + 4 | (4,65535) | 40 | \x00000400ffff28000000000000c0844000000000&zwsp;00c084400000000000307f400000000000307f40 + 5 | (5,65535) | 40 | \x00000500ffff28000000000000f0894000000000&zwsp;00f089400000000000c884400000000000c88440 + 6 | (6,65535) | 40 | \x00000600ffff28000000000000208f4000000000&zwsp;00208f400000000000f889400000000000f88940 + 7 | (7,65535) | 40 | \x00000700ffff28000000000000408f4000000000&zwsp;00408f400000000000288f400000000000288f40 (7 rows) From 8a337b0ed21c654521da137159b8b9327a5cb971 Mon Sep 17 00:00:00 2001 From: Magnus Hagander Date: Sun, 24 Jan 2021 14:19:00 +0100 Subject: [PATCH 165/240] Remove make_diff set of tools These are mostly obsoleted by the switch to git, and it's easier to remove them than to update the incorrect documentation. Discussion: https://postgr.es/m/CABUevEwmASMn4WRJ6RagBx43sj10ctfMHcMA_-7KA3pDYmwpJw@mail.gmail.com --- src/tools/make_diff/README | 39 ------------------------------------ src/tools/make_diff/cporig | 11 ---------- src/tools/make_diff/difforig | 14 ------------- src/tools/make_diff/rmorig | 9 --------- 4 files changed, 73 deletions(-) delete mode 100644 src/tools/make_diff/README delete mode 100755 src/tools/make_diff/cporig delete mode 100755 src/tools/make_diff/difforig delete mode 100755 src/tools/make_diff/rmorig diff --git a/src/tools/make_diff/README b/src/tools/make_diff/README deleted file mode 100644 index 9401a74a647f4..0000000000000 --- a/src/tools/make_diff/README +++ /dev/null @@ -1,39 +0,0 @@ -src/tools/make_diff/README - -scripts -======= - -Here are some of the scripts I use to make development easier. - -First, I use 'cporig' on every file I am about to change. This makes a -copy with the extension .orig. If an .orig already exists, I am warned. - -I can get really fancy with this. I can do 'cporig *' and make a .orig -for every file in the current directory. I can: - - cporig `grep -l HeapTuple *` - -If I use mkid (from ftp.postgreSQL.org), I can do: - - cporig `lid -kn 'fsyncOff'` - -and get a copy of every file containing that word. I can then do: - - vi `find . -name '*.orig'` - -or even better (using mkid): - - eid fsyncOff - -to edit all those files. - -When I am ready to generate a patch, I run 'difforig' command from the top of -the source tree: - -I pipe the output of this to a file to hold my patch, and the file names -it processes appear on my screen. It creates a nice patch for me of all -the files I used with cporig. - -Finally, I remove my old copies with 'rmorig'. - -Bruce Momjian diff --git a/src/tools/make_diff/cporig b/src/tools/make_diff/cporig deleted file mode 100755 index 7b8f75feb43c7..0000000000000 --- a/src/tools/make_diff/cporig +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -# src/tools/make_diff/cporig - -for FILE -do - if [ ! -f "$FILE.orig" ] - then cp $FILE $FILE.orig - else echo "$FILE.orig exists" 1>&2 - fi -done diff --git a/src/tools/make_diff/difforig b/src/tools/make_diff/difforig deleted file mode 100755 index 08119a42c333d..0000000000000 --- a/src/tools/make_diff/difforig +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -# src/tools/make_diff/difforig - -if [ "$#" -eq 0 ] -then APATH="." -else APATH="$1" -fi -find $APATH -name '*.orig' -print | sort | while read FILE -do - NEW="`dirname $FILE`/`basename $FILE .orig`" - echo "$NEW" 1>&2 - diff -c $FILE $NEW -done diff --git a/src/tools/make_diff/rmorig b/src/tools/make_diff/rmorig deleted file mode 100755 index 9879b786f4ca8..0000000000000 --- a/src/tools/make_diff/rmorig +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -# src/tools/make_diff/rmorig - -if [ "$#" -eq 0 ] -then APATH="." -else APATH="$1" -fi -find $APATH -name '*.orig' -exec rm {} \; From 0c1e8845f28bd07ad381c8b0d6701575d967b88e Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 24 Jan 2021 14:59:33 -0500 Subject: [PATCH 166/240] Add a simple test for contrib/auto_explain. This module formerly had zero test coverage. Discussion: https://postgr.es/m/1445881.1611441692@sss.pgh.pa.us --- contrib/auto_explain/.gitignore | 4 ++ contrib/auto_explain/Makefile | 2 + contrib/auto_explain/t/001_auto_explain.pl | 52 ++++++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 contrib/auto_explain/.gitignore create mode 100644 contrib/auto_explain/t/001_auto_explain.pl diff --git a/contrib/auto_explain/.gitignore b/contrib/auto_explain/.gitignore new file mode 100644 index 0000000000000..5dcb3ff972350 --- /dev/null +++ b/contrib/auto_explain/.gitignore @@ -0,0 +1,4 @@ +# Generated subdirectories +/log/ +/results/ +/tmp_check/ diff --git a/contrib/auto_explain/Makefile b/contrib/auto_explain/Makefile index 54d6d45d4004b..efd127d3cae64 100644 --- a/contrib/auto_explain/Makefile +++ b/contrib/auto_explain/Makefile @@ -6,6 +6,8 @@ OBJS = \ auto_explain.o PGFILEDESC = "auto_explain - logging facility for execution plans" +TAP_TESTS = 1 + ifdef USE_PGXS PG_CONFIG = pg_config PGXS := $(shell $(PG_CONFIG) --pgxs) diff --git a/contrib/auto_explain/t/001_auto_explain.pl b/contrib/auto_explain/t/001_auto_explain.pl new file mode 100644 index 0000000000000..7968be963b125 --- /dev/null +++ b/contrib/auto_explain/t/001_auto_explain.pl @@ -0,0 +1,52 @@ +use strict; +use warnings; + +use PostgresNode; +use TestLib; +use Test::More tests => 4; + +my $node = get_new_node('main'); +$node->init; +$node->append_conf('postgresql.conf', + "shared_preload_libraries = 'auto_explain'"); +$node->append_conf('postgresql.conf', "auto_explain.log_min_duration = 0"); +$node->append_conf('postgresql.conf', "auto_explain.log_analyze = on"); +$node->start; + +# run a couple of queries +$node->safe_psql("postgres", "SELECT * FROM pg_class;"); +$node->safe_psql("postgres", + "SELECT * FROM pg_proc WHERE proname = 'int4pl';"); + +# emit some json too +$node->append_conf('postgresql.conf', "auto_explain.log_format = json"); +$node->reload; +$node->safe_psql("postgres", "SELECT * FROM pg_proc;"); +$node->safe_psql("postgres", + "SELECT * FROM pg_class WHERE relname = 'pg_class';"); + +$node->stop('fast'); + +my $log = $node->logfile(); + +my $log_contents = slurp_file($log); + +like( + $log_contents, + qr/Seq Scan on pg_class/, + "sequential scan logged, text mode"); + +like( + $log_contents, + qr/Index Scan using pg_proc_proname_args_nsp_index on pg_proc/, + "index scan logged, text mode"); + +like( + $log_contents, + qr/"Node Type": "Seq Scan"[^}]*"Relation Name": "pg_proc"/s, + "sequential scan logged, json mode"); + +like( + $log_contents, + qr/"Node Type": "Index Scan"[^}]*"Index Name": "pg_class_relname_nsp_index"/s, + "index scan logged, json mode"); From c7edf4ac246b67073563354c2808c78868cbac36 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 24 Jan 2021 16:29:47 -0500 Subject: [PATCH 167/240] Update time zone data files to tzdata release 2021a. DST law changes in Russia (Volgograd zone) and South Sudan. Historical corrections for Australia, Bahamas, Belize, Bermuda, Ghana, Israel, Kenya, Nigeria, Palestine, Seychelles, and Vanuatu. Notably, the Australia/Currie zone has been corrected to the point where it is identical to Australia/Hobart. --- src/timezone/Makefile | 3 +- src/timezone/data/tzdata.zi | 226 +++++++++++++++++++++--------------- 2 files changed, 133 insertions(+), 96 deletions(-) diff --git a/src/timezone/Makefile b/src/timezone/Makefile index 2b5d8ecbef810..fbbaae4cc57cb 100644 --- a/src/timezone/Makefile +++ b/src/timezone/Makefile @@ -60,9 +60,10 @@ ifeq (,$(with_system_tzdata)) endif $(MAKE) -C tznames $@ +# Note: -P code currently depends on '-b fat'. Not worth fixing right now. abbrevs.txt: zic $(TZDATAFILES) mkdir junkdir - $(ZIC) -P -d junkdir $(TZDATAFILES) | LANG=C sort | uniq >abbrevs.txt + $(ZIC) -P -b fat -d junkdir $(TZDATAFILES) | LANG=C sort | uniq >abbrevs.txt rm -rf junkdir installdirs: diff --git a/src/timezone/data/tzdata.zi b/src/timezone/data/tzdata.zi index 09afb428717f6..dfa7e88f8d895 100644 --- a/src/timezone/data/tzdata.zi +++ b/src/timezone/data/tzdata.zi @@ -1,4 +1,4 @@ -# version 2020d +# version 2021a # This zic input file is in the public domain. R d 1916 o - Jun 14 23s 1 S R d 1916 1919 - O Su>=1 23s 0 - @@ -86,17 +86,24 @@ R K 2014 o - Jul 31 24 1 S R K 2014 o - S lastTh 24 0 - Z Africa/Cairo 2:5:9 - LMT 1900 O 2 K EE%sT -R GH 1920 1942 - S 1 0 0:20 - -R GH 1920 1942 - D 31 0 0 - -Z Africa/Accra -0:0:52 - LMT 1918 -0 GH GMT/+0020 +R GH 1919 o - N 24 0 0:20 +0020 +R GH 1920 1942 - Ja 1 2 0 GMT +R GH 1920 1939 - S 1 2 0:20 +0020 +R GH 1940 1941 - May 1 2 0:20 +0020 +R GH 1950 1955 - S 1 2 0:30 +0030 +R GH 1951 1956 - Ja 1 2 0 GMT +Z Africa/Accra -0:0:52 - LMT 1915 N 2 +0 GH %s 1942 F 8 +0:30 - +0030 1946 Ja 6 +0 GH %s Z Africa/Bissau -1:2:20 - LMT 1912 Ja 1 1u -1 - -01 1975 0 - GMT -Z Africa/Nairobi 2:27:16 - LMT 1928 Jul -3 - EAT 1930 -2:30 - +0230 1940 -2:45 - +0245 1960 +Z Africa/Nairobi 2:27:16 - LMT 1908 May +2:30 - +0230 1928 Jun 30 24 +3 - EAT 1930 Ja 4 24 +2:30 - +0230 1936 D 31 24 +2:45 - +0245 1942 Jul 31 24 3 - EAT L Africa/Nairobi Africa/Addis_Ababa L Africa/Nairobi Africa/Asmara @@ -353,7 +360,10 @@ Z Africa/Windhoek 1:8:24 - LMT 1892 F 8 2 1 SAST 1943 Mar 21 2 2 - SAST 1990 Mar 21 2 NA %s -Z Africa/Lagos 0:13:36 - LMT 1919 S +Z Africa/Lagos 0:13:35 - LMT 1905 Jul +0 - GMT 1908 Jul +0:13:35 - LMT 1914 +0:30 - +0030 1919 S 1 - WAT L Africa/Lagos Africa/Bangui L Africa/Lagos Africa/Brazzaville @@ -371,7 +381,7 @@ Z Africa/Sao_Tome 0:26:56 - LMT 1884 0 - GMT 2018 Ja 1 1 1 - WAT 2019 Ja 1 2 0 - GMT -Z Indian/Mahe 3:41:48 - LMT 1906 Jun +Z Indian/Mahe 3:41:48 - LMT 1907 4 - +04 R SA 1942 1943 - S Su>=15 2 1 - R SA 1943 1944 - Mar Su>=15 2 0 - @@ -390,7 +400,8 @@ Z Africa/Khartoum 2:10:8 - LMT 1931 2 - CAT Z Africa/Juba 2:6:28 - LMT 1931 2 SD CA%sT 2000 Ja 15 12 -3 - EAT +3 - EAT 2021 F +2 - CAT R n 1939 o - Ap 15 23s 1 S R n 1939 o - N 18 23s 0 - R n 1940 o - F 25 23s 1 S @@ -782,68 +793,66 @@ Z Asia/Baghdad 2:57:40 - LMT 1890 2:57:36 - BMT 1918 3 - +03 1982 May 3 IQ +03/+04 -R Z 1940 o - Jun 1 0 1 D -R Z 1942 1944 - N 1 0 0 S -R Z 1943 o - Ap 1 2 1 D -R Z 1944 o - Ap 1 0 1 D -R Z 1945 o - Ap 16 0 1 D -R Z 1945 o - N 1 2 0 S -R Z 1946 o - Ap 16 2 1 D -R Z 1946 o - N 1 0 0 S -R Z 1948 o - May 23 0 2 DD -R Z 1948 o - S 1 0 1 D -R Z 1948 1949 - N 1 2 0 S -R Z 1949 o - May 1 0 1 D -R Z 1950 o - Ap 16 0 1 D -R Z 1950 o - S 15 3 0 S -R Z 1951 o - Ap 1 0 1 D -R Z 1951 o - N 11 3 0 S -R Z 1952 o - Ap 20 2 1 D -R Z 1952 o - O 19 3 0 S -R Z 1953 o - Ap 12 2 1 D -R Z 1953 o - S 13 3 0 S -R Z 1954 o - Jun 13 0 1 D -R Z 1954 o - S 12 0 0 S -R Z 1955 o - Jun 11 2 1 D -R Z 1955 o - S 11 0 0 S -R Z 1956 o - Jun 3 0 1 D -R Z 1956 o - S 30 3 0 S -R Z 1957 o - Ap 29 2 1 D -R Z 1957 o - S 22 0 0 S -R Z 1974 o - Jul 7 0 1 D -R Z 1974 o - O 13 0 0 S -R Z 1975 o - Ap 20 0 1 D -R Z 1975 o - Au 31 0 0 S -R Z 1980 o - Au 2 0 1 D -R Z 1980 o - S 13 1 0 S -R Z 1984 o - May 5 0 1 D -R Z 1984 o - Au 25 1 0 S -R Z 1985 o - Ap 14 0 1 D -R Z 1985 o - S 15 0 0 S -R Z 1986 o - May 18 0 1 D -R Z 1986 o - S 7 0 0 S -R Z 1987 o - Ap 15 0 1 D -R Z 1987 o - S 13 0 0 S -R Z 1988 o - Ap 10 0 1 D -R Z 1988 o - S 4 0 0 S -R Z 1989 o - Ap 30 0 1 D -R Z 1989 o - S 3 0 0 S -R Z 1990 o - Mar 25 0 1 D -R Z 1990 o - Au 26 0 0 S -R Z 1991 o - Mar 24 0 1 D -R Z 1991 o - S 1 0 0 S -R Z 1992 o - Mar 29 0 1 D -R Z 1992 o - S 6 0 0 S +R Z 1940 o - May 31 24u 1 D +R Z 1940 o - S 30 24u 0 S +R Z 1940 o - N 16 24u 1 D +R Z 1942 1946 - O 31 24u 0 S +R Z 1943 1944 - Mar 31 24u 1 D +R Z 1945 1946 - Ap 15 24u 1 D +R Z 1948 o - May 22 24u 2 DD +R Z 1948 o - Au 31 24u 1 D +R Z 1948 1949 - O 31 24u 0 S +R Z 1949 o - Ap 30 24u 1 D +R Z 1950 o - Ap 15 24u 1 D +R Z 1950 o - S 14 24u 0 S +R Z 1951 o - Mar 31 24u 1 D +R Z 1951 o - N 10 24u 0 S +R Z 1952 o - Ap 19 24u 1 D +R Z 1952 o - O 18 24u 0 S +R Z 1953 o - Ap 11 24u 1 D +R Z 1953 o - S 12 24u 0 S +R Z 1954 o - Jun 12 24u 1 D +R Z 1954 o - S 11 24u 0 S +R Z 1955 o - Jun 11 24u 1 D +R Z 1955 o - S 10 24u 0 S +R Z 1956 o - Jun 2 24u 1 D +R Z 1956 o - S 29 24u 0 S +R Z 1957 o - Ap 27 24u 1 D +R Z 1957 o - S 21 24u 0 S +R Z 1974 o - Jul 6 24 1 D +R Z 1974 o - O 12 24 0 S +R Z 1975 o - Ap 19 24 1 D +R Z 1975 o - Au 30 24 0 S +R Z 1980 o - Au 2 24s 1 D +R Z 1980 o - S 13 24s 0 S +R Z 1984 o - May 5 24s 1 D +R Z 1984 o - Au 25 24s 0 S +R Z 1985 o - Ap 13 24 1 D +R Z 1985 o - Au 31 24 0 S +R Z 1986 o - May 17 24 1 D +R Z 1986 o - S 6 24 0 S +R Z 1987 o - Ap 14 24 1 D +R Z 1987 o - S 12 24 0 S +R Z 1988 o - Ap 9 24 1 D +R Z 1988 o - S 3 24 0 S +R Z 1989 o - Ap 29 24 1 D +R Z 1989 o - S 2 24 0 S +R Z 1990 o - Mar 24 24 1 D +R Z 1990 o - Au 25 24 0 S +R Z 1991 o - Mar 23 24 1 D +R Z 1991 o - Au 31 24 0 S +R Z 1992 o - Mar 28 24 1 D +R Z 1992 o - S 5 24 0 S R Z 1993 o - Ap 2 0 1 D R Z 1993 o - S 5 0 0 S R Z 1994 o - Ap 1 0 1 D R Z 1994 o - Au 28 0 0 S R Z 1995 o - Mar 31 0 1 D R Z 1995 o - S 3 0 0 S -R Z 1996 o - Mar 15 0 1 D -R Z 1996 o - S 16 0 0 S -R Z 1997 o - Mar 21 0 1 D -R Z 1997 o - S 14 0 0 S +R Z 1996 o - Mar 14 24 1 D +R Z 1996 o - S 15 24 0 S +R Z 1997 o - Mar 20 24 1 D +R Z 1997 o - S 13 24 0 S R Z 1998 o - Mar 20 0 1 D R Z 1998 o - S 6 0 0 S R Z 1999 o - Ap 2 2 1 D @@ -1256,13 +1265,13 @@ Z Asia/Ho_Chi_Minh 7:6:40 - LMT 1906 Jul 7 - +07 1959 D 31 23 8 - +08 1975 Jun 13 7 - +07 -R AU 1917 o - Ja 1 0:1 1 D -R AU 1917 o - Mar 25 2 0 S -R AU 1942 o - Ja 1 2 1 D -R AU 1942 o - Mar 29 2 0 S -R AU 1942 o - S 27 2 1 D -R AU 1943 1944 - Mar lastSu 2 0 S -R AU 1943 o - O 3 2 1 D +R AU 1917 o - Ja 1 2s 1 D +R AU 1917 o - Mar lastSu 2s 0 S +R AU 1942 o - Ja 1 2s 1 D +R AU 1942 o - Mar lastSu 2s 0 S +R AU 1942 o - S 27 2s 1 D +R AU 1943 1944 - Mar lastSu 2s 0 S +R AU 1943 o - O 3 2s 1 D Z Australia/Darwin 8:43:20 - LMT 1895 F 9 - ACST 1899 May 9:30 AU AC%sT @@ -1313,8 +1322,12 @@ Z Australia/Adelaide 9:14:20 - LMT 1895 F 9 - ACST 1899 May 9:30 AU AC%sT 1971 9:30 AS AC%sT +R AT 1916 o - O Su>=1 2s 1 D +R AT 1917 o - Mar lastSu 2s 0 S +R AT 1917 1918 - O Su>=22 2s 1 D +R AT 1918 1919 - Mar Su>=1 2s 0 S R AT 1967 o - O Su>=1 2s 1 D -R AT 1968 o - Mar lastSu 2s 0 S +R AT 1968 o - Mar Su>=29 2s 0 S R AT 1968 1985 - O lastSu 2s 1 D R AT 1969 1971 - Mar Su>=8 2s 0 S R AT 1972 o - F lastSu 2s 0 S @@ -1333,15 +1346,9 @@ R AT 2006 o - Ap Su>=1 2s 0 S R AT 2007 o - Mar lastSu 2s 0 S R AT 2008 ma - Ap Su>=1 2s 0 S Z Australia/Hobart 9:49:16 - LMT 1895 S -10 - AEST 1916 O 1 2 -10 1 AEDT 1917 F +10 AT AE%sT 1919 O 24 10 AU AE%sT 1967 10 AT AE%sT -Z Australia/Currie 9:35:28 - LMT 1895 S -10 - AEST 1916 O 1 2 -10 1 AEDT 1917 F -10 AU AE%sT 1971 Jul -10 AT AE%sT R AV 1971 1985 - O lastSu 2s 1 D R AV 1972 o - F lastSu 2s 0 S R AV 1973 1985 - Mar Su>=1 2s 0 S @@ -1615,12 +1622,12 @@ Z Pacific/Funafuti 11:56:52 - LMT 1901 12 - +12 Z Pacific/Wake 11:6:28 - LMT 1901 12 - +12 -R VU 1983 o - S 25 0 1 - -R VU 1984 1991 - Mar Su>=23 0 0 - -R VU 1984 o - O 23 0 1 - -R VU 1985 1991 - S Su>=23 0 1 - -R VU 1992 1993 - Ja Su>=23 0 0 - -R VU 1992 o - O Su>=23 0 1 - +R VU 1973 o - D 22 12u 1 - +R VU 1974 o - Mar 30 12u 0 - +R VU 1983 1991 - S Sa>=22 24 1 - +R VU 1984 1991 - Mar Sa>=22 24 0 - +R VU 1992 1993 - Ja Sa>=22 24 0 - +R VU 1992 o - O Sa>=22 24 1 - Z Pacific/Efate 11:13:16 - LMT 1912 Ja 13 11 VU +11/+12 Z Pacific/Wallis 12:15:20 - LMT 1901 @@ -2463,7 +2470,8 @@ Z Europe/Volgograd 2:57:40 - LMT 1920 Ja 3 3 R +03/+04 2011 Mar 27 2s 4 - +04 2014 O 26 2s 3 - +03 2018 O 28 2s -4 - +04 +4 - +04 2020 D 27 2s +3 - +03 Z Europe/Saratov 3:4:18 - LMT 1919 Jul 1 0u 3 - +03 1930 Jun 21 4 R +04/+05 1988 Mar 27 2s @@ -3546,6 +3554,11 @@ Z America/Tijuana -7:48:4 - LMT 1922 Ja 1 0:11:56 -8 u P%sT 2002 F 20 -8 m P%sT 2010 -8 u P%sT +R BS 1942 o - May 1 24 1 W +R BS 1944 o - D 31 24 0 S +R BS 1945 o - F 1 0 1 W +R BS 1945 o - Au 14 23u 1 P +R BS 1945 o - O 17 24 0 S R BS 1964 1975 - O lastSu 2 0 S R BS 1964 1975 - Ap lastSu 2 1 D Z America/Nassau -5:9:30 - LMT 1912 Mar 2 @@ -3559,16 +3572,38 @@ R BB 1980 o - S 25 2 0 S Z America/Barbados -3:58:29 - LMT 1924 -3:58:29 - BMT 1932 -4 BB A%sT -R BZ 1918 1942 - O Su>=2 0 0:30 -0530 -R BZ 1919 1943 - F Su>=9 0 0 CST +R BZ 1918 1941 - O Sa>=1 24 0:30 -0530 +R BZ 1919 1942 - F Sa>=8 24 0 CST +R BZ 1942 o - Jun 27 24 1 CWT +R BZ 1945 o - Au 14 23u 1 CPT +R BZ 1945 o - D 15 24 0 CST +R BZ 1947 1967 - O Sa>=1 24 0:30 -0530 +R BZ 1948 1968 - F Sa>=8 24 0 CST R BZ 1973 o - D 5 0 1 CDT R BZ 1974 o - F 9 0 0 CST R BZ 1982 o - D 18 0 1 CDT R BZ 1983 o - F 12 0 0 CST Z America/Belize -5:52:48 - LMT 1912 Ap -6 BZ %s -Z Atlantic/Bermuda -4:19:18 - LMT 1930 Ja 1 2 --4 - AST 1974 Ap 28 2 +R Be 1917 o - Ap 5 24 1 - +R Be 1917 o - S 30 24 0 - +R Be 1918 o - Ap 13 24 1 - +R Be 1918 o - S 15 24 0 S +R Be 1942 o - Ja 11 2 1 D +R Be 1942 o - O 18 2 0 S +R Be 1943 o - Mar 21 2 1 D +R Be 1943 o - O 31 2 0 S +R Be 1944 1945 - Mar Su>=8 2 1 D +R Be 1944 1945 - N Su>=1 2 0 S +R Be 1947 o - May Su>=15 2 1 D +R Be 1947 o - S Su>=8 2 0 S +R Be 1948 1952 - May Su>=22 2 1 D +R Be 1948 1952 - S Su>=1 2 0 S +R Be 1956 o - May Su>=22 2 1 D +R Be 1956 o - O lastSu 2 0 S +Z Atlantic/Bermuda -4:19:18 - LMT 1890 +-4:19:18 Be BMT/BST 1930 Ja 1 2 +-4 Be A%sT 1974 Ap 28 2 -4 C A%sT 1976 -4 u A%sT R CR 1979 1980 - F lastSu 0 1 D @@ -3707,7 +3742,7 @@ Z America/Miquelon -3:44:40 - LMT 1911 May 15 Z America/Grand_Turk -4:44:32 - LMT 1890 -5:7:10 - KMT 1912 F -5 - EST 1979 --5 u E%sT 2015 N Su>=1 2 +-5 u E%sT 2015 Mar 8 2 -4 - AST 2018 Mar 11 3 -5 u E%sT R A 1930 o - D 1 0 1 - @@ -4343,6 +4378,7 @@ L Atlantic/Faroe Atlantic/Faeroe L Europe/Oslo Atlantic/Jan_Mayen L Australia/Sydney Australia/ACT L Australia/Sydney Australia/Canberra +L Australia/Hobart Australia/Currie L Australia/Lord_Howe Australia/LHI L Australia/Sydney Australia/NSW L Australia/Darwin Australia/North From a4b03de589c1df0845e9732da203f505f2eedb6d Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 24 Jan 2021 18:08:55 -0500 Subject: [PATCH 168/240] Make storage/standby.h compile standalone again. This file has failed headerscheck/cpluspluscheck verification since commit 0650ff230, as a result of referencing typedef TimestampTz without including the appropriate header. --- src/include/storage/standby.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h index 2b1f340b82b8c..94d33851d09e7 100644 --- a/src/include/storage/standby.h +++ b/src/include/storage/standby.h @@ -14,6 +14,7 @@ #ifndef STANDBY_H #define STANDBY_H +#include "datatype/timestamp.h" #include "storage/lock.h" #include "storage/procsignal.h" #include "storage/relfilenode.h" From 40ab64c1ec1cb9bd73695f519cf66ddbb97d8144 Mon Sep 17 00:00:00 2001 From: Amit Kapila Date: Mon, 25 Jan 2021 07:39:29 +0530 Subject: [PATCH 169/240] Fix ALTER PUBLICATION...DROP TABLE behavior. Commit 69bd60672 fixed the initialization of streamed transactions for RelationSyncEntry. It forgot to initialize the publication actions while invalidating the RelationSyncEntry due to which even though the relation is dropped from a particular publication we still publish its changes. Fix it by initializing pubactions when entry got invalidated. Author: Japin Li and Bharath Rupireddy Reviewed-by: Amit Kapila Discussion: https://postgr.es/m/CALj2ACV+0UFpcZs5czYgBpujM9p0Hg1qdOZai_43OU7bqHU_xw@mail.gmail.com --- src/backend/replication/pgoutput/pgoutput.c | 11 +++ src/test/subscription/t/001_rep_changes.pl | 95 ++++++++++++++++++++- 2 files changed, 105 insertions(+), 1 deletion(-) diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c index 2f01137b426cd..79765f96969df 100644 --- a/src/backend/replication/pgoutput/pgoutput.c +++ b/src/backend/replication/pgoutput/pgoutput.c @@ -1179,5 +1179,16 @@ rel_sync_cache_publication_cb(Datum arg, int cacheid, uint32 hashvalue) */ hash_seq_init(&status, RelationSyncCache); while ((entry = (RelationSyncEntry *) hash_seq_search(&status)) != NULL) + { entry->replicate_valid = false; + + /* + * There might be some relations dropped from the publication so we + * don't need to publish the changes for them. + */ + entry->pubactions.pubinsert = false; + entry->pubactions.pubupdate = false; + entry->pubactions.pubdelete = false; + entry->pubactions.pubtruncate = false; + } } diff --git a/src/test/subscription/t/001_rep_changes.pl b/src/test/subscription/t/001_rep_changes.pl index 0680f44a1aa5d..c20fadcb0e340 100644 --- a/src/test/subscription/t/001_rep_changes.pl +++ b/src/test/subscription/t/001_rep_changes.pl @@ -3,7 +3,7 @@ use warnings; use PostgresNode; use TestLib; -use Test::More tests => 23; +use Test::More tests => 27; # Initialize publisher node my $node_publisher = get_new_node('publisher'); @@ -153,6 +153,99 @@ $node_publisher->safe_psql('postgres', "INSERT INTO tab_full SELECT generate_series(1,10)"); +# Test behaviour of ALTER PUBLICATION ... DROP TABLE +# +# When a publisher drops a table from publication, it should also stop sending +# its changes to subscribers. We look at the subscriber whether it receives +# the row that is inserted to the table in the publisher after it is dropped +# from the publication. +$result = $node_subscriber->safe_psql('postgres', + "SELECT count(*), min(a), max(a) FROM tab_ins"); +is($result, qq(1052|1|1002), 'check rows on subscriber before table drop from publication'); + +# Drop the table from publication +$node_publisher->safe_psql('postgres', + "ALTER PUBLICATION tap_pub_ins_only DROP TABLE tab_ins"); + +# Insert a row in publisher, but publisher will not send this row to subscriber +$node_publisher->safe_psql('postgres', "INSERT INTO tab_ins VALUES(8888)"); + +$node_publisher->wait_for_catchup('tap_sub'); + +# Subscriber will not receive the inserted row, after table is dropped from +# publication, so row count should remain the same. +$result = $node_subscriber->safe_psql('postgres', + "SELECT count(*), min(a), max(a) FROM tab_ins"); +is($result, qq(1052|1|1002), 'check rows on subscriber after table drop from publication'); + +# Delete the inserted row in publisher +$node_publisher->safe_psql('postgres', "DELETE FROM tab_ins WHERE a = 8888"); + +# Add the table to publication again +$node_publisher->safe_psql('postgres', + "ALTER PUBLICATION tap_pub_ins_only ADD TABLE tab_ins"); + +# Refresh publication after table is added to publication +$node_subscriber->safe_psql('postgres', + "ALTER SUBSCRIPTION tap_sub REFRESH PUBLICATION"); + +# Test replication with multiple publications for a subscription such that the +# operations are performed on the table from the first publication in the list. + +# Create tables on publisher +$node_publisher->safe_psql('postgres', "CREATE TABLE temp1 (a int)"); +$node_publisher->safe_psql('postgres', "CREATE TABLE temp2 (a int)"); + +# Create tables on subscriber +$node_subscriber->safe_psql('postgres', "CREATE TABLE temp1 (a int)"); +$node_subscriber->safe_psql('postgres', "CREATE TABLE temp2 (a int)"); + +# Setup logical replication that will only be used for this test +$node_publisher->safe_psql('postgres', + "CREATE PUBLICATION tap_pub_temp1 FOR TABLE temp1 WITH (publish = insert)"); +$node_publisher->safe_psql('postgres', + "CREATE PUBLICATION tap_pub_temp2 FOR TABLE temp2"); +$node_subscriber->safe_psql('postgres', + "CREATE SUBSCRIPTION tap_sub_temp1 CONNECTION '$publisher_connstr' PUBLICATION tap_pub_temp1, tap_pub_temp2" +); + +$node_publisher->wait_for_catchup('tap_sub_temp1'); + +# Also wait for initial table sync to finish +$synced_query = + "SELECT count(1) = 0 FROM pg_subscription_rel WHERE srsubstate NOT IN ('r', 's');"; +$node_subscriber->poll_query_until('postgres', $synced_query) + or die "Timed out while waiting for subscriber to synchronize data"; + +# Subscriber table will have no rows initially +$result = $node_subscriber->safe_psql('postgres', + "SELECT count(*) FROM temp1"); +is($result, qq(0), 'check initial rows on subscriber with multiple publications'); + +# Insert a row into the table that's part of first publication in subscriber +# list of publications. +$node_publisher->safe_psql('postgres', "INSERT INTO temp1 VALUES (1)"); + +$node_publisher->wait_for_catchup('tap_sub_temp1'); + +# Subscriber should receive the inserted row +$result = $node_subscriber->safe_psql('postgres', + "SELECT count(*) FROM temp1"); +is($result, qq(1), 'check rows on subscriber with multiple publications'); + +# Drop subscription as we don't need it anymore +$node_subscriber->safe_psql('postgres', "DROP SUBSCRIPTION tap_sub_temp1"); + +# Drop publications as we don't need them anymore +$node_publisher->safe_psql('postgres', "DROP PUBLICATION tap_pub_temp1"); +$node_publisher->safe_psql('postgres', "DROP PUBLICATION tap_pub_temp2"); + +# Clean up the tables on both publisher and subscriber as we don't need them +$node_publisher->safe_psql('postgres', "DROP TABLE temp1"); +$node_publisher->safe_psql('postgres', "DROP TABLE temp2"); +$node_subscriber->safe_psql('postgres', "DROP TABLE temp1"); +$node_subscriber->safe_psql('postgres', "DROP TABLE temp2"); + # add REPLICA IDENTITY FULL so we can update $node_publisher->safe_psql('postgres', "ALTER TABLE tab_full REPLICA IDENTITY FULL"); From 16dfe253e31f75b60e93acc0c2b5bbf19936c074 Mon Sep 17 00:00:00 2001 From: David Rowley Date: Mon, 25 Jan 2021 19:52:18 +1300 Subject: [PATCH 170/240] Fix hypothetical bug in heap backward scans Both heapgettup() and heapgettup_pagemode() incorrectly set the first page to scan in a backward scan in which the number of pages to scan was specified by heap_setscanlimits(). The code incorrectly started the scan at the end of the relation when startBlk was 0, or otherwise at startBlk - 1, neither of which is correct when only scanning a subset of pages. The fix here checks if heap_setscanlimits() has changed the number of pages to scan and if so we set the first page to scan as the final page in the specified range during backward scans. Proper adjustment of this code was forgotten when heap_setscanlimits() was added in 7516f5259 back in 9.5. However, practice, nowhere in core code performs backward scans after having used heap_setscanlimits(), yet, it is possible an extension uses the heap functions in this way, hence backpatch. An upcoming patch does use heap_setscanlimits() with backward scans, so this must be fixed before that can go in. Author: David Rowley Discussion: https://postgr.es/m/CAApHDvpGc9h0_oVD2CtgBcxCS1N-qDYZSeBRnUh+0CWJA9cMaA@mail.gmail.com Backpatch-through: 9.5, all supported versions --- src/backend/access/heap/heapam.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index d107e14690c7e..9926e2bd546ae 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -603,8 +603,14 @@ heapgettup(HeapScanDesc scan, * forward scanners. */ scan->rs_base.rs_flags &= ~SO_ALLOW_SYNC; - /* start from last page of the scan */ - if (scan->rs_startblock > 0) + + /* + * Start from last page of the scan. Ensure we take into account + * rs_numblocks if it's been adjusted by heap_setscanlimits(). + */ + if (scan->rs_numblocks != InvalidBlockNumber) + page = (scan->rs_startblock + scan->rs_numblocks - 1) % scan->rs_nblocks; + else if (scan->rs_startblock > 0) page = scan->rs_startblock - 1; else page = scan->rs_nblocks - 1; @@ -918,8 +924,14 @@ heapgettup_pagemode(HeapScanDesc scan, * forward scanners. */ scan->rs_base.rs_flags &= ~SO_ALLOW_SYNC; - /* start from last page of the scan */ - if (scan->rs_startblock > 0) + + /* + * Start from last page of the scan. Ensure we take into account + * rs_numblocks if it's been adjusted by heap_setscanlimits(). + */ + if (scan->rs_numblocks != InvalidBlockNumber) + page = (scan->rs_startblock + scan->rs_numblocks - 1) % scan->rs_nblocks; + else if (scan->rs_startblock > 0) page = scan->rs_startblock - 1; else page = scan->rs_nblocks - 1; From ecc4b1318c92594abdf9bd2933fb6feaa9d56229 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Mon, 25 Jan 2021 08:55:43 +0100 Subject: [PATCH 171/240] Remove duplicate include Reported-by: Ashutosh Sharma Discussion: https://www.postgresql.org/message-id/flat/CAE9k0PkORqHHGKY54-sFyDpP90yAf%2B05Auc4fs9EAn4J%2BuBeUQ%40mail.gmail.com --- .../ecpg/test/expected/preproc-define.c | 67 +++++++++---------- .../ecpg/test/expected/preproc-define.stderr | 48 ++++++------- src/interfaces/ecpg/test/preproc/define.pgc | 1 - 3 files changed, 57 insertions(+), 59 deletions(-) diff --git a/src/interfaces/ecpg/test/expected/preproc-define.c b/src/interfaces/ecpg/test/expected/preproc-define.c index 0256609b1f96c..455e96a39cc08 100644 --- a/src/interfaces/ecpg/test/expected/preproc-define.c +++ b/src/interfaces/ecpg/test/expected/preproc-define.c @@ -9,7 +9,6 @@ #line 1 "define.pgc" #include #include -#include #include @@ -20,18 +19,18 @@ -#line 6 "define.pgc" +#line 5 "define.pgc" /* exec sql whenever sqlerror sqlprint ; */ -#line 8 "define.pgc" +#line 7 "define.pgc" /* exec sql type intarray is int [ 6 ] */ -#line 13 "define.pgc" +#line 12 "define.pgc" typedef int intarray[ 6]; @@ -43,7 +42,7 @@ main(void) typedef char string [ 8 ]; -#line 22 "define.pgc" +#line 21 "define.pgc" @@ -65,65 +64,65 @@ main(void) -#line 23 "define.pgc" +#line 22 "define.pgc" intarray amount ; -#line 24 "define.pgc" +#line 23 "define.pgc" char name [ 6 ] [ 8 ] ; -#line 37 "define.pgc" +#line 36 "define.pgc" char letter [ 6 ] [ 1 ] ; #if 0 -#line 39 "define.pgc" +#line 38 "define.pgc" int not_used ; #endif /* exec sql end declare section */ -#line 46 "define.pgc" +#line 45 "define.pgc" int i,j; ECPGdebug(1, stderr); { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , NULL, 0); -#line 51 "define.pgc" +#line 50 "define.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 51 "define.pgc" +#line 50 "define.pgc" { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table test ( name char ( 8 ) , amount int , letter char ( 1 ) )", ECPGt_EOIT, ECPGt_EORT); -#line 53 "define.pgc" +#line 52 "define.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 53 "define.pgc" +#line 52 "define.pgc" { ECPGtrans(__LINE__, NULL, "commit"); -#line 54 "define.pgc" +#line 53 "define.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 54 "define.pgc" +#line 53 "define.pgc" { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into Test ( name , amount , letter ) values ( 'false' , 1 , 'f' )", ECPGt_EOIT, ECPGt_EORT); -#line 56 "define.pgc" +#line 55 "define.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 56 "define.pgc" +#line 55 "define.pgc" { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into test ( name , amount , letter ) values ( 'true' , 2 , 't' )", ECPGt_EOIT, ECPGt_EORT); -#line 57 "define.pgc" +#line 56 "define.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 57 "define.pgc" +#line 56 "define.pgc" { ECPGtrans(__LINE__, NULL, "commit"); -#line 58 "define.pgc" +#line 57 "define.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 58 "define.pgc" +#line 57 "define.pgc" { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select * from test", ECPGt_EOIT, @@ -133,10 +132,10 @@ if (sqlca.sqlcode < 0) sqlprint();} ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_char,(letter),(long)1,(long)6,(1)*sizeof(char), ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT); -#line 60 "define.pgc" +#line 59 "define.pgc" if (sqlca.sqlcode < 0) sqlprint();} -#line 60 "define.pgc" +#line 59 "define.pgc" for (i=0, j=sqlca.sqlerrd[2]; i port [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute on line 53: query: create table test ( name char ( 8 ) , amount int , letter char ( 1 ) ); with 0 parameter(s) on connection ecpg1_regression +[NO_PID]: ecpg_execute on line 52: query: create table test ( name char ( 8 ) , amount int , letter char ( 1 ) ); with 0 parameter(s) on connection ecpg1_regression [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute on line 53: using PQexec +[NO_PID]: ecpg_execute on line 52: using PQexec [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_process_output on line 53: OK: CREATE TABLE +[NO_PID]: ecpg_process_output on line 52: OK: CREATE TABLE [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ECPGtrans on line 54: action "commit"; connection "ecpg1_regression" +[NO_PID]: ECPGtrans on line 53: action "commit"; connection "ecpg1_regression" [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute on line 56: query: insert into Test ( name , amount , letter ) values ( 'false' , 1 , 'f' ); with 0 parameter(s) on connection ecpg1_regression +[NO_PID]: ecpg_execute on line 55: query: insert into Test ( name , amount , letter ) values ( 'false' , 1 , 'f' ); with 0 parameter(s) on connection ecpg1_regression [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute on line 56: using PQexec +[NO_PID]: ecpg_execute on line 55: using PQexec [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_process_output on line 56: OK: INSERT 0 1 +[NO_PID]: ecpg_process_output on line 55: OK: INSERT 0 1 [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute on line 57: query: insert into test ( name , amount , letter ) values ( 'true' , 2 , 't' ); with 0 parameter(s) on connection ecpg1_regression +[NO_PID]: ecpg_execute on line 56: query: insert into test ( name , amount , letter ) values ( 'true' , 2 , 't' ); with 0 parameter(s) on connection ecpg1_regression [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute on line 57: using PQexec +[NO_PID]: ecpg_execute on line 56: using PQexec [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_process_output on line 57: OK: INSERT 0 1 +[NO_PID]: ecpg_process_output on line 56: OK: INSERT 0 1 [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ECPGtrans on line 58: action "commit"; connection "ecpg1_regression" +[NO_PID]: ECPGtrans on line 57: action "commit"; connection "ecpg1_regression" [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute on line 60: query: select * from test; with 0 parameter(s) on connection ecpg1_regression +[NO_PID]: ecpg_execute on line 59: query: select * from test; with 0 parameter(s) on connection ecpg1_regression [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute on line 60: using PQexec +[NO_PID]: ecpg_execute on line 59: using PQexec [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_process_output on line 60: correctly got 2 tuples with 3 fields +[NO_PID]: ecpg_process_output on line 59: correctly got 2 tuples with 3 fields [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_get_data on line 60: RESULT: false offset: -1; array: no +[NO_PID]: ecpg_get_data on line 59: RESULT: false offset: -1; array: no [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_get_data on line 60: RESULT: true offset: -1; array: no +[NO_PID]: ecpg_get_data on line 59: RESULT: true offset: -1; array: no [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_get_data on line 60: RESULT: 1 offset: -1; array: no +[NO_PID]: ecpg_get_data on line 59: RESULT: 1 offset: -1; array: no [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_get_data on line 60: RESULT: 2 offset: -1; array: no +[NO_PID]: ecpg_get_data on line 59: RESULT: 2 offset: -1; array: no [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_get_data on line 60: RESULT: f offset: -1; array: no +[NO_PID]: ecpg_get_data on line 59: RESULT: f offset: -1; array: no [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_get_data on line 60: RESULT: t offset: -1; array: no +[NO_PID]: ecpg_get_data on line 59: RESULT: t offset: -1; array: no [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute on line 74: query: drop table test; with 0 parameter(s) on connection ecpg1_regression +[NO_PID]: ecpg_execute on line 73: query: drop table test; with 0 parameter(s) on connection ecpg1_regression [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute on line 74: using PQexec +[NO_PID]: ecpg_execute on line 73: using PQexec [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_process_output on line 74: OK: DROP TABLE +[NO_PID]: ecpg_process_output on line 73: OK: DROP TABLE [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ECPGtrans on line 75: action "commit"; connection "ecpg1_regression" +[NO_PID]: ECPGtrans on line 74: action "commit"; connection "ecpg1_regression" [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ecpg_finish: connection ecpg1_regression closed [NO_PID]: sqlca: code: 0, state: 00000 diff --git a/src/interfaces/ecpg/test/preproc/define.pgc b/src/interfaces/ecpg/test/preproc/define.pgc index d360da7ece2a8..90dc32856ef98 100644 --- a/src/interfaces/ecpg/test/preproc/define.pgc +++ b/src/interfaces/ecpg/test/preproc/define.pgc @@ -1,6 +1,5 @@ #include #include -#include #include exec sql include ../regression; From 951862eda57e5dc8f78c97b3c30fe2032a5562b8 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 25 Jan 2021 11:20:17 -0500 Subject: [PATCH 172/240] Doc: improve documentation of pg_proc.protrftypes. Add a "references" link pointing to pg_type, as we have for other arrays of type OIDs. Wordsmith the explanation a bit. Joel Jacobson, additional editing by me Discussion: https://postgr.es/m/d1cc628c-3953-4209-957b-29427acc38c8@www.fastmail.com --- doc/src/sgml/catalogs.sgml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 43d7a1ad90e00..865e826fb0b34 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -5874,7 +5874,7 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_type.oid) - An array with the data types of the function arguments. This includes + An array of the data types of the function arguments. This includes only input arguments (including INOUT and VARIADIC arguments), as well as OUT parameters of procedures, and thus represents @@ -5888,7 +5888,7 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_type.oid) - An array with the data types of the function arguments. This includes + An array of the data types of the function arguments. This includes all arguments (including OUT and INOUT arguments); however, if all the arguments are IN arguments, this field will be null. @@ -5902,7 +5902,7 @@ SCRAM-SHA-256$<iteration count>:&l proargmodes char[] - An array with the modes of the function arguments, encoded as + An array of the modes of the function arguments, encoded as i for IN arguments, o for OUT arguments, b for INOUT arguments, @@ -5920,7 +5920,7 @@ SCRAM-SHA-256$<iteration count>:&l proargnames text[] - An array with the names of the function arguments. + An array of the names of the function arguments. Arguments without a name are set to empty strings in the array. If none of the arguments have a name, this field will be null. Note that subscripts correspond to positions of @@ -5945,9 +5945,12 @@ SCRAM-SHA-256$<iteration count>:&l protrftypes oid[] + (references pg_type.oid) - Data type OIDs for which to apply transforms. + An array of the argument/result data type(s) for which to apply + transforms (from the function's TRANSFORM + clause). Null if none. From d18e75664a2fda2e4d5cc433d68e37fc0e9499f2 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Mon, 25 Jan 2021 12:34:00 -0500 Subject: [PATCH 173/240] Remove CheckpointLock. Up until now, we've held this lock when performing a checkpoint or restartpoint, but commit 076a055acf3c55314de267c62b03191586d79cf6 back in 2004 and commit 7e48b77b1cebb9a43f9fdd6b17128a0ba36132f9 from 2009, taken together, have removed all need for this. In the present code, there's only ever one process entitled to attempt a checkpoint: either the checkpointer, during normal operation, or the postmaster, during single-user operation. So, we don't need the lock. One possible concern in making this change is that it means that a substantial amount of code where HOLD_INTERRUPTS() was previously in effect due to the preceding LWLockAcquire() will now be running without that. This could mean that ProcessInterrupts() gets called in places from which it didn't before. However, this seems unlikely to do very much, because the checkpointer doesn't have any signal mapped to die(), so it's not clear how, for example, ProcDiePending = true could happen in the first place. Similarly with ClientConnectionLost and recovery conflicts. Also, if there are any such problems, we might want to fix them rather than reverting this, since running lots of code with interrupt handling suspended is generally bad. Patch by me, per an inquiry by Amul Sul. Review by Tom Lane and Michael Paquier. Discussion: http://postgr.es/m/CAAJ_b97XnBBfYeSREDJorFsyoD1sHgqnNuCi=02mNQBUMnA=FA@mail.gmail.com --- doc/src/sgml/monitoring.sgml | 4 ---- src/backend/access/heap/rewriteheap.c | 4 ++-- src/backend/access/transam/xlog.c | 28 +----------------------- src/backend/replication/logical/origin.c | 4 ++-- src/backend/storage/lmgr/lwlocknames.txt | 2 +- 5 files changed, 6 insertions(+), 36 deletions(-) diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index f05140dd42400..9496f76b1fb0e 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -1880,10 +1880,6 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser Waiting to associate a data block with a buffer in the buffer pool. - - Checkpoint - Waiting to begin a checkpoint. - CheckpointerComm Waiting to manage fsync requests. diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c index 29ffe4067042c..fcaad9ba0b7f7 100644 --- a/src/backend/access/heap/rewriteheap.c +++ b/src/backend/access/heap/rewriteheap.c @@ -1256,8 +1256,8 @@ CheckPointLogicalRewriteHeap(void) /* * The file cannot vanish due to concurrency since this function - * is the only one removing logical mappings and it's run while - * CheckpointLock is held exclusively. + * is the only one removing logical mappings and only one + * checkpoint can be in progress at a time. */ if (fd < 0) ereport(ERROR, diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 470e113b33199..cc007b8963ef3 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -430,10 +430,6 @@ static XLogRecPtr RedoStartLSN = InvalidXLogRecPtr; * ControlFileLock: must be held to read/update control file or create * new log file. * - * CheckpointLock: must be held to do a checkpoint or restartpoint (ensures - * only one checkpointer at a time; currently, with all checkpoints done by - * the checkpointer, this is just pro forma). - * *---------- */ @@ -8864,14 +8860,6 @@ CreateCheckPoint(int flags) */ InitXLogInsert(); - /* - * Acquire CheckpointLock to ensure only one checkpoint happens at a time. - * (This is just pro forma, since in the present system structure there is - * only one process that is allowed to issue checkpoints at any given - * time.) - */ - LWLockAcquire(CheckpointLock, LW_EXCLUSIVE); - /* * Prepare to accumulate statistics. * @@ -8941,7 +8929,6 @@ CreateCheckPoint(int flags) if (last_important_lsn == ControlFile->checkPoint) { WALInsertLockRelease(); - LWLockRelease(CheckpointLock); END_CRIT_SECTION(); ereport(DEBUG1, (errmsg("checkpoint skipped because system is idle"))); @@ -9241,15 +9228,12 @@ CreateCheckPoint(int flags) CheckpointStats.ckpt_segs_added, CheckpointStats.ckpt_segs_removed, CheckpointStats.ckpt_segs_recycled); - - LWLockRelease(CheckpointLock); } /* * Mark the end of recovery in WAL though without running a full checkpoint. * We can expect that a restartpoint is likely to be in progress as we - * do this, though we are unwilling to wait for it to complete. So be - * careful to avoid taking the CheckpointLock anywhere here. + * do this, though we are unwilling to wait for it to complete. * * CreateRestartPoint() allows for the case where recovery may end before * the restartpoint completes so there is no concern of concurrent behaviour. @@ -9399,12 +9383,6 @@ CreateRestartPoint(int flags) XLogSegNo _logSegNo; TimestampTz xtime; - /* - * Acquire CheckpointLock to ensure only one restartpoint or checkpoint - * happens at a time. - */ - LWLockAcquire(CheckpointLock, LW_EXCLUSIVE); - /* Get a local copy of the last safe checkpoint record. */ SpinLockAcquire(&XLogCtl->info_lck); lastCheckPointRecPtr = XLogCtl->lastCheckPointRecPtr; @@ -9420,7 +9398,6 @@ CreateRestartPoint(int flags) { ereport(DEBUG2, (errmsg("skipping restartpoint, recovery has already ended"))); - LWLockRelease(CheckpointLock); return false; } @@ -9455,7 +9432,6 @@ CreateRestartPoint(int flags) UpdateControlFile(); LWLockRelease(ControlFileLock); } - LWLockRelease(CheckpointLock); return false; } @@ -9621,8 +9597,6 @@ CreateRestartPoint(int flags) xtime ? errdetail("Last completed transaction was at log time %s.", timestamptz_to_str(xtime)) : 0)); - LWLockRelease(CheckpointLock); - /* * Finally, execute archive_cleanup_command, if any. */ diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c index 77781d059ddde..9bd761a426223 100644 --- a/src/backend/replication/logical/origin.c +++ b/src/backend/replication/logical/origin.c @@ -559,8 +559,8 @@ CheckPointReplicationOrigin(void) tmppath))); /* - * no other backend can perform this at the same time, we're protected by - * CheckpointLock. + * no other backend can perform this at the same time; only one + * checkpoint can happen at a time. */ tmpfd = OpenTransientFile(tmppath, O_CREAT | O_EXCL | O_WRONLY | PG_BINARY); diff --git a/src/backend/storage/lmgr/lwlocknames.txt b/src/backend/storage/lmgr/lwlocknames.txt index 774292fd94277..6c7cf6c295661 100644 --- a/src/backend/storage/lmgr/lwlocknames.txt +++ b/src/backend/storage/lmgr/lwlocknames.txt @@ -15,7 +15,7 @@ SInvalWriteLock 6 WALBufMappingLock 7 WALWriteLock 8 ControlFileLock 9 -CheckpointLock 10 +# 10 was CheckpointLock XactSLRULock 11 SubtransSLRULock 12 MultiXactGenLock 13 From 07d46fceb4254b00e79f3d06419cbae13b0ecb5a Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 25 Jan 2021 13:03:11 -0500 Subject: [PATCH 174/240] Fix broken ruleutils support for function TRANSFORM clauses. I chanced to notice that this dumped core due to a faulty Assert. To add insult to injury, the output has been misformatted since v11. Obviously we need some regression testing here. Discussion: https://postgr.es/m/d1cc628c-3953-4209-957b-29427acc38c8@www.fastmail.com --- contrib/bool_plperl/expected/bool_plperl.out | 17 ++++++++++++++++- contrib/bool_plperl/expected/bool_plperlu.out | 17 ++++++++++++++++- contrib/bool_plperl/sql/bool_plperl.sql | 6 +++++- contrib/bool_plperl/sql/bool_plperlu.sql | 6 +++++- .../expected/hstore_plpython.out | 16 +++++++++++++--- contrib/hstore_plpython/sql/hstore_plpython.sql | 9 ++++++--- src/backend/utils/adt/ruleutils.c | 3 ++- src/backend/utils/fmgr/funcapi.c | 5 +++-- 8 files changed, 66 insertions(+), 13 deletions(-) diff --git a/contrib/bool_plperl/expected/bool_plperl.out b/contrib/bool_plperl/expected/bool_plperl.out index 84c25acdb4f83..187df8db96f9e 100644 --- a/contrib/bool_plperl/expected/bool_plperl.out +++ b/contrib/bool_plperl/expected/bool_plperl.out @@ -52,7 +52,7 @@ SELECT perl2undef() IS NULL AS p; --- test transforming to perl CREATE FUNCTION bool2perl(bool, bool, bool) RETURNS void LANGUAGE plperl -TRANSFORM FOR TYPE bool +TRANSFORM FOR TYPE bool, for type boolean -- duplicate to test ruleutils AS $$ my ($x, $y, $z) = @_; @@ -68,6 +68,21 @@ SELECT bool2perl (true, false, NULL); (1 row) +--- test ruleutils +\sf bool2perl +CREATE OR REPLACE FUNCTION public.bool2perl(boolean, boolean, boolean) + RETURNS void + TRANSFORM FOR TYPE boolean, FOR TYPE boolean + LANGUAGE plperl +AS $function$ +my ($x, $y, $z) = @_; + +die("NULL mistransformed") if (defined($z)); +die("TRUE mistransformed to UNDEF") if (!defined($x)); +die("FALSE mistransformed to UNDEF") if (!defined($y)); +die("TRUE mistransformed") if (!$x); +die("FALSE mistransformed") if ($y); +$function$ --- test selecting bool through SPI CREATE FUNCTION spi_test() RETURNS void LANGUAGE plperl diff --git a/contrib/bool_plperl/expected/bool_plperlu.out b/contrib/bool_plperl/expected/bool_plperlu.out index 745ba98933862..8337d337e992e 100644 --- a/contrib/bool_plperl/expected/bool_plperlu.out +++ b/contrib/bool_plperl/expected/bool_plperlu.out @@ -52,7 +52,7 @@ SELECT perl2undef() IS NULL AS p; --- test transforming to perl CREATE FUNCTION bool2perl(bool, bool, bool) RETURNS void LANGUAGE plperlu -TRANSFORM FOR TYPE bool +TRANSFORM FOR TYPE bool, for type boolean -- duplicate to test ruleutils AS $$ my ($x, $y, $z) = @_; @@ -68,6 +68,21 @@ SELECT bool2perl (true, false, NULL); (1 row) +--- test ruleutils +\sf bool2perl +CREATE OR REPLACE FUNCTION public.bool2perl(boolean, boolean, boolean) + RETURNS void + TRANSFORM FOR TYPE boolean, FOR TYPE boolean + LANGUAGE plperlu +AS $function$ +my ($x, $y, $z) = @_; + +die("NULL mistransformed") if (defined($z)); +die("TRUE mistransformed to UNDEF") if (!defined($x)); +die("FALSE mistransformed to UNDEF") if (!defined($y)); +die("TRUE mistransformed") if (!$x); +die("FALSE mistransformed") if ($y); +$function$ --- test selecting bool through SPI CREATE FUNCTION spi_test() RETURNS void LANGUAGE plperlu diff --git a/contrib/bool_plperl/sql/bool_plperl.sql b/contrib/bool_plperl/sql/bool_plperl.sql index dd99f545ea98e..b7f570862cee5 100644 --- a/contrib/bool_plperl/sql/bool_plperl.sql +++ b/contrib/bool_plperl/sql/bool_plperl.sql @@ -33,7 +33,7 @@ SELECT perl2undef() IS NULL AS p; CREATE FUNCTION bool2perl(bool, bool, bool) RETURNS void LANGUAGE plperl -TRANSFORM FOR TYPE bool +TRANSFORM FOR TYPE bool, for type boolean -- duplicate to test ruleutils AS $$ my ($x, $y, $z) = @_; @@ -46,6 +46,10 @@ $$; SELECT bool2perl (true, false, NULL); +--- test ruleutils + +\sf bool2perl + --- test selecting bool through SPI CREATE FUNCTION spi_test() RETURNS void diff --git a/contrib/bool_plperl/sql/bool_plperlu.sql b/contrib/bool_plperl/sql/bool_plperlu.sql index b756b0be67685..1480a0433067a 100644 --- a/contrib/bool_plperl/sql/bool_plperlu.sql +++ b/contrib/bool_plperl/sql/bool_plperlu.sql @@ -33,7 +33,7 @@ SELECT perl2undef() IS NULL AS p; CREATE FUNCTION bool2perl(bool, bool, bool) RETURNS void LANGUAGE plperlu -TRANSFORM FOR TYPE bool +TRANSFORM FOR TYPE bool, for type boolean -- duplicate to test ruleutils AS $$ my ($x, $y, $z) = @_; @@ -46,6 +46,10 @@ $$; SELECT bool2perl (true, false, NULL); +--- test ruleutils + +\sf bool2perl + --- test selecting bool through SPI CREATE FUNCTION spi_test() RETURNS void diff --git a/contrib/hstore_plpython/expected/hstore_plpython.out b/contrib/hstore_plpython/expected/hstore_plpython.out index 1ab5feea93d79..ecf1dd61bc17f 100644 --- a/contrib/hstore_plpython/expected/hstore_plpython.out +++ b/contrib/hstore_plpython/expected/hstore_plpython.out @@ -47,19 +47,29 @@ SELECT test1arr(array['aa=>bb, cc=>NULL'::hstore, 'dd=>ee']); (1 row) -- test python -> hstore -CREATE FUNCTION test2() RETURNS hstore +CREATE FUNCTION test2(a int, b text) RETURNS hstore LANGUAGE plpythonu TRANSFORM FOR TYPE hstore AS $$ -val = {'a': 1, 'b': 'boo', 'c': None} +val = {'a': a, 'b': b, 'c': None} return val $$; -SELECT test2(); +SELECT test2(1, 'boo'); test2 --------------------------------- "a"=>"1", "b"=>"boo", "c"=>NULL (1 row) +--- test ruleutils +\sf test2 +CREATE OR REPLACE FUNCTION public.test2(a integer, b text) + RETURNS hstore + TRANSFORM FOR TYPE hstore + LANGUAGE plpythonu +AS $function$ +val = {'a': a, 'b': b, 'c': None} +return val +$function$ -- test python -> hstore[] CREATE FUNCTION test2arr() RETURNS hstore[] LANGUAGE plpythonu diff --git a/contrib/hstore_plpython/sql/hstore_plpython.sql b/contrib/hstore_plpython/sql/hstore_plpython.sql index 2c54ee6aaad26..b6d98b7dd5371 100644 --- a/contrib/hstore_plpython/sql/hstore_plpython.sql +++ b/contrib/hstore_plpython/sql/hstore_plpython.sql @@ -40,15 +40,18 @@ SELECT test1arr(array['aa=>bb, cc=>NULL'::hstore, 'dd=>ee']); -- test python -> hstore -CREATE FUNCTION test2() RETURNS hstore +CREATE FUNCTION test2(a int, b text) RETURNS hstore LANGUAGE plpythonu TRANSFORM FOR TYPE hstore AS $$ -val = {'a': 1, 'b': 'boo', 'c': None} +val = {'a': a, 'b': b, 'c': None} return val $$; -SELECT test2(); +SELECT test2(1, 'boo'); + +--- test ruleutils +\sf test2 -- test python -> hstore[] diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 8a1fbda57227e..1a844bc4613f9 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -3126,13 +3126,14 @@ print_function_trftypes(StringInfo buf, HeapTuple proctup) { int i; - appendStringInfoString(buf, "\n TRANSFORM "); + appendStringInfoString(buf, " TRANSFORM "); for (i = 0; i < ntypes; i++) { if (i != 0) appendStringInfoString(buf, ", "); appendStringInfo(buf, "FOR TYPE %s", format_type_be(trftypes[i])); } + appendStringInfoChar(buf, '\n'); } } diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c index 2fd2e41f99b83..717b62907c78e 100644 --- a/src/backend/utils/fmgr/funcapi.c +++ b/src/backend/utils/fmgr/funcapi.c @@ -1357,7 +1357,9 @@ get_func_arg_info(HeapTuple procTup, /* * get_func_trftypes * - * Returns the number of transformed types used by function. + * Returns the number of transformed types used by the function. + * If there are any, a palloc'd array of the type OIDs is returned + * into *p_trftypes. */ int get_func_trftypes(HeapTuple procTup, @@ -1386,7 +1388,6 @@ get_func_trftypes(HeapTuple procTup, ARR_HASNULL(arr) || ARR_ELEMTYPE(arr) != OIDOID) elog(ERROR, "protrftypes is not a 1-D Oid array or it contains nulls"); - Assert(nelems >= ((Form_pg_proc) GETSTRUCT(procTup))->pronargs); *p_trftypes = (Oid *) palloc(nelems * sizeof(Oid)); memcpy(*p_trftypes, ARR_DATA_PTR(arr), nelems * sizeof(Oid)); From 881933f194221abcce07fb134ebe8685e5bb58dd Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 25 Jan 2021 14:53:13 -0500 Subject: [PATCH 175/240] Don't clobber the calling user's credentials cache in Kerberos test. Embarrassing oversight in this test script, which fortunately is not run by default. Report and patch by Jacob Champion. Discussion: https://postgr.es/m/1fcb175bafef6560f47a8c31229fa7c938486b8d.camel@vmware.com --- src/test/kerberos/t/001_auth.pl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/kerberos/t/001_auth.pl b/src/test/kerberos/t/001_auth.pl index 4b03ff561d53c..079321bbfc295 100644 --- a/src/test/kerberos/t/001_auth.pl +++ b/src/test/kerberos/t/001_auth.pl @@ -68,6 +68,7 @@ my $krb5_conf = "${TestLib::tmp_check}/krb5.conf"; my $kdc_conf = "${TestLib::tmp_check}/kdc.conf"; +my $krb5_cache = "${TestLib::tmp_check}/krb5cc"; my $krb5_log = "${TestLib::log_path}/krb5libs.log"; my $kdc_log = "${TestLib::log_path}/krb5kdc.log"; my $kdc_port = get_free_port(); @@ -139,8 +140,10 @@ mkdir $kdc_datadir or die; +# Ensure that we use test's config and cache files, not global ones. $ENV{'KRB5_CONFIG'} = $krb5_conf; $ENV{'KRB5_KDC_PROFILE'} = $kdc_conf; +$ENV{'KRB5CCNAME'} = $krb5_cache; my $service_principal = "$ENV{with_krb_srvnam}/$host"; From 55ef8555f0c1207bac25050e7297bbb969c84233 Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Mon, 25 Jan 2021 12:15:10 -0800 Subject: [PATCH 176/240] Fix two typos in snapbuild.c. Reported-by: Heikki Linnakangas Discussion: https://postgr.es/m/c94be044-818f-15e3-1ad3-7a7ae2dfed0a@iki.fi --- src/backend/replication/logical/snapbuild.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c index 71d510e305e14..e903e561afc42 100644 --- a/src/backend/replication/logical/snapbuild.c +++ b/src/backend/replication/logical/snapbuild.c @@ -1385,7 +1385,7 @@ SnapBuildFindSnapshot(SnapBuild *builder, XLogRecPtr lsn, xl_running_xacts *runn * a) allow isolationtester to notice that we're currently waiting for * something. * b) log a new xl_running_xacts record where it'd be helpful, without having - * to write for bgwriter or checkpointer. + * to wait for bgwriter or checkpointer. * --- */ static void @@ -1414,7 +1414,7 @@ SnapBuildWaitSnapshot(xl_running_xacts *running, TransactionId cutoff) /* * All transactions we needed to finish finished - try to ensure there is * another xl_running_xacts record in a timely manner, without having to - * write for bgwriter or checkpointer to log one. During recovery we + * wait for bgwriter or checkpointer to log one. During recovery we * can't enforce that, so we'll have to wait. */ if (!RecoveryInProgress()) From ee895a655ce4341546facd6f23e3e8f2931b96bf Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 25 Jan 2021 22:28:29 -0500 Subject: [PATCH 177/240] Improve performance of repeated CALLs within plpgsql procedures. This patch essentially is cleaning up technical debt left behind by the original implementation of plpgsql procedures, particularly commit d92bc83c4. That patch (or more precisely, follow-on patches fixing its worst bugs) forced us to re-plan CALL and DO statements each time through, if we're in a non-atomic context. That wasn't for any fundamental reason, but just because use of a saved plan requires having a ResourceOwner to hold a reference count for the plan, and we had no suitable resowner at hand, nor would the available APIs support using one if we did. While it's not that expensive to create a "plan" for CALL/DO, the cycles do add up in repeated executions. This patch therefore makes the following API changes: * GetCachedPlan/ReleaseCachedPlan are modified to let the caller specify which resowner to use to pin the plan, rather than forcing use of CurrentResourceOwner. * spi.c gains a "SPI_execute_plan_extended" entry point that lets callers say which resowner to use to pin the plan. This borrows the idea of an options struct from the recently added SPI_prepare_extended, hopefully allowing future options to be added without more API breaks. This supersedes SPI_execute_plan_with_paramlist (which I've marked deprecated) as well as SPI_execute_plan_with_receiver (which is new in v14, so I just took it out altogether). * I also took the opportunity to remove the crude hack of letting plpgsql reach into SPI private data structures to mark SPI plans as "no_snapshot". It's better to treat that as an option of SPI_prepare_extended. Now, when running a non-atomic procedure or DO block that contains any CALL or DO commands, plpgsql creates a ResourceOwner that will be used to pin the plans of the CALL/DO commands. (In an atomic context, we just use CurrentResourceOwner, as before.) Having done this, we can just save CALL/DO plans normally, whether or not they are used across transaction boundaries. This seems to be good for something like 2X speedup of a CALL of a trivial procedure with a few simple argument expressions. By restricting the creation of an extra ResourceOwner like this, there's essentially zero penalty in cases that can't benefit. Pavel Stehule, with some further hacking by me Discussion: https://postgr.es/m/CAFj8pRCLPdDAETvR7Po7gC5y_ibkn_-bOzbeJb39WHms01194Q@mail.gmail.com --- doc/src/sgml/spi.sgml | 165 ++++++---- src/backend/commands/prepare.c | 7 +- src/backend/executor/spi.c | 106 ++++--- src/backend/tcop/postgres.c | 2 +- src/backend/utils/cache/plancache.c | 32 +- src/backend/utils/mmgr/portalmem.c | 2 +- src/backend/utils/resowner/resowner.c | 8 +- src/include/executor/spi.h | 17 +- src/include/executor/spi_priv.h | 1 - src/include/utils/plancache.h | 4 +- src/pl/plpgsql/src/pl_comp.c | 2 + src/pl/plpgsql/src/pl_exec.c | 440 ++++++++++++-------------- src/pl/plpgsql/src/pl_gram.y | 6 + src/pl/plpgsql/src/pl_handler.c | 25 ++ src/pl/plpgsql/src/plpgsql.h | 11 +- 15 files changed, 461 insertions(+), 367 deletions(-) diff --git a/doc/src/sgml/spi.sgml b/doc/src/sgml/spi.sgml index f5e0a35da0645..d8c121f5f355f 100644 --- a/doc/src/sgml/spi.sgml +++ b/doc/src/sgml/spi.sgml @@ -1722,25 +1722,23 @@ int SPI_execute_plan(SPIPlanPtr plan, Datum * - - SPI_execute_plan_with_paramlist + + SPI_execute_plan_extended - SPI_execute_plan_with_paramlist + SPI_execute_plan_extended 3 - SPI_execute_plan_with_paramlist + SPI_execute_plan_extended execute a statement prepared by SPI_prepare -int SPI_execute_plan_with_paramlist(SPIPlanPtr plan, - ParamListInfo params, - bool read_only, - long count) +int SPI_execute_plan_extended(SPIPlanPtr plan, + const SPIExecuteOptions * options) @@ -1748,14 +1746,29 @@ int SPI_execute_plan_with_paramlist(SPIPlanPtr plan, Description - SPI_execute_plan_with_paramlist executes a statement - prepared by SPI_prepare. - This function is equivalent to SPI_execute_plan + SPI_execute_plan_extended executes a statement + prepared by SPI_prepare or one of its siblings. + This function is equivalent to SPI_execute_plan, except that information about the parameter values to be passed to the - query is presented differently. The ParamListInfo - representation can be convenient for passing down values that are - already available in that format. It also supports use of dynamic - parameter sets via hook functions specified in ParamListInfo. + query is presented differently, and additional execution-controlling + options can be passed. + + + + Query parameter values are represented by + a ParamListInfo struct, which is convenient for passing + down values that are already available in that format. Dynamic parameter + sets can also be used, via hook functions specified + in ParamListInfo. + + + + Also, instead of always accumulating the result tuples into a + SPI_tuptable structure, tuples can be passed to a + caller-supplied DestReceiver object as they are + generated by the executor. This is particularly helpful for queries + that might generate many tuples, since the data can be processed + on-the-fly instead of being accumulated in memory. @@ -1772,11 +1785,30 @@ int SPI_execute_plan_with_paramlist(SPIPlanPtr plan, + + const SPIExecuteOptions * options + + + struct containing optional arguments + + + + + + + Callers should always zero out the entire options + struct, then fill whichever fields they want to set. This ensures forward + compatibility of code, since any fields that are added to the struct in + future will be defined to behave backwards-compatibly if they are zero. + The currently available options fields are: + + + ParamListInfo params - data structure containing parameter types and values; NULL if none + data structure containing query parameter types and values; NULL if none @@ -1789,7 +1821,17 @@ int SPI_execute_plan_with_paramlist(SPIPlanPtr plan, - long count + bool no_snapshots + + + true prevents SPI from managing snapshots for + execution of the query; use with extreme caution + + + + + + uint64 tcount maximum number of rows to return, @@ -1797,6 +1839,29 @@ int SPI_execute_plan_with_paramlist(SPIPlanPtr plan, + + + DestReceiver * dest + + + DestReceiver object that will receive any tuples + emitted by the query; if NULL, result tuples are accumulated into + a SPI_tuptable structure, as + in SPI_execute_plan + + + + + + ResourceOwner owner + + + The resource owner that will hold a reference count on the plan while + it is executed. If NULL, CurrentResourceOwner is used. Ignored for + non-saved plans, as SPI does not acquire reference counts on those. + + + @@ -1808,35 +1873,40 @@ int SPI_execute_plan_with_paramlist(SPIPlanPtr plan, + When dest is NULL, SPI_processed and SPI_tuptable are set as in - SPI_execute_plan if successful. + SPI_execute_plan. + When dest is not NULL, + SPI_processed is set to zero and + SPI_tuptable is set to NULL. If a tuple count + is required, the caller's DestReceiver object must + calculate it. - - SPI_execute_plan_with_receiver + + SPI_execute_plan_with_paramlist - SPI_execute_plan_with_receiver + SPI_execute_plan_with_paramlist 3 - SPI_execute_plan_with_receiver + SPI_execute_plan_with_paramlist execute a statement prepared by SPI_prepare -int SPI_execute_plan_with_receiver(SPIPlanPtr plan, - ParamListInfo params, - bool read_only, - long count, - DestReceiver *dest) +int SPI_execute_plan_with_paramlist(SPIPlanPtr plan, + ParamListInfo params, + bool read_only, + long count) @@ -1844,15 +1914,19 @@ int SPI_execute_plan_with_receiver(SPIPlanPtr plan, Description - SPI_execute_plan_with_receiver executes a statement - prepared by SPI_prepare. This function is - equivalent to SPI_execute_plan_with_paramlist - except that, instead of always accumulating the result tuples into a - SPI_tuptable structure, tuples can be passed to a - caller-supplied DestReceiver object as they are - generated by the executor. This is particularly helpful for queries - that might generate many tuples, since the data can be processed - on-the-fly instead of being accumulated in memory. + SPI_execute_plan_with_paramlist executes a statement + prepared by SPI_prepare. + This function is equivalent to SPI_execute_plan + except that information about the parameter values to be passed to the + query is presented differently. The ParamListInfo + representation can be convenient for passing down values that are + already available in that format. It also supports use of dynamic + parameter sets via hook functions specified in ParamListInfo. + + + + This function is now deprecated in favor + of SPI_execute_plan_extended. @@ -1894,17 +1968,6 @@ int SPI_execute_plan_with_receiver(SPIPlanPtr plan, - - - DestReceiver * dest - - - DestReceiver object that will receive any tuples - emitted by the query; if NULL, this function is exactly equivalent to - SPI_execute_plan_with_paramlist - - - @@ -1916,15 +1979,9 @@ int SPI_execute_plan_with_receiver(SPIPlanPtr plan, - When dest is NULL, SPI_processed and SPI_tuptable are set as in - SPI_execute_plan. - When dest is not NULL, - SPI_processed is set to zero and - SPI_tuptable is set to NULL. If a tuple count - is required, the caller's DestReceiver object must - calculate it. + SPI_execute_plan if successful. diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c index 653ef8e41a69f..f767751c71ae3 100644 --- a/src/backend/commands/prepare.c +++ b/src/backend/commands/prepare.c @@ -230,7 +230,7 @@ ExecuteQuery(ParseState *pstate, entry->plansource->query_string); /* Replan if needed, and increment plan refcount for portal */ - cplan = GetCachedPlan(entry->plansource, paramLI, false, NULL); + cplan = GetCachedPlan(entry->plansource, paramLI, NULL, NULL); plan_list = cplan->stmt_list; /* @@ -651,7 +651,8 @@ ExplainExecuteQuery(ExecuteStmt *execstmt, IntoClause *into, ExplainState *es, } /* Replan if needed, and acquire a transient refcount */ - cplan = GetCachedPlan(entry->plansource, paramLI, true, queryEnv); + cplan = GetCachedPlan(entry->plansource, paramLI, + CurrentResourceOwner, queryEnv); INSTR_TIME_SET_CURRENT(planduration); INSTR_TIME_SUBTRACT(planduration, planstart); @@ -687,7 +688,7 @@ ExplainExecuteQuery(ExecuteStmt *execstmt, IntoClause *into, ExplainState *es, if (estate) FreeExecutorState(estate); - ReleaseCachedPlan(cplan, true); + ReleaseCachedPlan(cplan, CurrentResourceOwner); } /* diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index e28d2429222f0..68a6bcea02d59 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -66,8 +66,10 @@ static void _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan); static int _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, Snapshot snapshot, Snapshot crosscheck_snapshot, - bool read_only, bool fire_triggers, uint64 tcount, - DestReceiver *caller_dest); + bool read_only, bool no_snapshots, + bool fire_triggers, uint64 tcount, + DestReceiver *caller_dest, + ResourceOwner plan_owner); static ParamListInfo _SPI_convert_params(int nargs, Oid *argtypes, Datum *Values, const char *Nulls); @@ -521,7 +523,9 @@ SPI_execute(const char *src, bool read_only, long tcount) res = _SPI_execute_plan(&plan, NULL, InvalidSnapshot, InvalidSnapshot, - read_only, true, tcount, NULL); + read_only, false, + true, tcount, + NULL, NULL); _SPI_end_call(true); return res; @@ -555,7 +559,9 @@ SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls, _SPI_convert_params(plan->nargs, plan->argtypes, Values, Nulls), InvalidSnapshot, InvalidSnapshot, - read_only, true, tcount, NULL); + read_only, false, + true, tcount, + NULL, NULL); _SPI_end_call(true); return res; @@ -570,37 +576,32 @@ SPI_execp(SPIPlanPtr plan, Datum *Values, const char *Nulls, long tcount) /* Execute a previously prepared plan */ int -SPI_execute_plan_with_paramlist(SPIPlanPtr plan, ParamListInfo params, - bool read_only, long tcount) +SPI_execute_plan_extended(SPIPlanPtr plan, + const SPIExecuteOptions *options) { int res; - if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || tcount < 0) + if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || options == NULL) return SPI_ERROR_ARGUMENT; res = _SPI_begin_call(true); if (res < 0) return res; - res = _SPI_execute_plan(plan, params, + res = _SPI_execute_plan(plan, options->params, InvalidSnapshot, InvalidSnapshot, - read_only, true, tcount, NULL); + options->read_only, options->no_snapshots, + true, options->tcount, + options->dest, options->owner); _SPI_end_call(true); return res; } -/* - * Execute a previously prepared plan. If dest isn't NULL, we send result - * tuples to the caller-supplied DestReceiver rather than through the usual - * SPI output arrangements. If dest is NULL this is equivalent to - * SPI_execute_plan_with_paramlist. - */ +/* Execute a previously prepared plan */ int -SPI_execute_plan_with_receiver(SPIPlanPtr plan, - ParamListInfo params, - bool read_only, long tcount, - DestReceiver *dest) +SPI_execute_plan_with_paramlist(SPIPlanPtr plan, ParamListInfo params, + bool read_only, long tcount) { int res; @@ -613,7 +614,9 @@ SPI_execute_plan_with_receiver(SPIPlanPtr plan, res = _SPI_execute_plan(plan, params, InvalidSnapshot, InvalidSnapshot, - read_only, true, tcount, dest); + read_only, false, + true, tcount, + NULL, NULL); _SPI_end_call(true); return res; @@ -654,7 +657,9 @@ SPI_execute_snapshot(SPIPlanPtr plan, _SPI_convert_params(plan->nargs, plan->argtypes, Values, Nulls), snapshot, crosscheck_snapshot, - read_only, fire_triggers, tcount, NULL); + read_only, false, + fire_triggers, tcount, + NULL, NULL); _SPI_end_call(true); return res; @@ -702,7 +707,9 @@ SPI_execute_with_args(const char *src, res = _SPI_execute_plan(&plan, paramLI, InvalidSnapshot, InvalidSnapshot, - read_only, true, tcount, NULL); + read_only, false, + true, tcount, + NULL, NULL); _SPI_end_call(true); return res; @@ -746,7 +753,9 @@ SPI_execute_with_receiver(const char *src, res = _SPI_execute_plan(&plan, params, InvalidSnapshot, InvalidSnapshot, - read_only, true, tcount, dest); + read_only, false, + true, tcount, + dest, NULL); _SPI_end_call(true); return res; @@ -1554,7 +1563,7 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan, */ /* Replan if needed, and increment plan refcount for portal */ - cplan = GetCachedPlan(plansource, paramLI, false, _SPI_current->queryEnv); + cplan = GetCachedPlan(plansource, paramLI, NULL, _SPI_current->queryEnv); stmt_list = cplan->stmt_list; if (!plan->saved) @@ -1568,7 +1577,7 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan, oldcontext = MemoryContextSwitchTo(portal->portalContext); stmt_list = copyObject(stmt_list); MemoryContextSwitchTo(oldcontext); - ReleaseCachedPlan(cplan, false); + ReleaseCachedPlan(cplan, NULL); cplan = NULL; /* portal shouldn't depend on cplan */ } @@ -1950,7 +1959,10 @@ SPI_plan_get_plan_sources(SPIPlanPtr plan) /* * SPI_plan_get_cached_plan --- get a SPI plan's generic CachedPlan, * if the SPI plan contains exactly one CachedPlanSource. If not, - * return NULL. Caller is responsible for doing ReleaseCachedPlan(). + * return NULL. + * + * The plan's refcount is incremented (and logged in CurrentResourceOwner, + * if it's a saved plan). Caller is responsible for doing ReleaseCachedPlan. * * This is exported so that PL/pgSQL can use it (this beats letting PL/pgSQL * look directly into the SPIPlan for itself). It's not documented in @@ -1984,7 +1996,8 @@ SPI_plan_get_cached_plan(SPIPlanPtr plan) error_context_stack = &spierrcontext; /* Get the generic plan for the query */ - cplan = GetCachedPlan(plansource, NULL, plan->saved, + cplan = GetCachedPlan(plansource, NULL, + plan->saved ? CurrentResourceOwner : NULL, _SPI_current->queryEnv); Assert(cplan == plansource->gplan); @@ -2265,16 +2278,20 @@ _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan) * behavior of taking a new snapshot for each query. * crosscheck_snapshot: for RI use, all others pass InvalidSnapshot * read_only: true for read-only execution (no CommandCounterIncrement) + * no_snapshots: true to skip snapshot management * fire_triggers: true to fire AFTER triggers at end of query (normal case); * false means any AFTER triggers are postponed to end of outer query * tcount: execution tuple-count limit, or 0 for none * caller_dest: DestReceiver to receive output, or NULL for normal SPI output + * plan_owner: ResourceOwner that will be used to hold refcount on plan; + * if NULL, CurrentResourceOwner is used (ignored for non-saved plan) */ static int _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, Snapshot snapshot, Snapshot crosscheck_snapshot, - bool read_only, bool fire_triggers, uint64 tcount, - DestReceiver *caller_dest) + bool read_only, bool no_snapshots, + bool fire_triggers, uint64 tcount, + DestReceiver *caller_dest, ResourceOwner plan_owner) { int my_res = 0; uint64 my_processed = 0; @@ -2315,10 +2332,10 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, * In the first two cases, we can just push the snap onto the stack once * for the whole plan list. * - * But if the plan has no_snapshots set to true, then don't manage - * snapshots at all. The caller should then take care of that. + * But if no_snapshots is true, then don't manage snapshots at all here. + * The caller must then take care of that. */ - if (snapshot != InvalidSnapshot && !plan->no_snapshots) + if (snapshot != InvalidSnapshot && !no_snapshots) { if (read_only) { @@ -2333,6 +2350,15 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, } } + /* + * Ensure that we have a resource owner if plan is saved, and not if it + * isn't. + */ + if (!plan->saved) + plan_owner = NULL; + else if (plan_owner == NULL) + plan_owner = CurrentResourceOwner; + foreach(lc1, plan->plancache_list) { CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc1); @@ -2388,16 +2414,18 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, /* * Replan if needed, and increment plan refcount. If it's a saved - * plan, the refcount must be backed by the CurrentResourceOwner. + * plan, the refcount must be backed by the plan_owner. */ - cplan = GetCachedPlan(plansource, paramLI, plan->saved, _SPI_current->queryEnv); + cplan = GetCachedPlan(plansource, paramLI, + plan_owner, _SPI_current->queryEnv); + stmt_list = cplan->stmt_list; /* * In the default non-read-only case, get a new snapshot, replacing * any that we pushed in a previous cycle. */ - if (snapshot == InvalidSnapshot && !read_only && !plan->no_snapshots) + if (snapshot == InvalidSnapshot && !read_only && !no_snapshots) { if (pushed_active_snap) PopActiveSnapshot(); @@ -2450,7 +2478,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, * If not read-only mode, advance the command counter before each * command and update the snapshot. */ - if (!read_only && !plan->no_snapshots) + if (!read_only && !no_snapshots) { CommandCounterIncrement(); UpdateActiveSnapshotCommandId(); @@ -2499,7 +2527,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, * caller must be in a nonatomic SPI context and manage * snapshots itself. */ - if (_SPI_current->atomic || !plan->no_snapshots) + if (_SPI_current->atomic || !no_snapshots) context = PROCESS_UTILITY_QUERY; else context = PROCESS_UTILITY_QUERY_NONATOMIC; @@ -2586,7 +2614,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, } /* Done with this plan, so release refcount */ - ReleaseCachedPlan(cplan, plan->saved); + ReleaseCachedPlan(cplan, plan_owner); cplan = NULL; /* @@ -2606,7 +2634,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, /* We no longer need the cached plan refcount, if any */ if (cplan) - ReleaseCachedPlan(cplan, plan->saved); + ReleaseCachedPlan(cplan, plan_owner); /* * Pop the error context stack diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 8dab9fd578001..cb5a96117f6cd 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -1963,7 +1963,7 @@ exec_bind_message(StringInfo input_message) * will be generated in MessageContext. The plan refcount will be * assigned to the Portal, so it will be released at portal destruction. */ - cplan = GetCachedPlan(psrc, params, false, NULL); + cplan = GetCachedPlan(psrc, params, NULL, NULL); /* * Now we can define the portal. diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c index cc04b5b4bef90..1a0950489d741 100644 --- a/src/backend/utils/cache/plancache.c +++ b/src/backend/utils/cache/plancache.c @@ -533,7 +533,7 @@ ReleaseGenericPlan(CachedPlanSource *plansource) Assert(plan->magic == CACHEDPLAN_MAGIC); plansource->gplan = NULL; - ReleaseCachedPlan(plan, false); + ReleaseCachedPlan(plan, NULL); } } @@ -1130,16 +1130,16 @@ cached_plan_cost(CachedPlan *plan, bool include_planner) * execution. * * On return, the refcount of the plan has been incremented; a later - * ReleaseCachedPlan() call is expected. The refcount has been reported - * to the CurrentResourceOwner if useResOwner is true (note that that must - * only be true if it's a "saved" CachedPlanSource). + * ReleaseCachedPlan() call is expected. If "owner" is not NULL then + * the refcount has been reported to that ResourceOwner (note that this + * is only supported for "saved" CachedPlanSources). * * Note: if any replanning activity is required, the caller's memory context * is used for that work. */ CachedPlan * GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams, - bool useResOwner, QueryEnvironment *queryEnv) + ResourceOwner owner, QueryEnvironment *queryEnv) { CachedPlan *plan = NULL; List *qlist; @@ -1149,7 +1149,7 @@ GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams, Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC); Assert(plansource->is_complete); /* This seems worth a real test, though */ - if (useResOwner && !plansource->is_saved) + if (owner && !plansource->is_saved) elog(ERROR, "cannot apply ResourceOwner to non-saved cached plan"); /* Make sure the querytree list is valid and we have parse-time locks */ @@ -1228,11 +1228,11 @@ GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams, Assert(plan != NULL); /* Flag the plan as in use by caller */ - if (useResOwner) - ResourceOwnerEnlargePlanCacheRefs(CurrentResourceOwner); + if (owner) + ResourceOwnerEnlargePlanCacheRefs(owner); plan->refcount++; - if (useResOwner) - ResourceOwnerRememberPlanCacheRef(CurrentResourceOwner, plan); + if (owner) + ResourceOwnerRememberPlanCacheRef(owner, plan); /* * Saved plans should be under CacheMemoryContext so they will not go away @@ -1253,21 +1253,21 @@ GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams, * ReleaseCachedPlan: release active use of a cached plan. * * This decrements the reference count, and frees the plan if the count - * has thereby gone to zero. If useResOwner is true, it is assumed that - * the reference count is managed by the CurrentResourceOwner. + * has thereby gone to zero. If "owner" is not NULL, it is assumed that + * the reference count is managed by that ResourceOwner. * - * Note: useResOwner = false is used for releasing references that are in + * Note: owner == NULL is used for releasing references that are in * persistent data structures, such as the parent CachedPlanSource or a * Portal. Transient references should be protected by a resource owner. */ void -ReleaseCachedPlan(CachedPlan *plan, bool useResOwner) +ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner) { Assert(plan->magic == CACHEDPLAN_MAGIC); - if (useResOwner) + if (owner) { Assert(plan->is_saved); - ResourceOwnerForgetPlanCacheRef(CurrentResourceOwner, plan); + ResourceOwnerForgetPlanCacheRef(owner, plan); } Assert(plan->refcount > 0); plan->refcount--; diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c index 22c6d2ba5b2fe..66e3181815687 100644 --- a/src/backend/utils/mmgr/portalmem.c +++ b/src/backend/utils/mmgr/portalmem.c @@ -310,7 +310,7 @@ PortalReleaseCachedPlan(Portal portal) { if (portal->cplan) { - ReleaseCachedPlan(portal->cplan, false); + ReleaseCachedPlan(portal->cplan, NULL); portal->cplan = NULL; /* diff --git a/src/backend/utils/resowner/resowner.c b/src/backend/utils/resowner/resowner.c index 10f15f6a3579a..a171df573ceeb 100644 --- a/src/backend/utils/resowner/resowner.c +++ b/src/backend/utils/resowner/resowner.c @@ -652,7 +652,7 @@ ResourceOwnerReleaseInternal(ResourceOwner owner, if (isCommit) PrintPlanCacheLeakWarning(res); - ReleaseCachedPlan(res, true); + ReleaseCachedPlan(res, owner); } /* Ditto for tupdesc references */ @@ -703,18 +703,14 @@ ResourceOwnerReleaseInternal(ResourceOwner owner, void ResourceOwnerReleaseAllPlanCacheRefs(ResourceOwner owner) { - ResourceOwner save; Datum foundres; - save = CurrentResourceOwner; - CurrentResourceOwner = owner; while (ResourceArrayGetAny(&(owner->planrefarr), &foundres)) { CachedPlan *res = (CachedPlan *) DatumGetPointer(foundres); - ReleaseCachedPlan(res, true); + ReleaseCachedPlan(res, owner); } - CurrentResourceOwner = save; } /* diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h index 9c70603434a20..5740f8956e53a 100644 --- a/src/include/executor/spi.h +++ b/src/include/executor/spi.h @@ -42,6 +42,17 @@ typedef struct SPIPrepareOptions int cursorOptions; } SPIPrepareOptions; +/* Optional arguments for SPI_execute_plan_extended */ +typedef struct SPIExecuteOptions +{ + ParamListInfo params; + bool read_only; + bool no_snapshots; + uint64 tcount; + DestReceiver *dest; + ResourceOwner owner; +} SPIExecuteOptions; + /* Plans are opaque structs for standard users of SPI */ typedef struct _SPI_plan *SPIPlanPtr; @@ -96,13 +107,11 @@ extern int SPI_finish(void); extern int SPI_execute(const char *src, bool read_only, long tcount); extern int SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only, long tcount); +extern int SPI_execute_plan_extended(SPIPlanPtr plan, + const SPIExecuteOptions *options); extern int SPI_execute_plan_with_paramlist(SPIPlanPtr plan, ParamListInfo params, bool read_only, long tcount); -extern int SPI_execute_plan_with_receiver(SPIPlanPtr plan, - ParamListInfo params, - bool read_only, long tcount, - DestReceiver *dest); extern int SPI_exec(const char *src, long tcount); extern int SPI_execp(SPIPlanPtr plan, Datum *Values, const char *Nulls, long tcount); diff --git a/src/include/executor/spi_priv.h b/src/include/executor/spi_priv.h index ce0f58ce687b0..97f4279ac4ad9 100644 --- a/src/include/executor/spi_priv.h +++ b/src/include/executor/spi_priv.h @@ -92,7 +92,6 @@ typedef struct _SPI_plan int magic; /* should equal _SPI_PLAN_MAGIC */ bool saved; /* saved or unsaved plan? */ bool oneshot; /* one-shot plan? */ - bool no_snapshots; /* let the caller handle the snapshots */ List *plancache_list; /* one CachedPlanSource per parsetree */ MemoryContext plancxt; /* Context containing _SPI_plan and data */ RawParseMode parse_mode; /* raw_parser() mode */ diff --git a/src/include/utils/plancache.h b/src/include/utils/plancache.h index 79d96e5ed0332..ff09c63a02f14 100644 --- a/src/include/utils/plancache.h +++ b/src/include/utils/plancache.h @@ -219,9 +219,9 @@ extern List *CachedPlanGetTargetList(CachedPlanSource *plansource, extern CachedPlan *GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams, - bool useResOwner, + ResourceOwner owner, QueryEnvironment *queryEnv); -extern void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner); +extern void ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner); extern bool CachedPlanAllowsSimpleValidityCheck(CachedPlanSource *plansource, CachedPlan *plan, diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 5336793a9335e..ce8d97447d1d3 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -369,6 +369,7 @@ do_compile(FunctionCallInfo fcinfo, function->fn_prokind = procStruct->prokind; function->nstatements = 0; + function->requires_procedure_resowner = false; /* * Initialize the compiler, particularly the namespace stack. The @@ -903,6 +904,7 @@ plpgsql_compile_inline(char *proc_source) function->extra_errors = 0; function->nstatements = 0; + function->requires_procedure_resowner = false; plpgsql_ns_init(); plpgsql_ns_push(func_name, PLPGSQL_LABEL_BLOCK); diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 3a9349b724261..383d92fc1d054 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -26,7 +26,6 @@ #include "commands/defrem.h" #include "executor/execExpr.h" #include "executor/spi.h" -#include "executor/spi_priv.h" #include "executor/tstoreReceiver.h" #include "funcapi.h" #include "mb/stringinfo_mb.h" @@ -329,8 +328,7 @@ static void plpgsql_estate_setup(PLpgSQL_execstate *estate, static void exec_eval_cleanup(PLpgSQL_execstate *estate); static void exec_prepare_plan(PLpgSQL_execstate *estate, - PLpgSQL_expr *expr, int cursorOptions, - bool keepplan); + PLpgSQL_expr *expr, int cursorOptions); static void exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr); static void exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan); static void exec_check_rw_parameter(PLpgSQL_expr *expr); @@ -446,6 +444,8 @@ static char *format_expr_params(PLpgSQL_execstate *estate, const PLpgSQL_expr *expr); static char *format_preparedparamsdata(PLpgSQL_execstate *estate, ParamListInfo paramLI); +static PLpgSQL_variable *make_callstmt_target(PLpgSQL_execstate *estate, + PLpgSQL_expr *expr); /* ---------- @@ -460,12 +460,18 @@ static char *format_preparedparamsdata(PLpgSQL_execstate *estate, * shared_simple_eval_resowner. (When using a private simple_eval_estate, * we must also use a private cast hashtable, but that's taken care of * within plpgsql_estate_setup.) + * procedure_resowner is a resowner that will survive for the duration + * of execution of this function/procedure. It is needed only if we + * are doing non-atomic execution and there are CALL or DO statements + * in the function; otherwise it can be NULL. We use it to hold refcounts + * on the CALL/DO statements' plans. * ---------- */ Datum plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo, EState *simple_eval_estate, ResourceOwner simple_eval_resowner, + ResourceOwner procedure_resowner, bool atomic) { PLpgSQL_execstate estate; @@ -478,6 +484,7 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo, */ plpgsql_estate_setup(&estate, func, (ReturnSetInfo *) fcinfo->resultinfo, simple_eval_estate, simple_eval_resowner); + estate.procedure_resowner = procedure_resowner; estate.atomic = atomic; /* @@ -2150,233 +2157,65 @@ static int exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt) { PLpgSQL_expr *expr = stmt->expr; - SPIPlanPtr orig_plan = expr->plan; - bool local_plan; - PLpgSQL_variable *volatile cur_target = stmt->target; - volatile LocalTransactionId before_lxid; + LocalTransactionId before_lxid; LocalTransactionId after_lxid; - volatile bool pushed_active_snap = false; - volatile int rc; + bool pushed_active_snap = false; + ParamListInfo paramLI; + SPIExecuteOptions options; + int rc; /* - * If not in atomic context, we make a local plan that we'll just use for - * this invocation, and will free at the end. Otherwise, transaction ends - * would cause errors about plancache leaks. - * - * XXX This would be fixable with some plancache/resowner surgery - * elsewhere, but for now we'll just work around this here. + * Make a plan if we don't have one already. */ - local_plan = !estate->atomic; - - /* PG_TRY to ensure we clear the plan link, if needed, on failure */ - PG_TRY(); + if (expr->plan == NULL) { - SPIPlanPtr plan = expr->plan; - ParamListInfo paramLI; + exec_prepare_plan(estate, expr, 0); /* - * Make a plan if we don't have one, or if we need a local one. Note - * that we'll overwrite expr->plan either way; the PG_TRY block will - * ensure we undo that on the way out, if the plan is local. + * A CALL or DO can never be a simple expression. */ - if (plan == NULL || local_plan) - { - /* Don't let SPI save the plan if it's going to be local */ - exec_prepare_plan(estate, expr, 0, !local_plan); - plan = expr->plan; - - /* - * A CALL or DO can never be a simple expression. (If it could - * be, we'd have to worry about saving/restoring the previous - * values of the related expr fields, not just expr->plan.) - */ - Assert(!expr->expr_simple_expr); - - /* - * The procedure call could end transactions, which would upset - * the snapshot management in SPI_execute*, so don't let it do it. - * Instead, we set the snapshots ourselves below. - */ - plan->no_snapshots = true; - - /* - * Force target to be recalculated whenever the plan changes, in - * case the procedure's argument list has changed. - */ - stmt->target = NULL; - cur_target = NULL; - } + Assert(!expr->expr_simple_expr); /* - * We construct a DTYPE_ROW datum representing the plpgsql variables + * Also construct a DTYPE_ROW datum representing the plpgsql variables * associated with the procedure's output arguments. Then we can use * exec_move_row() to do the assignments. - * - * If we're using a local plan, also make a local target; otherwise, - * since the above code will force a new plan each time through, we'd - * repeatedly leak the memory for the target. (Note: we also leak the - * target when a plan change is forced, but that isn't so likely to - * cause excessive memory leaks.) */ - if (stmt->is_call && cur_target == NULL) - { - Node *node; - FuncExpr *funcexpr; - HeapTuple func_tuple; - List *funcargs; - Oid *argtypes; - char **argnames; - char *argmodes; - MemoryContext oldcontext; - PLpgSQL_row *row; - int nfields; - int i; - ListCell *lc; - - /* Use stmt_mcontext for any cruft accumulated here */ - oldcontext = MemoryContextSwitchTo(get_stmt_mcontext(estate)); - - /* - * Get the parsed CallStmt, and look up the called procedure - */ - node = linitial_node(Query, - ((CachedPlanSource *) linitial(plan->plancache_list))->query_list)->utilityStmt; - if (node == NULL || !IsA(node, CallStmt)) - elog(ERROR, "query for CALL statement is not a CallStmt"); - - funcexpr = ((CallStmt *) node)->funcexpr; - - func_tuple = SearchSysCache1(PROCOID, - ObjectIdGetDatum(funcexpr->funcid)); - if (!HeapTupleIsValid(func_tuple)) - elog(ERROR, "cache lookup failed for function %u", - funcexpr->funcid); - - /* - * Extract function arguments, and expand any named-arg notation - */ - funcargs = expand_function_arguments(funcexpr->args, - funcexpr->funcresulttype, - func_tuple); - - /* - * Get the argument names and modes, too - */ - get_func_arg_info(func_tuple, &argtypes, &argnames, &argmodes); - - ReleaseSysCache(func_tuple); - - /* - * Begin constructing row Datum; keep it in fn_cxt if it's to be - * long-lived. - */ - if (!local_plan) - MemoryContextSwitchTo(estate->func->fn_cxt); - - row = (PLpgSQL_row *) palloc0(sizeof(PLpgSQL_row)); - row->dtype = PLPGSQL_DTYPE_ROW; - row->refname = "(unnamed row)"; - row->lineno = -1; - row->varnos = (int *) palloc(sizeof(int) * list_length(funcargs)); - - if (!local_plan) - MemoryContextSwitchTo(get_stmt_mcontext(estate)); - - /* - * Examine procedure's argument list. Each output arg position - * should be an unadorned plpgsql variable (Datum), which we can - * insert into the row Datum. - */ - nfields = 0; - i = 0; - foreach(lc, funcargs) - { - Node *n = lfirst(lc); - - if (argmodes && - (argmodes[i] == PROARGMODE_INOUT || - argmodes[i] == PROARGMODE_OUT)) - { - if (IsA(n, Param)) - { - Param *param = (Param *) n; - - /* paramid is offset by 1 (see make_datum_param()) */ - row->varnos[nfields++] = param->paramid - 1; - } - else - { - /* report error using parameter name, if available */ - if (argnames && argnames[i] && argnames[i][0]) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("procedure parameter \"%s\" is an output parameter but corresponding argument is not writable", - argnames[i]))); - else - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("procedure parameter %d is an output parameter but corresponding argument is not writable", - i + 1))); - } - } - i++; - } - - row->nfields = nfields; - - cur_target = (PLpgSQL_variable *) row; - - /* We can save and re-use the target datum, if it's not local */ - if (!local_plan) - stmt->target = cur_target; - - MemoryContextSwitchTo(oldcontext); - } + if (stmt->is_call) + stmt->target = make_callstmt_target(estate, expr); + } - paramLI = setup_param_list(estate, expr); + paramLI = setup_param_list(estate, expr); - before_lxid = MyProc->lxid; + before_lxid = MyProc->lxid; - /* - * Set snapshot only for non-read-only procedures, similar to SPI - * behavior. - */ - if (!estate->readonly_func) - { - PushActiveSnapshot(GetTransactionSnapshot()); - pushed_active_snap = true; - } - - rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI, - estate->readonly_func, 0); - } - PG_CATCH(); + /* + * The procedure call could end transactions, which would upset the + * snapshot management in SPI_execute*, so handle snapshots here instead. + * Set a snapshot only for non-read-only procedures, similar to SPI + * behavior. + */ + if (!estate->readonly_func) { - /* - * If we are using a local plan, restore the old plan link. - */ - if (local_plan) - expr->plan = orig_plan; - PG_RE_THROW(); + PushActiveSnapshot(GetTransactionSnapshot()); + pushed_active_snap = true; } - PG_END_TRY(); /* - * If we are using a local plan, restore the old plan link; then free the - * local plan to avoid memory leaks. (Note that the error exit path above - * just clears the link without risking calling SPI_freeplan; we expect - * that xact cleanup will take care of the mess in that case.) + * If we have a procedure-lifespan resowner, use that to hold the refcount + * for the plan. This avoids refcount leakage complaints if the called + * procedure ends the current transaction. */ - if (local_plan) - { - SPIPlanPtr plan = expr->plan; + memset(&options, 0, sizeof(options)); + options.params = paramLI; + options.read_only = estate->readonly_func; + options.no_snapshots = true; /* disable SPI's snapshot management */ + options.owner = estate->procedure_resowner; - expr->plan = orig_plan; - SPI_freeplan(plan); - } + rc = SPI_execute_plan_extended(expr->plan, &options); if (rc < 0) - elog(ERROR, "SPI_execute_plan_with_paramlist failed executing query \"%s\": %s", + elog(ERROR, "SPI_execute_plan_extended failed executing query \"%s\": %s", expr->query, SPI_result_code_string(rc)); after_lxid = MyProc->lxid; @@ -2410,10 +2249,10 @@ exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt) { SPITupleTable *tuptab = SPI_tuptable; - if (!cur_target) + if (!stmt->is_call) elog(ERROR, "DO statement returned a row"); - exec_move_row(estate, cur_target, tuptab->vals[0], tuptab->tupdesc); + exec_move_row(estate, stmt->target, tuptab->vals[0], tuptab->tupdesc); } else if (SPI_processed > 1) elog(ERROR, "procedure call returned more than one row"); @@ -2424,6 +2263,128 @@ exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt) return PLPGSQL_RC_OK; } +/* + * We construct a DTYPE_ROW datum representing the plpgsql variables + * associated with the procedure's output arguments. Then we can use + * exec_move_row() to do the assignments. + */ +static PLpgSQL_variable * +make_callstmt_target(PLpgSQL_execstate *estate, PLpgSQL_expr *expr) +{ + List *plansources; + CachedPlanSource *plansource; + Node *node; + FuncExpr *funcexpr; + HeapTuple func_tuple; + List *funcargs; + Oid *argtypes; + char **argnames; + char *argmodes; + MemoryContext oldcontext; + PLpgSQL_row *row; + int nfields; + int i; + ListCell *lc; + + /* Use eval_mcontext for any cruft accumulated here */ + oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); + + /* + * Get the parsed CallStmt, and look up the called procedure + */ + plansources = SPI_plan_get_plan_sources(expr->plan); + if (list_length(plansources) != 1) + elog(ERROR, "query for CALL statement is not a CallStmt"); + plansource = (CachedPlanSource *) linitial(plansources); + if (list_length(plansource->query_list) != 1) + elog(ERROR, "query for CALL statement is not a CallStmt"); + node = linitial_node(Query, plansource->query_list)->utilityStmt; + if (node == NULL || !IsA(node, CallStmt)) + elog(ERROR, "query for CALL statement is not a CallStmt"); + + funcexpr = ((CallStmt *) node)->funcexpr; + + func_tuple = SearchSysCache1(PROCOID, + ObjectIdGetDatum(funcexpr->funcid)); + if (!HeapTupleIsValid(func_tuple)) + elog(ERROR, "cache lookup failed for function %u", + funcexpr->funcid); + + /* + * Extract function arguments, and expand any named-arg notation + */ + funcargs = expand_function_arguments(funcexpr->args, + funcexpr->funcresulttype, + func_tuple); + + /* + * Get the argument names and modes, too + */ + get_func_arg_info(func_tuple, &argtypes, &argnames, &argmodes); + + ReleaseSysCache(func_tuple); + + /* + * Begin constructing row Datum; keep it in fn_cxt so it's adequately + * long-lived. + */ + MemoryContextSwitchTo(estate->func->fn_cxt); + + row = (PLpgSQL_row *) palloc0(sizeof(PLpgSQL_row)); + row->dtype = PLPGSQL_DTYPE_ROW; + row->refname = "(unnamed row)"; + row->lineno = -1; + row->varnos = (int *) palloc(sizeof(int) * list_length(funcargs)); + + MemoryContextSwitchTo(get_eval_mcontext(estate)); + + /* + * Examine procedure's argument list. Each output arg position should be + * an unadorned plpgsql variable (Datum), which we can insert into the row + * Datum. + */ + nfields = 0; + i = 0; + foreach(lc, funcargs) + { + Node *n = lfirst(lc); + + if (argmodes && + (argmodes[i] == PROARGMODE_INOUT || + argmodes[i] == PROARGMODE_OUT)) + { + if (IsA(n, Param)) + { + Param *param = (Param *) n; + + /* paramid is offset by 1 (see make_datum_param()) */ + row->varnos[nfields++] = param->paramid - 1; + } + else + { + /* report error using parameter name, if available */ + if (argnames && argnames[i] && argnames[i][0]) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("procedure parameter \"%s\" is an output parameter but corresponding argument is not writable", + argnames[i]))); + else + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("procedure parameter %d is an output parameter but corresponding argument is not writable", + i + 1))); + } + } + i++; + } + + row->nfields = nfields; + + MemoryContextSwitchTo(oldcontext); + + return (PLpgSQL_variable *) row; +} + /* ---------- * exec_stmt_getdiag Put internal PG information into * specified variables. @@ -2960,7 +2921,7 @@ exec_stmt_forc(PLpgSQL_execstate *estate, PLpgSQL_stmt_forc *stmt) Assert(query); if (query->plan == NULL) - exec_prepare_plan(estate, query, curvar->cursor_options, true); + exec_prepare_plan(estate, query, curvar->cursor_options); /* * Set up ParamListInfo for this query @@ -3607,12 +3568,13 @@ exec_stmt_return_query(PLpgSQL_execstate *estate, /* static query */ PLpgSQL_expr *expr = stmt->query; ParamListInfo paramLI; + SPIExecuteOptions options; /* * On the first call for this expression generate the plan. */ if (expr->plan == NULL) - exec_prepare_plan(estate, expr, CURSOR_OPT_PARALLEL_OK, true); + exec_prepare_plan(estate, expr, CURSOR_OPT_PARALLEL_OK); /* * Set up ParamListInfo to pass to executor @@ -3622,9 +3584,12 @@ exec_stmt_return_query(PLpgSQL_execstate *estate, /* * Execute the query */ - rc = SPI_execute_plan_with_receiver(expr->plan, paramLI, - estate->readonly_func, 0, - treceiver); + memset(&options, 0, sizeof(options)); + options.params = paramLI; + options.read_only = estate->readonly_func; + options.dest = treceiver; + + rc = SPI_execute_plan_extended(expr->plan, &options); if (rc != SPI_OK_SELECT) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), @@ -4091,6 +4056,9 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate, else estate->simple_eval_resowner = shared_simple_eval_resowner; + /* if there's a procedure resowner, it'll be filled in later */ + estate->procedure_resowner = NULL; + /* * We start with no stmt_mcontext; one will be created only if needed. * That context will be a direct child of the function's main execution @@ -4159,8 +4127,7 @@ exec_eval_cleanup(PLpgSQL_execstate *estate) */ static void exec_prepare_plan(PLpgSQL_execstate *estate, - PLpgSQL_expr *expr, int cursorOptions, - bool keepplan) + PLpgSQL_expr *expr, int cursorOptions) { SPIPlanPtr plan; SPIPrepareOptions options; @@ -4183,8 +4150,8 @@ exec_prepare_plan(PLpgSQL_execstate *estate, if (plan == NULL) elog(ERROR, "SPI_prepare_extended failed for \"%s\": %s", expr->query, SPI_result_code_string(SPI_result)); - if (keepplan) - SPI_keepplan(plan); + + SPI_keepplan(plan); expr->plan = plan; /* Check to see if it's a simple expression */ @@ -4222,7 +4189,7 @@ exec_stmt_execsql(PLpgSQL_execstate *estate, { ListCell *l; - exec_prepare_plan(estate, expr, CURSOR_OPT_PARALLEL_OK, true); + exec_prepare_plan(estate, expr, CURSOR_OPT_PARALLEL_OK); stmt->mod_stmt = false; foreach(l, SPI_plan_get_plan_sources(expr->plan)) { @@ -4681,7 +4648,7 @@ exec_stmt_open(PLpgSQL_execstate *estate, PLpgSQL_stmt_open *stmt) */ query = stmt->query; if (query->plan == NULL) - exec_prepare_plan(estate, query, stmt->cursor_options, true); + exec_prepare_plan(estate, query, stmt->cursor_options); } else if (stmt->dynquery != NULL) { @@ -4752,7 +4719,7 @@ exec_stmt_open(PLpgSQL_execstate *estate, PLpgSQL_stmt_open *stmt) query = curvar->cursor_explicit_expr; if (query->plan == NULL) - exec_prepare_plan(estate, query, curvar->cursor_options, true); + exec_prepare_plan(estate, query, curvar->cursor_options); } /* @@ -4985,18 +4952,20 @@ static int exec_stmt_set(PLpgSQL_execstate *estate, PLpgSQL_stmt_set *stmt) { PLpgSQL_expr *expr = stmt->expr; + SPIExecuteOptions options; int rc; if (expr->plan == NULL) - { - exec_prepare_plan(estate, expr, 0, true); - expr->plan->no_snapshots = true; - } + exec_prepare_plan(estate, expr, 0); + + memset(&options, 0, sizeof(options)); + options.read_only = estate->readonly_func; + options.no_snapshots = true; /* disable SPI's snapshot management */ - rc = SPI_execute_plan(expr->plan, NULL, NULL, estate->readonly_func, 0); + rc = SPI_execute_plan_extended(expr->plan, &options); if (rc != SPI_OK_UTILITY) - elog(ERROR, "SPI_execute_plan failed executing query \"%s\": %s", + elog(ERROR, "SPI_execute_plan_extended failed executing query \"%s\": %s", expr->query, SPI_result_code_string(rc)); return PLPGSQL_RC_OK; @@ -5032,7 +5001,7 @@ exec_assign_expr(PLpgSQL_execstate *estate, PLpgSQL_datum *target, else expr->target_param = -1; /* should be that already */ - exec_prepare_plan(estate, expr, 0, true); + exec_prepare_plan(estate, expr, 0); } value = exec_eval_expr(estate, expr, &isnull, &valtype, &valtypmod); @@ -5697,7 +5666,7 @@ exec_eval_expr(PLpgSQL_execstate *estate, * If first time through, create a plan for this expression. */ if (expr->plan == NULL) - exec_prepare_plan(estate, expr, CURSOR_OPT_PARALLEL_OK, true); + exec_prepare_plan(estate, expr, CURSOR_OPT_PARALLEL_OK); /* * If this is a simple expression, bypass SPI and use the executor @@ -5783,7 +5752,7 @@ exec_run_select(PLpgSQL_execstate *estate, */ if (expr->plan == NULL) exec_prepare_plan(estate, expr, - portalP == NULL ? CURSOR_OPT_PARALLEL_OK : 0, true); + portalP == NULL ? CURSOR_OPT_PARALLEL_OK : 0); /* * Set up ParamListInfo to pass to executor @@ -6056,11 +6025,8 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate, */ if (expr->expr_simple_plan_lxid == curlxid) { - ResourceOwner saveResourceOwner = CurrentResourceOwner; - - CurrentResourceOwner = estate->simple_eval_resowner; - ReleaseCachedPlan(expr->expr_simple_plan, true); - CurrentResourceOwner = saveResourceOwner; + ReleaseCachedPlan(expr->expr_simple_plan, + estate->simple_eval_resowner); expr->expr_simple_plan = NULL; expr->expr_simple_plan_lxid = InvalidLocalTransactionId; } @@ -6094,7 +6060,7 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate, else { /* Release SPI_plan_get_cached_plan's refcount */ - ReleaseCachedPlan(cplan, true); + ReleaseCachedPlan(cplan, CurrentResourceOwner); /* Mark expression as non-simple, and fail */ expr->expr_simple_expr = NULL; expr->expr_rw_param = NULL; @@ -6105,7 +6071,7 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate, * SPI_plan_get_cached_plan acquired a plan refcount stored in the * active resowner. We don't need that anymore, so release it. */ - ReleaseCachedPlan(cplan, true); + ReleaseCachedPlan(cplan, CurrentResourceOwner); /* Extract desired scalar expression from cached plan */ exec_save_simple_expr(expr, cplan); @@ -8023,7 +7989,7 @@ exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr) * Release the plan refcount obtained by SPI_plan_get_cached_plan. (This * refcount is held by the wrong resowner, so we can't just repurpose it.) */ - ReleaseCachedPlan(cplan, true); + ReleaseCachedPlan(cplan, CurrentResourceOwner); } /* diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y index 0b0ff4e5de28d..abf196d4be149 100644 --- a/src/pl/plpgsql/src/pl_gram.y +++ b/src/pl/plpgsql/src/pl_gram.y @@ -951,6 +951,9 @@ stmt_call : K_CALL new->expr = read_sql_stmt(); new->is_call = true; + /* Remember we may need a procedure resource owner */ + plpgsql_curr_compile->requires_procedure_resowner = true; + $$ = (PLpgSQL_stmt *)new; } @@ -967,6 +970,9 @@ stmt_call : K_CALL new->expr = read_sql_stmt(); new->is_call = false; + /* Remember we may need a procedure resource owner */ + plpgsql_curr_compile->requires_procedure_resowner = true; + $$ = (PLpgSQL_stmt *)new; } diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c index 52e6c69cc5599..97f4264c28726 100644 --- a/src/pl/plpgsql/src/pl_handler.c +++ b/src/pl/plpgsql/src/pl_handler.c @@ -224,6 +224,7 @@ plpgsql_call_handler(PG_FUNCTION_ARGS) bool nonatomic; PLpgSQL_function *func; PLpgSQL_execstate *save_cur_estate; + ResourceOwner procedure_resowner = NULL; Datum retval; int rc; @@ -246,6 +247,17 @@ plpgsql_call_handler(PG_FUNCTION_ARGS) /* Mark the function as busy, so it can't be deleted from under us */ func->use_count++; + /* + * If we'll need a procedure-lifespan resowner to execute any CALL or DO + * statements, create it now. Since this resowner is not tied to any + * parent, failing to free it would result in process-lifespan leaks. + * Therefore, be very wary of adding any code between here and the PG_TRY + * block. + */ + if (nonatomic && func->requires_procedure_resowner) + procedure_resowner = + ResourceOwnerCreate(NULL, "PL/pgSQL procedure resources"); + PG_TRY(); { /* @@ -264,6 +276,7 @@ plpgsql_call_handler(PG_FUNCTION_ARGS) else retval = plpgsql_exec_function(func, fcinfo, NULL, NULL, + procedure_resowner, !nonatomic); } PG_FINALLY(); @@ -271,6 +284,13 @@ plpgsql_call_handler(PG_FUNCTION_ARGS) /* Decrement use-count, restore cur_estate */ func->use_count--; func->cur_estate = save_cur_estate; + + /* Be sure to release the procedure resowner if any */ + if (procedure_resowner) + { + ResourceOwnerReleaseAllPlanCacheRefs(procedure_resowner); + ResourceOwnerDelete(procedure_resowner); + } } PG_END_TRY(); @@ -333,6 +353,10 @@ plpgsql_inline_handler(PG_FUNCTION_ARGS) * unconditionally try to clean them up below. (Hence, be wary of adding * anything that could fail between here and the PG_TRY block.) See the * comments for shared_simple_eval_estate. + * + * Because this resowner isn't tied to the calling transaction, we can + * also use it as the "procedure" resowner for any CALL statements. That + * helps reduce the opportunities for failure here. */ simple_eval_estate = CreateExecutorState(); simple_eval_resowner = @@ -344,6 +368,7 @@ plpgsql_inline_handler(PG_FUNCTION_ARGS) retval = plpgsql_exec_function(func, fake_fcinfo, simple_eval_estate, simple_eval_resowner, + simple_eval_resowner, /* see above */ codeblock->atomic); } PG_CATCH(); diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index 416fda7f3b5c6..d5010862a5035 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -1009,9 +1009,6 @@ typedef struct PLpgSQL_function int extra_warnings; int extra_errors; - /* count of statements inside function */ - unsigned int nstatements; - /* the datums representing the function's local variables */ int ndatums; PLpgSQL_datum **datums; @@ -1020,6 +1017,10 @@ typedef struct PLpgSQL_function /* function body parsetree */ PLpgSQL_stmt_block *action; + /* data derived while parsing body */ + unsigned int nstatements; /* counter for assigning stmtids */ + bool requires_procedure_resowner; /* contains CALL or DO? */ + /* these fields change when the function is used */ struct PLpgSQL_execstate *cur_estate; unsigned long use_count; @@ -1081,6 +1082,9 @@ typedef struct PLpgSQL_execstate EState *simple_eval_estate; ResourceOwner simple_eval_resowner; + /* if running nonatomic procedure or DO block, resowner to use for CALL */ + ResourceOwner procedure_resowner; + /* lookup table to use for executing type casts */ HTAB *cast_hash; MemoryContext cast_hash_context; @@ -1265,6 +1269,7 @@ extern Datum plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo, EState *simple_eval_estate, ResourceOwner simple_eval_resowner, + ResourceOwner procedure_resowner, bool atomic); extern HeapTuple plpgsql_exec_trigger(PLpgSQL_function *func, TriggerData *trigdata); From 411ae64997dc3a42d19eda6721c581841ce2cb82 Mon Sep 17 00:00:00 2001 From: Fujii Masao Date: Tue, 26 Jan 2021 03:54:46 +0900 Subject: [PATCH 178/240] postgres_fdw: Add functions to discard cached connections. This commit introduces two new functions postgres_fdw_disconnect() and postgres_fdw_disconnect_all(). The former function discards the cached connections to the specified foreign server. The latter discards all the cached connections. If the connection is used in the current transaction, it's not closed and a warning message is emitted. For example, these functions are useful when users want to explicitly close the foreign server connections that are no longer necessary and then to prevent them from eating up the foreign servers connections capacity. Author: Bharath Rupireddy, tweaked a bit by Fujii Masao Reviewed-by: Alexey Kondratov, Zhijie Hou, Zhihong Yu, Fujii Masao Discussion: https://postgr.es/m/CALj2ACVvrp5=AVp2PupEm+nAC8S4buqR3fJMmaCoc7ftT0aD2A@mail.gmail.com --- contrib/postgres_fdw/connection.c | 135 +++++++++++- .../postgres_fdw/expected/postgres_fdw.out | 208 +++++++++++++++++- .../postgres_fdw/postgres_fdw--1.0--1.1.sql | 10 + contrib/postgres_fdw/sql/postgres_fdw.sql | 98 ++++++++- doc/src/sgml/postgres-fdw.sgml | 67 +++++- 5 files changed, 505 insertions(+), 13 deletions(-) diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c index a1404cb6bb1d4..ee0b4acf0bad6 100644 --- a/contrib/postgres_fdw/connection.c +++ b/contrib/postgres_fdw/connection.c @@ -80,6 +80,8 @@ static bool xact_got_connection = false; * SQL functions */ PG_FUNCTION_INFO_V1(postgres_fdw_get_connections); +PG_FUNCTION_INFO_V1(postgres_fdw_disconnect); +PG_FUNCTION_INFO_V1(postgres_fdw_disconnect_all); /* prototypes of private functions */ static void make_new_connection(ConnCacheEntry *entry, UserMapping *user); @@ -102,6 +104,7 @@ static bool pgfdw_exec_cleanup_query(PGconn *conn, const char *query, static bool pgfdw_get_cleanup_result(PGconn *conn, TimestampTz endtime, PGresult **result); static bool UserMappingPasswordRequired(UserMapping *user); +static bool disconnect_cached_connections(Oid serverid); /* * Get a PGconn which can be used to execute queries on the remote PostgreSQL @@ -1428,8 +1431,8 @@ postgres_fdw_get_connections(PG_FUNCTION_ARGS) * Even though the server is dropped in the current transaction, the * cache can still have associated active connection entry, say we * call such connections dangling. Since we can not fetch the server - * name from system catalogs for dangling connections, instead we - * show NULL value for server name in output. + * name from system catalogs for dangling connections, instead we show + * NULL value for server name in output. * * We could have done better by storing the server name in the cache * entry instead of server oid so that it could be used in the output. @@ -1447,7 +1450,7 @@ postgres_fdw_get_connections(PG_FUNCTION_ARGS) /* * If the server has been dropped in the current explicit * transaction, then this entry would have been invalidated in - * pgfdw_inval_callback at the end of drop sever command. Note + * pgfdw_inval_callback at the end of drop server command. Note * that this connection would not have been closed in * pgfdw_inval_callback because it is still being used in the * current explicit transaction. So, assert that here. @@ -1470,3 +1473,129 @@ postgres_fdw_get_connections(PG_FUNCTION_ARGS) PG_RETURN_VOID(); } + +/* + * Disconnect the specified cached connections. + * + * This function discards the open connections that are established by + * postgres_fdw from the local session to the foreign server with + * the given name. Note that there can be multiple connections to + * the given server using different user mappings. If the connections + * are used in the current local transaction, they are not disconnected + * and warning messages are reported. This function returns true + * if it disconnects at least one connection, otherwise false. If no + * foreign server with the given name is found, an error is reported. + */ +Datum +postgres_fdw_disconnect(PG_FUNCTION_ARGS) +{ + ForeignServer *server; + char *servername; + + servername = text_to_cstring(PG_GETARG_TEXT_PP(0)); + server = GetForeignServerByName(servername, false); + + PG_RETURN_BOOL(disconnect_cached_connections(server->serverid)); +} + +/* + * Disconnect all the cached connections. + * + * This function discards all the open connections that are established by + * postgres_fdw from the local session to the foreign servers. + * If the connections are used in the current local transaction, they are + * not disconnected and warning messages are reported. This function + * returns true if it disconnects at least one connection, otherwise false. + */ +Datum +postgres_fdw_disconnect_all(PG_FUNCTION_ARGS) +{ + PG_RETURN_BOOL(disconnect_cached_connections(InvalidOid)); +} + +/* + * Workhorse to disconnect cached connections. + * + * This function scans all the connection cache entries and disconnects + * the open connections whose foreign server OID matches with + * the specified one. If InvalidOid is specified, it disconnects all + * the cached connections. + * + * This function emits a warning for each connection that's used in + * the current transaction and doesn't close it. It returns true if + * it disconnects at least one connection, otherwise false. + * + * Note that this function disconnects even the connections that are + * established by other users in the same local session using different + * user mappings. This leads even non-superuser to be able to close + * the connections established by superusers in the same local session. + * + * XXX As of now we don't see any security risk doing this. But we should + * set some restrictions on that, for example, prevent non-superuser + * from closing the connections established by superusers even + * in the same session? + */ +static bool +disconnect_cached_connections(Oid serverid) +{ + HASH_SEQ_STATUS scan; + ConnCacheEntry *entry; + bool all = !OidIsValid(serverid); + bool result = false; + + /* + * Connection cache hashtable has not been initialized yet in this + * session, so return false. + */ + if (!ConnectionHash) + return false; + + hash_seq_init(&scan, ConnectionHash); + while ((entry = (ConnCacheEntry *) hash_seq_search(&scan))) + { + /* Ignore cache entry if no open connection right now. */ + if (!entry->conn) + continue; + + if (all || entry->serverid == serverid) + { + /* + * Emit a warning because the connection to close is used in the + * current transaction and cannot be disconnected right now. + */ + if (entry->xact_depth > 0) + { + ForeignServer *server; + + server = GetForeignServerExtended(entry->serverid, + FSV_MISSING_OK); + + if (!server) + { + /* + * If the foreign server was dropped while its connection + * was used in the current transaction, the connection + * must have been marked as invalid by + * pgfdw_inval_callback at the end of DROP SERVER command. + */ + Assert(entry->invalidated); + + ereport(WARNING, + (errmsg("cannot close dropped server connection because it is still in use"))); + } + else + ereport(WARNING, + (errmsg("cannot close connection for server \"%s\" because it is still in use", + server->servername))); + } + else + { + elog(DEBUG3, "discarding connection %p", entry->conn); + disconnect_pg_server(entry); + result = true; + } + } + } + + return result; +} diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index b4a04d2c1432d..e33c92d7f1c2b 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -17,7 +17,10 @@ DO $d$ OPTIONS (dbname '$$||current_database()||$$', port '$$||current_setting('port')||$$' )$$; - + EXECUTE $$CREATE SERVER loopback4 FOREIGN DATA WRAPPER postgres_fdw + OPTIONS (dbname '$$||current_database()||$$', + port '$$||current_setting('port')||$$' + )$$; END; $d$; CREATE USER MAPPING FOR public SERVER testserver1 @@ -25,6 +28,7 @@ CREATE USER MAPPING FOR public SERVER testserver1 CREATE USER MAPPING FOR CURRENT_USER SERVER loopback; CREATE USER MAPPING FOR CURRENT_USER SERVER loopback2; CREATE USER MAPPING FOR public SERVER loopback3; +CREATE USER MAPPING FOR public SERVER loopback4; -- =================================================================== -- create objects used through FDW loopback server -- =================================================================== @@ -140,6 +144,11 @@ CREATE FOREIGN TABLE ft7 ( c2 int NOT NULL, c3 text ) SERVER loopback3 OPTIONS (schema_name 'S 1', table_name 'T 4'); +CREATE FOREIGN TABLE ft8 ( + c1 int NOT NULL, + c2 int NOT NULL, + c3 text +) SERVER loopback4 OPTIONS (schema_name 'S 1', table_name 'T 4'); -- =================================================================== -- tests for validator -- =================================================================== @@ -211,7 +220,8 @@ ALTER FOREIGN TABLE ft2 ALTER COLUMN c1 OPTIONS (column_name 'C 1'); public | ft5 | loopback | (schema_name 'S 1', table_name 'T 4') | public | ft6 | loopback2 | (schema_name 'S 1', table_name 'T 4') | public | ft7 | loopback3 | (schema_name 'S 1', table_name 'T 4') | -(6 rows) + public | ft8 | loopback4 | (schema_name 'S 1', table_name 'T 4') | +(7 rows) -- Test that alteration of server options causes reconnection -- Remote's errors might be non-English, so hide them to ensure stable results @@ -9053,9 +9063,9 @@ ERROR: 08006 COMMIT; -- Clean up DROP PROCEDURE terminate_backend_and_wait(text); --- =================================================================== --- test connection invalidation cases --- =================================================================== +-- ============================================================================= +-- test connection invalidation cases and postgres_fdw_get_connections function +-- ============================================================================= -- This test case is for closing the connection in pgfdw_xact_callback BEGIN; -- List all the existing cached connections. Only loopback2 should be output. @@ -9118,6 +9128,194 @@ SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; loopback2 | t (1 row) +-- ======================================================================= +-- test postgres_fdw_disconnect and postgres_fdw_disconnect_all functions +-- ======================================================================= +-- Return true as all cached connections are closed. +SELECT postgres_fdw_disconnect_all(); + postgres_fdw_disconnect_all +----------------------------- + t +(1 row) + +-- Ensure to cache loopback connection. +SELECT 1 FROM ft1 LIMIT 1; + ?column? +---------- + 1 +(1 row) + +BEGIN; +-- Ensure to cache loopback2 connection. +SELECT 1 FROM ft6 LIMIT 1; + ?column? +---------- + 1 +(1 row) + +-- List all the existing cached connections. loopback and loopback2 should be +-- output. +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; + server_name | valid +-------------+------- + loopback | t + loopback2 | t +(2 rows) + +-- Issue a warning and return false as loopback2 connection is still in use and +-- can not be closed. +SELECT postgres_fdw_disconnect('loopback2'); +WARNING: cannot close connection for server "loopback2" because it is still in use + postgres_fdw_disconnect +------------------------- + f +(1 row) + +-- Close loopback connection, return true and issue a warning as loopback2 +-- connection is still in use and can not be closed. +SELECT postgres_fdw_disconnect_all(); +WARNING: cannot close connection for server "loopback2" because it is still in use + postgres_fdw_disconnect_all +----------------------------- + t +(1 row) + +-- List all the existing cached connections. loopback2 should be output. +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; + server_name | valid +-------------+------- + loopback2 | t +(1 row) + +-- Ensure to cache loopback connection. +SELECT 1 FROM ft1 LIMIT 1; + ?column? +---------- + 1 +(1 row) + +-- Ensure to cache loopback4 connection. +SELECT 1 FROM ft8 LIMIT 1; + ?column? +---------- + 1 +(1 row) + +-- List all the existing cached connections. loopback, loopback2, loopback4 +-- should be output. +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; + server_name | valid +-------------+------- + loopback | t + loopback2 | t + loopback4 | t +(3 rows) + +DROP SERVER loopback4 CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to user mapping for public on server loopback4 +drop cascades to foreign table ft8 +-- Return false as connections are still in use, warnings are issued. +SELECT postgres_fdw_disconnect_all(); +WARNING: cannot close dropped server connection because it is still in use +WARNING: cannot close connection for server "loopback" because it is still in use +WARNING: cannot close connection for server "loopback2" because it is still in use + postgres_fdw_disconnect_all +----------------------------- + f +(1 row) + +COMMIT; +-- Close loopback2 connection and return true. +SELECT postgres_fdw_disconnect('loopback2'); + postgres_fdw_disconnect +------------------------- + t +(1 row) + +-- List all the existing cached connections. loopback should be output. +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; + server_name | valid +-------------+------- + loopback | t +(1 row) + +-- Return false as loopback2 connectin is closed already. +SELECT postgres_fdw_disconnect('loopback2'); + postgres_fdw_disconnect +------------------------- + f +(1 row) + +-- Return an error as there is no foreign server with given name. +SELECT postgres_fdw_disconnect('unknownserver'); +ERROR: server "unknownserver" does not exist +-- Close loopback connection and return true. +SELECT postgres_fdw_disconnect_all(); + postgres_fdw_disconnect_all +----------------------------- + t +(1 row) + +-- List all the existing cached connections. No connection exists, so NULL +-- should be output. +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; + server_name | valid +-------------+------- +(0 rows) + +-- ============================================================================= +-- test case for having multiple cached connections for a foreign server +-- ============================================================================= +CREATE ROLE multi_conn_user1 SUPERUSER; +CREATE ROLE multi_conn_user2 SUPERUSER; +CREATE USER MAPPING FOR multi_conn_user1 SERVER loopback; +CREATE USER MAPPING FOR multi_conn_user2 SERVER loopback; +-- Will cache loopback connection with user mapping for multi_conn_user1 +SET ROLE multi_conn_user1; +SELECT 1 FROM ft1 LIMIT 1; + ?column? +---------- + 1 +(1 row) + +RESET ROLE; +-- Will cache loopback connection with user mapping for multi_conn_user2 +SET ROLE multi_conn_user2; +SELECT 1 FROM ft1 LIMIT 1; + ?column? +---------- + 1 +(1 row) + +RESET ROLE; +-- Should output two connections for loopback server +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; + server_name | valid +-------------+------- + loopback | t + loopback | t +(2 rows) + +-- Close loopback connections and return true. +SELECT postgres_fdw_disconnect('loopback'); + postgres_fdw_disconnect +------------------------- + t +(1 row) + +-- List all the existing cached connections. No connection exists, so NULL +-- should be output. +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; + server_name | valid +-------------+------- +(0 rows) + +-- Clean up +DROP USER MAPPING FOR multi_conn_user1 SERVER loopback; +DROP USER MAPPING FOR multi_conn_user2 SERVER loopback; +DROP ROLE multi_conn_user1; +DROP ROLE multi_conn_user2; -- =================================================================== -- batch insert -- =================================================================== diff --git a/contrib/postgres_fdw/postgres_fdw--1.0--1.1.sql b/contrib/postgres_fdw/postgres_fdw--1.0--1.1.sql index 7f85784466c45..ed4ca378d4abe 100644 --- a/contrib/postgres_fdw/postgres_fdw--1.0--1.1.sql +++ b/contrib/postgres_fdw/postgres_fdw--1.0--1.1.sql @@ -8,3 +8,13 @@ CREATE FUNCTION postgres_fdw_get_connections (OUT server_name text, RETURNS SETOF record AS 'MODULE_PATHNAME' LANGUAGE C STRICT PARALLEL RESTRICTED; + +CREATE FUNCTION postgres_fdw_disconnect (text) +RETURNS bool +AS 'MODULE_PATHNAME' +LANGUAGE C STRICT PARALLEL RESTRICTED; + +CREATE FUNCTION postgres_fdw_disconnect_all () +RETURNS bool +AS 'MODULE_PATHNAME' +LANGUAGE C STRICT PARALLEL RESTRICTED; diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql index 28b82f5f9dc0c..9473ab07623ca 100644 --- a/contrib/postgres_fdw/sql/postgres_fdw.sql +++ b/contrib/postgres_fdw/sql/postgres_fdw.sql @@ -19,7 +19,10 @@ DO $d$ OPTIONS (dbname '$$||current_database()||$$', port '$$||current_setting('port')||$$' )$$; - + EXECUTE $$CREATE SERVER loopback4 FOREIGN DATA WRAPPER postgres_fdw + OPTIONS (dbname '$$||current_database()||$$', + port '$$||current_setting('port')||$$' + )$$; END; $d$; @@ -28,6 +31,7 @@ CREATE USER MAPPING FOR public SERVER testserver1 CREATE USER MAPPING FOR CURRENT_USER SERVER loopback; CREATE USER MAPPING FOR CURRENT_USER SERVER loopback2; CREATE USER MAPPING FOR public SERVER loopback3; +CREATE USER MAPPING FOR public SERVER loopback4; -- =================================================================== -- create objects used through FDW loopback server @@ -154,6 +158,12 @@ CREATE FOREIGN TABLE ft7 ( c3 text ) SERVER loopback3 OPTIONS (schema_name 'S 1', table_name 'T 4'); +CREATE FOREIGN TABLE ft8 ( + c1 int NOT NULL, + c2 int NOT NULL, + c3 text +) SERVER loopback4 OPTIONS (schema_name 'S 1', table_name 'T 4'); + -- =================================================================== -- tests for validator -- =================================================================== @@ -2710,9 +2720,9 @@ COMMIT; -- Clean up DROP PROCEDURE terminate_backend_and_wait(text); --- =================================================================== --- test connection invalidation cases --- =================================================================== +-- ============================================================================= +-- test connection invalidation cases and postgres_fdw_get_connections function +-- ============================================================================= -- This test case is for closing the connection in pgfdw_xact_callback BEGIN; -- List all the existing cached connections. Only loopback2 should be output. @@ -2739,6 +2749,86 @@ COMMIT; -- the above transaction. SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; +-- ======================================================================= +-- test postgres_fdw_disconnect and postgres_fdw_disconnect_all functions +-- ======================================================================= +-- Return true as all cached connections are closed. +SELECT postgres_fdw_disconnect_all(); +-- Ensure to cache loopback connection. +SELECT 1 FROM ft1 LIMIT 1; +BEGIN; +-- Ensure to cache loopback2 connection. +SELECT 1 FROM ft6 LIMIT 1; +-- List all the existing cached connections. loopback and loopback2 should be +-- output. +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; +-- Issue a warning and return false as loopback2 connection is still in use and +-- can not be closed. +SELECT postgres_fdw_disconnect('loopback2'); +-- Close loopback connection, return true and issue a warning as loopback2 +-- connection is still in use and can not be closed. +SELECT postgres_fdw_disconnect_all(); +-- List all the existing cached connections. loopback2 should be output. +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; +-- Ensure to cache loopback connection. +SELECT 1 FROM ft1 LIMIT 1; +-- Ensure to cache loopback4 connection. +SELECT 1 FROM ft8 LIMIT 1; +-- List all the existing cached connections. loopback, loopback2, loopback4 +-- should be output. +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; +DROP SERVER loopback4 CASCADE; +-- Return false as connections are still in use, warnings are issued. +SELECT postgres_fdw_disconnect_all(); +COMMIT; +-- Close loopback2 connection and return true. +SELECT postgres_fdw_disconnect('loopback2'); +-- List all the existing cached connections. loopback should be output. +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; +-- Return false as loopback2 connectin is closed already. +SELECT postgres_fdw_disconnect('loopback2'); +-- Return an error as there is no foreign server with given name. +SELECT postgres_fdw_disconnect('unknownserver'); +-- Close loopback connection and return true. +SELECT postgres_fdw_disconnect_all(); +-- List all the existing cached connections. No connection exists, so NULL +-- should be output. +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; + +-- ============================================================================= +-- test case for having multiple cached connections for a foreign server +-- ============================================================================= +CREATE ROLE multi_conn_user1 SUPERUSER; +CREATE ROLE multi_conn_user2 SUPERUSER; +CREATE USER MAPPING FOR multi_conn_user1 SERVER loopback; +CREATE USER MAPPING FOR multi_conn_user2 SERVER loopback; + +-- Will cache loopback connection with user mapping for multi_conn_user1 +SET ROLE multi_conn_user1; +SELECT 1 FROM ft1 LIMIT 1; +RESET ROLE; + +-- Will cache loopback connection with user mapping for multi_conn_user2 +SET ROLE multi_conn_user2; +SELECT 1 FROM ft1 LIMIT 1; +RESET ROLE; + +-- Should output two connections for loopback server +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; + +-- Close loopback connections and return true. +SELECT postgres_fdw_disconnect('loopback'); + +-- List all the existing cached connections. No connection exists, so NULL +-- should be output. +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; + +-- Clean up +DROP USER MAPPING FOR multi_conn_user1 SERVER loopback; +DROP USER MAPPING FOR multi_conn_user2 SERVER loopback; +DROP ROLE multi_conn_user1; +DROP ROLE multi_conn_user2; + -- =================================================================== -- batch insert -- =================================================================== diff --git a/doc/src/sgml/postgres-fdw.sgml b/doc/src/sgml/postgres-fdw.sgml index fb4c22ac69f9f..8d6abd4c54886 100644 --- a/doc/src/sgml/postgres-fdw.sgml +++ b/doc/src/sgml/postgres-fdw.sgml @@ -512,7 +512,7 @@ OPTIONS (ADD password_required 'false'); the end of that transaction. true is returned otherwise. If there are no open connections, no record is returned. Example usage of the function: - + postgres=# SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; server_name | valid -------------+------- @@ -522,6 +522,51 @@ postgres=# SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; + + + postgres_fdw_disconnect(server_name text) returns boolean + + + This function discards the open connections that are established by + postgres_fdw from the local session to + the foreign server with the given name. Note that there can be + multiple connections to the given server using different user mappings. + If the connections are used in the current local transaction, + they are not disconnected and warning messages are reported. + This function returns true if it disconnects + at least one connection, otherwise false. + If no foreign server with the given name is found, an error is reported. + Example usage of the function: + +postgres=# SELECT postgres_fdw_disconnect('loopback1'); + postgres_fdw_disconnect +------------------------- + t + + + + + + + postgres_fdw_disconnect_all() returns boolean + + + This function discards all the open connections that are established by + postgres_fdw from the local session to + the foreign servers. If the connections are used in the current local + transaction, they are not disconnected and warning messages are reported. + This function returns true if it disconnects + at least one connection, otherwise false. + Example usage of the function: + +postgres=# SELECT postgres_fdw_disconnect_all(); + postgres_fdw_disconnect_all +----------------------------- + t + + + + @@ -537,6 +582,26 @@ postgres=# SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; multiple user identities (user mappings) are used to access the foreign server, a connection is established for each user mapping. + + + When changing the definition of or removing a foreign server or + a user mapping, the corresponding connections are closed. + But note that if the connections are used in the current local transaction + at that moment, they are kept until the end of the transaction. + Closed connections will be established again when they are necessary + by subsequent queries using a foreign table. + + + + Once a connection to a foreign server has been established, + it's usually kept until the local or the corresponding remote + session exits. To disconnect a connection explicitly, + postgres_fdw_disconnect and + postgres_fdw_disconnect_all functions + need to be used. For example, these are useful when closing + the connections that are no longer necessary and then preventing them + from consuming the foreign server connections capacity too much. + From 6adc5376dca4ef8b7d591c0ee7338cb9ff660216 Mon Sep 17 00:00:00 2001 From: Fujii Masao Date: Tue, 26 Jan 2021 16:36:21 +0900 Subject: [PATCH 179/240] postgres_fdw: Stabilize regression test for postgres_fdw_disconnect_all(). The regression test added in commit 411ae64997 caused buildfarm failures. The cause of them was that the order of warning messages output in the test was not stable. To fix this, this commit sets client_min_messages to ERROR temporarily when performing the test generating those warnings. Per buildfarm failures. Discussion: https://postgr.es/m/2147113.1611644754@sss.pgh.pa.us --- contrib/postgres_fdw/expected/postgres_fdw.out | 6 +++--- contrib/postgres_fdw/sql/postgres_fdw.sql | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index e33c92d7f1c2b..9d77d6e850560 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -9216,15 +9216,15 @@ NOTICE: drop cascades to 2 other objects DETAIL: drop cascades to user mapping for public on server loopback4 drop cascades to foreign table ft8 -- Return false as connections are still in use, warnings are issued. +-- But disable warnings temporarily because the order of them is not stable. +SET client_min_messages = 'ERROR'; SELECT postgres_fdw_disconnect_all(); -WARNING: cannot close dropped server connection because it is still in use -WARNING: cannot close connection for server "loopback" because it is still in use -WARNING: cannot close connection for server "loopback2" because it is still in use postgres_fdw_disconnect_all ----------------------------- f (1 row) +RESET client_min_messages; COMMIT; -- Close loopback2 connection and return true. SELECT postgres_fdw_disconnect('loopback2'); diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql index 9473ab07623ca..62382d1a55f7f 100644 --- a/contrib/postgres_fdw/sql/postgres_fdw.sql +++ b/contrib/postgres_fdw/sql/postgres_fdw.sql @@ -2779,7 +2779,10 @@ SELECT 1 FROM ft8 LIMIT 1; SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; DROP SERVER loopback4 CASCADE; -- Return false as connections are still in use, warnings are issued. +-- But disable warnings temporarily because the order of them is not stable. +SET client_min_messages = 'ERROR'; SELECT postgres_fdw_disconnect_all(); +RESET client_min_messages; COMMIT; -- Close loopback2 connection and return true. SELECT postgres_fdw_disconnect('loopback2'); From 0c3fc09fe359a6dc46f1870ceccf60ec60396bc9 Mon Sep 17 00:00:00 2001 From: Fujii Masao Date: Tue, 26 Jan 2021 17:16:52 +0900 Subject: [PATCH 180/240] postgres_fdw: Fix test failure with -DENFORCE_REGRESSION_TEST_NAME_RESTRICTIONS The roles created by regression test should have names starting with "regress_", and the test introduced in commit 411ae64997 did not do that. Per buildfarm member longfin. Discussion: https://postgr.es/m/73fc5ae4-3c54-1262-4533-f8c547de2e60@oss.nttdata.com --- .../postgres_fdw/expected/postgres_fdw.out | 24 +++++++++---------- contrib/postgres_fdw/sql/postgres_fdw.sql | 24 +++++++++---------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index 9d77d6e850560..07e06e5bf7310 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -9267,12 +9267,12 @@ SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; -- ============================================================================= -- test case for having multiple cached connections for a foreign server -- ============================================================================= -CREATE ROLE multi_conn_user1 SUPERUSER; -CREATE ROLE multi_conn_user2 SUPERUSER; -CREATE USER MAPPING FOR multi_conn_user1 SERVER loopback; -CREATE USER MAPPING FOR multi_conn_user2 SERVER loopback; --- Will cache loopback connection with user mapping for multi_conn_user1 -SET ROLE multi_conn_user1; +CREATE ROLE regress_multi_conn_user1 SUPERUSER; +CREATE ROLE regress_multi_conn_user2 SUPERUSER; +CREATE USER MAPPING FOR regress_multi_conn_user1 SERVER loopback; +CREATE USER MAPPING FOR regress_multi_conn_user2 SERVER loopback; +-- Will cache loopback connection with user mapping for regress_multi_conn_user1 +SET ROLE regress_multi_conn_user1; SELECT 1 FROM ft1 LIMIT 1; ?column? ---------- @@ -9280,8 +9280,8 @@ SELECT 1 FROM ft1 LIMIT 1; (1 row) RESET ROLE; --- Will cache loopback connection with user mapping for multi_conn_user2 -SET ROLE multi_conn_user2; +-- Will cache loopback connection with user mapping for regress_multi_conn_user2 +SET ROLE regress_multi_conn_user2; SELECT 1 FROM ft1 LIMIT 1; ?column? ---------- @@ -9312,10 +9312,10 @@ SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; (0 rows) -- Clean up -DROP USER MAPPING FOR multi_conn_user1 SERVER loopback; -DROP USER MAPPING FOR multi_conn_user2 SERVER loopback; -DROP ROLE multi_conn_user1; -DROP ROLE multi_conn_user2; +DROP USER MAPPING FOR regress_multi_conn_user1 SERVER loopback; +DROP USER MAPPING FOR regress_multi_conn_user2 SERVER loopback; +DROP ROLE regress_multi_conn_user1; +DROP ROLE regress_multi_conn_user2; -- =================================================================== -- batch insert -- =================================================================== diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql index 62382d1a55f7f..647192cf6ace6 100644 --- a/contrib/postgres_fdw/sql/postgres_fdw.sql +++ b/contrib/postgres_fdw/sql/postgres_fdw.sql @@ -2801,18 +2801,18 @@ SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; -- ============================================================================= -- test case for having multiple cached connections for a foreign server -- ============================================================================= -CREATE ROLE multi_conn_user1 SUPERUSER; -CREATE ROLE multi_conn_user2 SUPERUSER; -CREATE USER MAPPING FOR multi_conn_user1 SERVER loopback; -CREATE USER MAPPING FOR multi_conn_user2 SERVER loopback; +CREATE ROLE regress_multi_conn_user1 SUPERUSER; +CREATE ROLE regress_multi_conn_user2 SUPERUSER; +CREATE USER MAPPING FOR regress_multi_conn_user1 SERVER loopback; +CREATE USER MAPPING FOR regress_multi_conn_user2 SERVER loopback; --- Will cache loopback connection with user mapping for multi_conn_user1 -SET ROLE multi_conn_user1; +-- Will cache loopback connection with user mapping for regress_multi_conn_user1 +SET ROLE regress_multi_conn_user1; SELECT 1 FROM ft1 LIMIT 1; RESET ROLE; --- Will cache loopback connection with user mapping for multi_conn_user2 -SET ROLE multi_conn_user2; +-- Will cache loopback connection with user mapping for regress_multi_conn_user2 +SET ROLE regress_multi_conn_user2; SELECT 1 FROM ft1 LIMIT 1; RESET ROLE; @@ -2827,10 +2827,10 @@ SELECT postgres_fdw_disconnect('loopback'); SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; -- Clean up -DROP USER MAPPING FOR multi_conn_user1 SERVER loopback; -DROP USER MAPPING FOR multi_conn_user2 SERVER loopback; -DROP ROLE multi_conn_user1; -DROP ROLE multi_conn_user2; +DROP USER MAPPING FOR regress_multi_conn_user1 SERVER loopback; +DROP USER MAPPING FOR regress_multi_conn_user2 SERVER loopback; +DROP ROLE regress_multi_conn_user1; +DROP ROLE regress_multi_conn_user2; -- =================================================================== -- batch insert From 7b4c660466dd8a1d25ca316ac02099a7cf0e5896 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Tue, 26 Jan 2021 18:43:01 +0900 Subject: [PATCH 181/240] Fix memory leak when deallocating prepared statement in postgres_fdw The leak is minor, so no backpatch is done. Oversight in 21734d2. Reported-by: Tom Lane --- contrib/postgres_fdw/postgres_fdw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index 8648be0b810f9..2ce42ce3f113d 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -4063,6 +4063,7 @@ deallocate_query(PgFdwModifyState *fmstate) if (PQresultStatus(res) != PGRES_COMMAND_OK) pgfdw_report_error(ERROR, res, fmstate->conn, true, sql); PQclear(res); + pfree(fmstate->p_name); fmstate->p_name = NULL; } From f76a85000bba2f1b1c926cbbe525e47b246215f1 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 26 Jan 2021 13:04:52 -0500 Subject: [PATCH 182/240] Code review for psql's helpSQL() function. The loops to identify word boundaries could access past the end of the input string. Likely that would never result in an actual crash, but it makes valgrind unhappy. The logic to try different numbers of words didn't work when the input has two words but we only have a match to the first, eg "\h with select". (We must "continue" the pass loop, not "break".) The logic to compute nl_count was bizarrely managed, and in at least two code paths could end up calling PageOutput with nl_count = 0, resulting in failing to paginate output that should have been fed to the pager. Also, in v12 and up, the nl_count calculation hadn't been updated to account for the addition of a URL. The PQExpBuffer holding the command syntax details wasn't freed, resulting in a session-lifespan memory leak. While here, improve some comments, choose a more descriptive name for a variable, fix inconsistent datatype choice for another variable. Per bug #16837 from Alexander Lakhin. This code is very old, so back-patch to all supported branches. Kyotaro Horiguchi and Tom Lane Discussion: https://postgr.es/m/16837-479bcd56040c71b3@postgresql.org --- src/bin/psql/help.c | 59 ++++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index 4883ebd2ed0b1..e44120bf76913 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -535,6 +535,7 @@ helpSQL(const char *topic, unsigned short int pager) int i; int j; + /* Find screen width to determine how many columns will fit */ #ifdef TIOCGWINSZ struct winsize screen_size; @@ -572,56 +573,63 @@ helpSQL(const char *topic, unsigned short int pager) else { int i, - j, - x = 0; - bool help_found = false; + pass; FILE *output = NULL; size_t len, - wordlen; - int nl_count = 0; + wordlen, + j; + int nl_count; /* + * len is the amount of the input to compare to the help topic names. * We first try exact match, then first + second words, then first * word only. */ len = strlen(topic); - for (x = 1; x <= 3; x++) + for (pass = 1; pass <= 3; pass++) { - if (x > 1) /* Nothing on first pass - try the opening + if (pass > 1) /* Nothing on first pass - try the opening * word(s) */ { wordlen = j = 1; - while (topic[j] != ' ' && j++ < len) + while (j < len && topic[j++] != ' ') wordlen++; - if (x == 2) + if (pass == 2 && j < len) { - j++; - while (topic[j] != ' ' && j++ <= len) + wordlen++; + while (j < len && topic[j++] != ' ') wordlen++; } - if (wordlen >= len) /* Don't try again if the same word */ + if (wordlen >= len) { - if (!output) - output = PageOutput(nl_count, pager ? &(pset.popt.topt) : NULL); - break; + /* Failed to shorten input, so try next pass if any */ + continue; } len = wordlen; } - /* Count newlines for pager */ + /* + * Count newlines for pager. This logic must agree with what the + * following loop will do! + */ + nl_count = 0; for (i = 0; QL_HELP[i].cmd; i++) { if (pg_strncasecmp(topic, QL_HELP[i].cmd, len) == 0 || strcmp(topic, "*") == 0) { - nl_count += 5 + QL_HELP[i].nl_count; + /* magic constant here must match format below! */ + nl_count += 7 + QL_HELP[i].nl_count; /* If we have an exact match, exit. Fixes \h SELECT */ if (pg_strcasecmp(topic, QL_HELP[i].cmd) == 0) break; } } + /* If no matches, don't open the output yet */ + if (nl_count == 0) + continue; if (!output) output = PageOutput(nl_count, pager ? &(pset.popt.topt) : NULL); @@ -636,10 +644,10 @@ helpSQL(const char *topic, unsigned short int pager) initPQExpBuffer(&buffer); QL_HELP[i].syntaxfunc(&buffer); - help_found = true; url = psprintf("https://www.postgresql.org/docs/%s/%s.html", strstr(PG_VERSION, "devel") ? "devel" : PG_MAJORVERSION, QL_HELP[i].docbook_id); + /* # of newlines in format must match constant above! */ fprintf(output, _("Command: %s\n" "Description: %s\n" "Syntax:\n%s\n\n" @@ -649,17 +657,24 @@ helpSQL(const char *topic, unsigned short int pager) buffer.data, url); free(url); + termPQExpBuffer(&buffer); + /* If we have an exact match, exit. Fixes \h SELECT */ if (pg_strcasecmp(topic, QL_HELP[i].cmd) == 0) break; } } - if (help_found) /* Don't keep trying if we got a match */ - break; + break; } - if (!help_found) - fprintf(output, _("No help available for \"%s\".\nTry \\h with no arguments to see available help.\n"), topic); + /* If we never found anything, report that */ + if (!output) + { + output = PageOutput(2, pager ? &(pset.popt.topt) : NULL); + fprintf(output, _("No help available for \"%s\".\n" + "Try \\h with no arguments to see available help.\n"), + topic); + } ClosePager(output); } From 7292fd8f1c781278021407276474d9188845113d Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 26 Jan 2021 13:58:18 -0500 Subject: [PATCH 183/240] Suppress compiler warnings from commit ee895a655. For obscure reasons, some buildfarm members are now generating complaints about plpgsql_call_handler's "retval" variable possibly being used uninitialized. It seems no less safe than it was before that commit, but these complaints are (mostly?) new. I trust that initializing the variable where it's declared will be enough to shut that up. I also notice that some compilers are warning about setjmp clobber of the same variable, which is maybe a bit more defensible. Mark it volatile to silence that. Also, rearrange the logic to give procedure_resowner a single point of initialization, in hopes of silencing some setjmp-clobber warnings about that. (Marking it volatile would serve too, but its sibling variables are depending on single assignment, so let's stick with that method.) Discussion: https://postgr.es/m/E1l4F1z-0000cN-Lx@gemulon.postgresql.org --- src/pl/plpgsql/src/pl_handler.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c index 97f4264c28726..00aace2f39fb3 100644 --- a/src/pl/plpgsql/src/pl_handler.c +++ b/src/pl/plpgsql/src/pl_handler.c @@ -224,8 +224,8 @@ plpgsql_call_handler(PG_FUNCTION_ARGS) bool nonatomic; PLpgSQL_function *func; PLpgSQL_execstate *save_cur_estate; - ResourceOwner procedure_resowner = NULL; - Datum retval; + ResourceOwner procedure_resowner; + volatile Datum retval = (Datum) 0; int rc; nonatomic = fcinfo->context && @@ -254,9 +254,9 @@ plpgsql_call_handler(PG_FUNCTION_ARGS) * Therefore, be very wary of adding any code between here and the PG_TRY * block. */ - if (nonatomic && func->requires_procedure_resowner) - procedure_resowner = - ResourceOwnerCreate(NULL, "PL/pgSQL procedure resources"); + procedure_resowner = + (nonatomic && func->requires_procedure_resowner) ? + ResourceOwnerCreate(NULL, "PL/pgSQL procedure resources") : NULL; PG_TRY(); { @@ -271,7 +271,7 @@ plpgsql_call_handler(PG_FUNCTION_ARGS) { plpgsql_exec_event_trigger(func, (EventTriggerData *) fcinfo->context); - retval = (Datum) 0; + /* there's no return value in this case */ } else retval = plpgsql_exec_function(func, fcinfo, From d5a83d79c9f9b660a6a5a77afafe146d3c8c6f46 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 26 Jan 2021 16:37:12 -0500 Subject: [PATCH 184/240] Rethink recently-added SPI interfaces. SPI_execute_with_receiver and SPI_cursor_parse_open_with_paramlist are new in v14 (cf. commit 2f48ede08). Before they can get out the door, let's change their APIs to follow the practice recently established by SPI_prepare_extended etc: shove all optional arguments into a struct that callers are supposed to pre-zero. The hope is to allow future addition of more options without either API breakage or a continuing proliferation of new SPI entry points. With that in mind, choose slightly more generic names for them: SPI_execute_extended and SPI_cursor_parse_open respectively. Discussion: https://postgr.es/m/CAFj8pRCLPdDAETvR7Po7gC5y_ibkn_-bOzbeJb39WHms01194Q@mail.gmail.com --- doc/src/sgml/spi.sgml | 306 +++++++++++++++++++++-------------- src/backend/executor/spi.c | 114 ++++++------- src/include/executor/spi.h | 24 +-- src/pl/plpgsql/src/pl_exec.c | 46 +++--- 4 files changed, 280 insertions(+), 210 deletions(-) diff --git a/doc/src/sgml/spi.sgml b/doc/src/sgml/spi.sgml index d8c121f5f355f..6543eaa03435b 100644 --- a/doc/src/sgml/spi.sgml +++ b/doc/src/sgml/spi.sgml @@ -632,25 +632,23 @@ int SPI_exec(const char * command, long count< - - SPI_execute_with_args + + SPI_execute_extended - SPI_execute_with_args + SPI_execute_extended 3 - SPI_execute_with_args + SPI_execute_extended execute a command with out-of-line parameters -int SPI_execute_with_args(const char *command, - int nargs, Oid *argtypes, - Datum *values, const char *nulls, - bool read_only, long count) +int SPI_execute_extended(const char *command, + const SPIExecuteOptions * options) @@ -658,30 +656,28 @@ int SPI_execute_with_args(const char *command, Description - SPI_execute_with_args executes a command that might + SPI_execute_extended executes a command that might include references to externally supplied parameters. The command text - refers to a parameter as $n, and - the call specifies data types and values for each such symbol. - read_only and count have - the same interpretation as in SPI_execute. + refers to a parameter as $n, + and the options->params object (if supplied) + provides values and type information for each such symbol. + Various execution options can be specified + in the options struct, too. - The main advantage of this routine compared to - SPI_execute is that data values can be inserted - into the command without tedious quoting/escaping, and thus with much - less risk of SQL-injection attacks. + The options->params object should normally + mark each parameter with the PARAM_FLAG_CONST flag, + since a one-shot plan is always used for the query. - Similar results can be achieved with SPI_prepare followed by - SPI_execute_plan; however, when using this function - the query plan is always customized to the specific parameter values - provided. - For one-time query execution, this function should be preferred. - If the same command is to be executed with many different parameters, - either method might be faster, depending on the cost of re-planning - versus the benefit of custom plans. + If options->dest is not NULL, then result + tuples are passed to that object as they are generated by the executor, + instead of being accumulated in SPI_tuptable. Using + a caller-supplied DestReceiver object is particularly + helpful for queries that might generate many tuples, since the data can + be processed on-the-fly instead of being accumulated in memory. @@ -699,69 +695,80 @@ int SPI_execute_with_args(const char *command, - int nargs + const SPIExecuteOptions * options - number of input parameters ($1, $2, etc.) + struct containing optional arguments + + + + Callers should always zero out the entire options + struct, then fill whichever fields they want to set. This ensures forward + compatibility of code, since any fields that are added to the struct in + future will be defined to behave backwards-compatibly if they are zero. + The currently available options fields are: + + - Oid * argtypes + ParamListInfo params - an array of length nargs, containing the - OIDs of the data types of the parameters + data structure containing query parameter types and values; NULL if none - Datum * values + bool read_only - - an array of length nargs, containing the actual - parameter values - + true for read-only execution - const char * nulls + bool no_snapshots - an array of length nargs, describing which - parameters are null + true prevents SPI from managing snapshots for + execution of the query; use with extreme caution + + + + uint64 tcount + - If nulls is NULL then - SPI_execute_with_args assumes that no parameters - are null. Otherwise, each entry of the nulls - array should be ' ' if the corresponding parameter - value is non-null, or 'n' if the corresponding parameter - value is null. (In the latter case, the actual value in the - corresponding values entry doesn't matter.) Note - that nulls is not a text string, just an array: - it does not need a '\0' terminator. + maximum number of rows to return, + or 0 for no limit - bool read_only + DestReceiver * dest - true for read-only execution + + DestReceiver object that will receive any tuples + emitted by the query; if NULL, result tuples are accumulated into + a SPI_tuptable structure, as + in SPI_execute + - long count + ResourceOwner owner - maximum number of rows to return, - or 0 for no limit + This field is present for consistency + with SPI_execute_plan_extended, but it is + ignored, since the plan used + by SPI_execute_extended is never saved. @@ -776,35 +783,40 @@ int SPI_execute_with_args(const char *command, + When options->dest is NULL, SPI_processed and SPI_tuptable are set as in - SPI_execute if successful. + SPI_execute. + When options->dest is not NULL, + SPI_processed is set to zero and + SPI_tuptable is set to NULL. If a tuple count + is required, the caller's DestReceiver object must + calculate it. - - SPI_execute_with_receiver + + SPI_execute_with_args - SPI_execute_with_receiver + SPI_execute_with_args 3 - SPI_execute_with_receiver + SPI_execute_with_args execute a command with out-of-line parameters - int SPI_execute_with_receiver(const char *command, - ParamListInfo params, - bool read_only, - long count, - DestReceiver *dest) +int SPI_execute_with_args(const char *command, + int nargs, Oid *argtypes, + Datum *values, const char *nulls, + bool read_only, long count) @@ -812,28 +824,30 @@ int SPI_execute_with_args(const char *command, Description - SPI_execute_with_receiver executes a command that might + SPI_execute_with_args executes a command that might include references to externally supplied parameters. The command text - refers to a parameter as $n, - and the params object provides values and type - information for each such symbol. + refers to a parameter as $n, and + the call specifies data types and values for each such symbol. read_only and count have the same interpretation as in SPI_execute. - If dest is not NULL, then result tuples are passed - to that object as they are generated by the executor, instead of being - accumulated in SPI_tuptable. Using a - caller-supplied DestReceiver object is particularly - helpful for queries that might generate many tuples, since the data can - be processed on-the-fly instead of being accumulated in memory. + The main advantage of this routine compared to + SPI_execute is that data values can be inserted + into the command without tedious quoting/escaping, and thus with much + less risk of SQL-injection attacks. - The params object should normally mark each - parameter with the PARAM_FLAG_CONST flag, since - a one-shot plan is always used for the query. + Similar results can be achieved with SPI_prepare followed by + SPI_execute_plan; however, when using this function + the query plan is always customized to the specific parameter values + provided. + For one-time query execution, this function should be preferred. + If the same command is to be executed with many different parameters, + either method might be faster, depending on the cost of re-planning + versus the benefit of custom plans. @@ -851,38 +865,69 @@ int SPI_execute_with_args(const char *command, - ParamListInfo params + int nargs - data structure containing parameter types and values; NULL if none + number of input parameters ($1, $2, etc.) - bool read_only + Oid * argtypes - true for read-only execution + + an array of length nargs, containing the + OIDs of the data types of the parameters + - long count + Datum * values - maximum number of rows to return, - or 0 for no limit + an array of length nargs, containing the actual + parameter values - DestReceiver * dest + const char * nulls - DestReceiver object that will receive any tuples - emitted by the query; if NULL, tuples are returned - in SPI_tuptable + an array of length nargs, describing which + parameters are null + + + + If nulls is NULL then + SPI_execute_with_args assumes that no parameters + are null. Otherwise, each entry of the nulls + array should be ' ' if the corresponding parameter + value is non-null, or 'n' if the corresponding parameter + value is null. (In the latter case, the actual value in the + corresponding values entry doesn't matter.) Note + that nulls is not a text string, just an array: + it does not need a '\0' terminator. + + + + + + bool read_only + + true for read-only execution + + + + + long count + + + maximum number of rows to return, + or 0 for no limit @@ -897,15 +942,9 @@ int SPI_execute_with_args(const char *command, - When dest is NULL, SPI_processed and SPI_tuptable are set as in - SPI_execute. - When dest is not NULL, - SPI_processed is set to zero and - SPI_tuptable is set to NULL. If a tuple count - is required, the caller's DestReceiver object must - calculate it. + SPI_execute if successful. @@ -1873,11 +1912,11 @@ int SPI_execute_plan_extended(SPIPlanPtr plan, - When dest is NULL, + When options->dest is NULL, SPI_processed and SPI_tuptable are set as in SPI_execute_plan. - When dest is not NULL, + When options->dest is not NULL, SPI_processed is set to zero and SPI_tuptable is set to NULL. If a tuple count is required, the caller's DestReceiver object must @@ -2263,6 +2302,12 @@ Portal SPI_cursor_open_with_args(const char *name, The passed-in parameter data will be copied into the cursor's portal, so it can be freed while the cursor still exists. + + + This function is now deprecated in favor + of SPI_cursor_parse_open, which provides equivalent + functionality using a more modern API for handling query parameters. + @@ -2465,26 +2510,24 @@ Portal SPI_cursor_open_with_paramlist(const char *name, - - SPI_cursor_parse_open_with_paramlist + + SPI_cursor_parse_open - SPI_cursor_parse_open_with_paramlist + SPI_cursor_parse_open 3 - SPI_cursor_parse_open_with_paramlist - set up a cursor using a query and parameters + SPI_cursor_parse_open + set up a cursor using a query string and parameters -Portal SPI_cursor_parse_open_with_paramlist(const char *name, - const char *command, - ParamListInfo params, - bool read_only, - int cursorOptions) +Portal SPI_cursor_parse_open(const char *name, + const char *command, + const SPIParseOpenOptions * options) @@ -2492,17 +2535,27 @@ Portal SPI_cursor_parse_open_with_paramlist(const char *nameDescription - SPI_cursor_parse_open_with_paramlist sets up a cursor - (internally, a portal) that will execute the specified query. This - function is equivalent to SPI_cursor_open_with_args - except that any parameters referenced by the query are provided by - a ParamListInfo object, rather than in ad-hoc arrays. + SPI_cursor_parse_open sets up a cursor + (internally, a portal) that will execute the specified query string. + This is comparable to SPI_prepare_cursor followed + by SPI_cursor_open_with_paramlist, except that + parameter references within the query string are handled entirely by + supplying a ParamListInfo object. + + + + For one-time query execution, this function should be preferred + over SPI_prepare_cursor followed by + SPI_cursor_open_with_paramlist. + If the same command is to be executed with many different parameters, + either method might be faster, depending on the cost of re-planning + versus the benefit of custom plans. - The params object should normally mark each - parameter with the PARAM_FLAG_CONST flag, since - a one-shot plan is always used for the query. + The options->params object should normally + mark each parameter with the PARAM_FLAG_CONST flag, + since a one-shot plan is always used for the query. @@ -2535,18 +2588,30 @@ Portal SPI_cursor_parse_open_with_paramlist(const char *name - ParamListInfo params + const SPIParseOpenOptions * options - data structure containing parameter types and values; NULL if none + struct containing optional arguments + + + + Callers should always zero out the entire options + struct, then fill whichever fields they want to set. This ensures forward + compatibility of code, since any fields that are added to the struct in + future will be defined to behave backwards-compatibly if they are zero. + The currently available options fields are: + + - bool read_only + ParamListInfo params - true for read-only execution + + data structure containing query parameter types and values; NULL if none + @@ -2558,6 +2623,13 @@ Portal SPI_cursor_parse_open_with_paramlist(const char *name + + + bool read_only + + true for read-only execution + + diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 68a6bcea02d59..00aa78ea53993 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -538,6 +538,43 @@ SPI_exec(const char *src, long tcount) return SPI_execute(src, false, tcount); } +/* Parse, plan, and execute a query string, with extensible options */ +int +SPI_execute_extended(const char *src, + const SPIExecuteOptions *options) +{ + int res; + _SPI_plan plan; + + if (src == NULL || options == NULL) + return SPI_ERROR_ARGUMENT; + + res = _SPI_begin_call(true); + if (res < 0) + return res; + + memset(&plan, 0, sizeof(_SPI_plan)); + plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = RAW_PARSE_DEFAULT; + plan.cursor_options = CURSOR_OPT_PARALLEL_OK; + if (options->params) + { + plan.parserSetup = options->params->parserSetup; + plan.parserSetupArg = options->params->parserSetupArg; + } + + _SPI_prepare_oneshot_plan(src, &plan); + + res = _SPI_execute_plan(&plan, options->params, + InvalidSnapshot, InvalidSnapshot, + options->read_only, options->no_snapshots, + true, options->tcount, + options->dest, options->owner); + + _SPI_end_call(true); + return res; +} + /* Execute a previously prepared plan */ int SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls, @@ -715,52 +752,6 @@ SPI_execute_with_args(const char *src, return res; } -/* - * SPI_execute_with_receiver -- plan and execute a query with arguments - * - * This is the same as SPI_execute_with_args except that parameters are - * supplied through a ParamListInfo, and (if dest isn't NULL) we send - * result tuples to the caller-supplied DestReceiver rather than through - * the usual SPI output arrangements. - */ -int -SPI_execute_with_receiver(const char *src, - ParamListInfo params, - bool read_only, long tcount, - DestReceiver *dest) -{ - int res; - _SPI_plan plan; - - if (src == NULL || tcount < 0) - return SPI_ERROR_ARGUMENT; - - res = _SPI_begin_call(true); - if (res < 0) - return res; - - memset(&plan, 0, sizeof(_SPI_plan)); - plan.magic = _SPI_PLAN_MAGIC; - plan.parse_mode = RAW_PARSE_DEFAULT; - plan.cursor_options = CURSOR_OPT_PARALLEL_OK; - if (params) - { - plan.parserSetup = params->parserSetup; - plan.parserSetupArg = params->parserSetupArg; - } - - _SPI_prepare_oneshot_plan(src, &plan); - - res = _SPI_execute_plan(&plan, params, - InvalidSnapshot, InvalidSnapshot, - read_only, false, - true, tcount, - dest, NULL); - - _SPI_end_call(true); - return res; -} - SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes) { @@ -1433,43 +1424,38 @@ SPI_cursor_open_with_paramlist(const char *name, SPIPlanPtr plan, return SPI_cursor_open_internal(name, plan, params, read_only); } -/* - * SPI_cursor_parse_open_with_paramlist() - * - * Same as SPI_cursor_open_with_args except that parameters (if any) are passed - * as a ParamListInfo, which supports dynamic parameter set determination - */ +/* Parse a query and open it as a cursor */ Portal -SPI_cursor_parse_open_with_paramlist(const char *name, - const char *src, - ParamListInfo params, - bool read_only, int cursorOptions) +SPI_cursor_parse_open(const char *name, + const char *src, + const SPIParseOpenOptions *options) { Portal result; _SPI_plan plan; - if (src == NULL) - elog(ERROR, "SPI_cursor_parse_open_with_paramlist called with invalid arguments"); + if (src == NULL || options == NULL) + elog(ERROR, "SPI_cursor_parse_open called with invalid arguments"); SPI_result = _SPI_begin_call(true); if (SPI_result < 0) - elog(ERROR, "SPI_cursor_parse_open_with_paramlist called while not connected"); + elog(ERROR, "SPI_cursor_parse_open called while not connected"); memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; plan.parse_mode = RAW_PARSE_DEFAULT; - plan.cursor_options = cursorOptions; - if (params) + plan.cursor_options = options->cursorOptions; + if (options->params) { - plan.parserSetup = params->parserSetup; - plan.parserSetupArg = params->parserSetupArg; + plan.parserSetup = options->params->parserSetup; + plan.parserSetupArg = options->params->parserSetupArg; } _SPI_prepare_plan(src, &plan); /* We needn't copy the plan; SPI_cursor_open_internal will do so */ - result = SPI_cursor_open_internal(name, &plan, params, read_only); + result = SPI_cursor_open_internal(name, &plan, + options->params, options->read_only); /* And clean up */ _SPI_end_call(true); diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h index 5740f8956e53a..6455d100f5034 100644 --- a/src/include/executor/spi.h +++ b/src/include/executor/spi.h @@ -42,7 +42,7 @@ typedef struct SPIPrepareOptions int cursorOptions; } SPIPrepareOptions; -/* Optional arguments for SPI_execute_plan_extended */ +/* Optional arguments for SPI_execute[_plan]_extended */ typedef struct SPIExecuteOptions { ParamListInfo params; @@ -53,6 +53,14 @@ typedef struct SPIExecuteOptions ResourceOwner owner; } SPIExecuteOptions; +/* Optional arguments for SPI_cursor_parse_open */ +typedef struct SPIParseOpenOptions +{ + ParamListInfo params; + int cursorOptions; + bool read_only; +} SPIParseOpenOptions; + /* Plans are opaque structs for standard users of SPI */ typedef struct _SPI_plan *SPIPlanPtr; @@ -105,6 +113,8 @@ extern int SPI_connect(void); extern int SPI_connect_ext(int options); extern int SPI_finish(void); extern int SPI_execute(const char *src, bool read_only, long tcount); +extern int SPI_execute_extended(const char *src, + const SPIExecuteOptions *options); extern int SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only, long tcount); extern int SPI_execute_plan_extended(SPIPlanPtr plan, @@ -124,10 +134,6 @@ extern int SPI_execute_with_args(const char *src, int nargs, Oid *argtypes, Datum *Values, const char *Nulls, bool read_only, long tcount); -extern int SPI_execute_with_receiver(const char *src, - ParamListInfo params, - bool read_only, long tcount, - DestReceiver *dest); extern SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes); extern SPIPlanPtr SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes, int cursorOptions); @@ -178,11 +184,9 @@ extern Portal SPI_cursor_open_with_args(const char *name, bool read_only, int cursorOptions); extern Portal SPI_cursor_open_with_paramlist(const char *name, SPIPlanPtr plan, ParamListInfo params, bool read_only); -extern Portal SPI_cursor_parse_open_with_paramlist(const char *name, - const char *src, - ParamListInfo params, - bool read_only, - int cursorOptions); +extern Portal SPI_cursor_parse_open(const char *name, + const char *src, + const SPIParseOpenOptions *options); extern Portal SPI_cursor_find(const char *name); extern void SPI_cursor_fetch(Portal portal, bool forward, long count); extern void SPI_cursor_move(Portal portal, bool forward, long count); diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 383d92fc1d054..b4c70aaa7fa5d 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -3603,6 +3603,7 @@ exec_stmt_return_query(PLpgSQL_execstate *estate, Oid restype; int32 restypmod; char *querystr; + SPIExecuteOptions options; /* * Evaluate the string expression after the EXECUTE keyword. Its @@ -3625,14 +3626,15 @@ exec_stmt_return_query(PLpgSQL_execstate *estate, exec_eval_cleanup(estate); /* Execute query, passing params if necessary */ - rc = SPI_execute_with_receiver(querystr, - exec_eval_using_params(estate, - stmt->params), - estate->readonly_func, - 0, - treceiver); + memset(&options, 0, sizeof(options)); + options.params = exec_eval_using_params(estate, + stmt->params); + options.read_only = estate->readonly_func; + options.dest = treceiver; + + rc = SPI_execute_extended(querystr, &options); if (rc < 0) - elog(ERROR, "SPI_execute_with_receiver failed executing query \"%s\": %s", + elog(ERROR, "SPI_execute_extended failed executing query \"%s\": %s", querystr, SPI_result_code_string(rc)); } @@ -4402,6 +4404,7 @@ exec_stmt_dynexecute(PLpgSQL_execstate *estate, char *querystr; int exec_res; ParamListInfo paramLI; + SPIExecuteOptions options; MemoryContext stmt_mcontext = get_stmt_mcontext(estate); /* @@ -4426,8 +4429,12 @@ exec_stmt_dynexecute(PLpgSQL_execstate *estate, * Execute the query without preparing a saved plan. */ paramLI = exec_eval_using_params(estate, stmt->params); - exec_res = SPI_execute_with_receiver(querystr, paramLI, - estate->readonly_func, 0, NULL); + + memset(&options, 0, sizeof(options)); + options.params = paramLI; + options.read_only = estate->readonly_func; + + exec_res = SPI_execute_extended(querystr, &options); switch (exec_res) { @@ -4479,7 +4486,7 @@ exec_stmt_dynexecute(PLpgSQL_execstate *estate, break; default: - elog(ERROR, "SPI_execute_with_receiver failed executing query \"%s\": %s", + elog(ERROR, "SPI_execute_extended failed executing query \"%s\": %s", querystr, SPI_result_code_string(exec_res)); break; } @@ -8582,6 +8589,7 @@ exec_dynquery_with_params(PLpgSQL_execstate *estate, Oid restype; int32 restypmod; char *querystr; + SPIParseOpenOptions options; MemoryContext stmt_mcontext = get_stmt_mcontext(estate); /* @@ -8603,16 +8611,16 @@ exec_dynquery_with_params(PLpgSQL_execstate *estate, exec_eval_cleanup(estate); /* - * Open an implicit cursor for the query. We use - * SPI_cursor_parse_open_with_paramlist even when there are no params, - * because this avoids making and freeing one copy of the plan. + * Open an implicit cursor for the query. We use SPI_cursor_parse_open + * even when there are no params, because this avoids making and freeing + * one copy of the plan. */ - portal = SPI_cursor_parse_open_with_paramlist(portalname, - querystr, - exec_eval_using_params(estate, - params), - estate->readonly_func, - cursorOptions); + memset(&options, 0, sizeof(options)); + options.params = exec_eval_using_params(estate, params); + options.cursorOptions = cursorOptions; + options.read_only = estate->readonly_func; + + portal = SPI_cursor_parse_open(portalname, querystr, &options); if (portal == NULL) elog(ERROR, "could not open implicit cursor for query \"%s\": %s", From 4c9c359d38ff1e2de388eedd860785be6a49201c Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Wed, 27 Jan 2021 11:54:16 +0900 Subject: [PATCH 185/240] Refactor code in tablecmds.c to check and process tablespace moves Two code paths of tablecmds.c (for relations with storage and without storage) use the same logic to check if the move of a relation to a new tablespace is allowed or not and to update pg_class.reltablespace and pg_class.relfilenode. A potential TABLESPACE clause for REINDEX, CLUSTER and VACUUM FULL needs similar checks to make sure that nothing is moved around in illegal ways (no mapped relations, shared relations only in pg_global, no move of temp tables owned by other backends). This reorganizes the existing code of ALTER TABLE so as all this logic is controlled by two new routines that can be reused for the other commands able to move relations across tablespaces, limiting the number of code paths in need of the same protections. This also removes some code that was duplicated for tables with and without storage for ALTER TABLE. Author: Alexey Kondratov, Michael Paquier Discussion: https://postgr.es/m/YA+9mAMWYLXJMVPL@paquier.xyz --- src/backend/commands/tablecmds.c | 211 ++++++++++++++++++------------- src/include/commands/tablecmds.h | 4 + 2 files changed, 124 insertions(+), 91 deletions(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 8687e9a97c5bb..36747e7277da4 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -3037,6 +3037,113 @@ SetRelationHasSubclass(Oid relationId, bool relhassubclass) table_close(relationRelation, RowExclusiveLock); } +/* + * CheckRelationTableSpaceMove + * Check if relation can be moved to new tablespace. + * + * NOTE: Caller must be holding an appropriate lock on the relation. + * ShareUpdateExclusiveLock is sufficient. + * + * Returns true if the relation can be moved to the new tablespace; + * false otherwise. + */ +bool +CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId) +{ + Oid oldTableSpaceId; + + /* + * No work if no change in tablespace. Note that MyDatabaseTableSpace is + * stored as 0. + */ + oldTableSpaceId = rel->rd_rel->reltablespace; + if (newTableSpaceId == oldTableSpaceId || + (newTableSpaceId == MyDatabaseTableSpace && oldTableSpaceId == 0)) + return false; + + /* + * We cannot support moving mapped relations into different tablespaces. + * (In particular this eliminates all shared catalogs.) + */ + if (RelationIsMapped(rel)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot move system relation \"%s\"", + RelationGetRelationName(rel)))); + + /* Cannot move a non-shared relation into pg_global */ + if (newTableSpaceId == GLOBALTABLESPACE_OID) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("only shared relations can be placed in pg_global tablespace"))); + + /* + * Do not allow moving temp tables of other backends ... their local + * buffer manager is not going to cope. + */ + if (RELATION_IS_OTHER_TEMP(rel)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot move temporary tables of other sessions"))); + + return true; +} + +/* + * SetRelationTableSpace + * Set new reltablespace and relfilenode in pg_class entry. + * + * newTableSpaceId is the new tablespace for the relation, and + * newRelFileNode its new filenode. If newrelfilenode is InvalidOid, + * this field is not updated. + * + * NOTE: Caller must be holding an appropriate lock on the relation. + * ShareUpdateExclusiveLock is sufficient. + * + * The caller of this routine had better check if a relation can be + * moved to this new tablespace by calling CheckRelationTableSpaceMove() + * first, and is responsible for making the change visible with + * CommandCounterIncrement(). + */ +void +SetRelationTableSpace(Relation rel, + Oid newTableSpaceId, + Oid newRelFileNode) +{ + Relation pg_class; + HeapTuple tuple; + Form_pg_class rd_rel; + Oid reloid = RelationGetRelid(rel); + + Assert(CheckRelationTableSpaceMove(rel, newTableSpaceId)); + + /* Get a modifiable copy of the relation's pg_class row. */ + pg_class = table_open(RelationRelationId, RowExclusiveLock); + + tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for relation %u", reloid); + rd_rel = (Form_pg_class) GETSTRUCT(tuple); + + /* Update the pg_class row. */ + rd_rel->reltablespace = (newTableSpaceId == MyDatabaseTableSpace) ? + InvalidOid : newTableSpaceId; + if (OidIsValid(newRelFileNode)) + rd_rel->relfilenode = newRelFileNode; + CatalogTupleUpdate(pg_class, &tuple->t_self, tuple); + + /* + * Record dependency on tablespace. This is only required for relations + * that have no physical storage. + */ + if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind)) + changeDependencyOnTablespace(RelationRelationId, reloid, + rd_rel->reltablespace); + + heap_freetuple(tuple); + table_close(pg_class, RowExclusiveLock); +} + /* * renameatt_check - basic sanity checks before attribute rename */ @@ -13160,13 +13267,9 @@ static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode) { Relation rel; - Oid oldTableSpace; Oid reltoastrelid; Oid newrelfilenode; RelFileNode newrnode; - Relation pg_class; - HeapTuple tuple; - Form_pg_class rd_rel; List *reltoastidxids = NIL; ListCell *lc; @@ -13175,45 +13278,15 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode) */ rel = relation_open(tableOid, lockmode); - /* - * No work if no change in tablespace. - */ - oldTableSpace = rel->rd_rel->reltablespace; - if (newTableSpace == oldTableSpace || - (newTableSpace == MyDatabaseTableSpace && oldTableSpace == 0)) + /* Check first if relation can be moved to new tablespace */ + if (!CheckRelationTableSpaceMove(rel, newTableSpace)) { InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0); - relation_close(rel, NoLock); return; } - /* - * We cannot support moving mapped relations into different tablespaces. - * (In particular this eliminates all shared catalogs.) - */ - if (RelationIsMapped(rel)) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot move system relation \"%s\"", - RelationGetRelationName(rel)))); - - /* Can't move a non-shared relation into pg_global */ - if (newTableSpace == GLOBALTABLESPACE_OID) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("only shared relations can be placed in pg_global tablespace"))); - - /* - * Don't allow moving temp tables of other backends ... their local buffer - * manager is not going to cope. - */ - if (RELATION_IS_OTHER_TEMP(rel)) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot move temporary tables of other sessions"))); - reltoastrelid = rel->rd_rel->reltoastrelid; /* Fetch the list of indexes on toast relation if necessary */ if (OidIsValid(reltoastrelid)) @@ -13224,14 +13297,6 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode) relation_close(toastRel, lockmode); } - /* Get a modifiable copy of the relation's pg_class row */ - pg_class = table_open(RelationRelationId, RowExclusiveLock); - - tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(tableOid)); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for relation %u", tableOid); - rd_rel = (Form_pg_class) GETSTRUCT(tuple); - /* * Relfilenodes are not unique in databases across tablespaces, so we need * to allocate a new one in the new tablespace. @@ -13262,18 +13327,13 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode) * * NB: This wouldn't work if ATExecSetTableSpace() were allowed to be * executed on pg_class or its indexes (the above copy wouldn't contain - * the updated pg_class entry), but that's forbidden above. + * the updated pg_class entry), but that's forbidden with + * CheckRelationTableSpaceMove(). */ - rd_rel->reltablespace = (newTableSpace == MyDatabaseTableSpace) ? InvalidOid : newTableSpace; - rd_rel->relfilenode = newrelfilenode; - CatalogTupleUpdate(pg_class, &tuple->t_self, tuple); + SetRelationTableSpace(rel, newTableSpace, newrelfilenode); InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0); - heap_freetuple(tuple); - - table_close(pg_class, RowExclusiveLock); - RelationAssumeNewRelfilenode(rel); relation_close(rel, NoLock); @@ -13301,56 +13361,25 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode) static void ATExecSetTableSpaceNoStorage(Relation rel, Oid newTableSpace) { - HeapTuple tuple; - Oid oldTableSpace; - Relation pg_class; - Form_pg_class rd_rel; - Oid reloid = RelationGetRelid(rel); - /* * Shouldn't be called on relations having storage; these are processed in * phase 3. */ Assert(!RELKIND_HAS_STORAGE(rel->rd_rel->relkind)); - /* Can't allow a non-shared relation in pg_global */ - if (newTableSpace == GLOBALTABLESPACE_OID) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("only shared relations can be placed in pg_global tablespace"))); - - /* - * No work if no change in tablespace. - */ - oldTableSpace = rel->rd_rel->reltablespace; - if (newTableSpace == oldTableSpace || - (newTableSpace == MyDatabaseTableSpace && oldTableSpace == 0)) + /* check if relation can be moved to its new tablespace */ + if (!CheckRelationTableSpaceMove(rel, newTableSpace)) { - InvokeObjectPostAlterHook(RelationRelationId, reloid, 0); + InvokeObjectPostAlterHook(RelationRelationId, + RelationGetRelid(rel), + 0); return; } - /* Get a modifiable copy of the relation's pg_class row */ - pg_class = table_open(RelationRelationId, RowExclusiveLock); - - tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid)); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for relation %u", reloid); - rd_rel = (Form_pg_class) GETSTRUCT(tuple); - - /* update the pg_class row */ - rd_rel->reltablespace = (newTableSpace == MyDatabaseTableSpace) ? InvalidOid : newTableSpace; - CatalogTupleUpdate(pg_class, &tuple->t_self, tuple); - - /* Record dependency on tablespace */ - changeDependencyOnTablespace(RelationRelationId, - reloid, rd_rel->reltablespace); - - InvokeObjectPostAlterHook(RelationRelationId, reloid, 0); + /* Update can be done, so change reltablespace */ + SetRelationTableSpace(rel, newTableSpace, InvalidOid); - heap_freetuple(tuple); - - table_close(pg_class, RowExclusiveLock); + InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0); /* Make sure the reltablespace change is visible */ CommandCounterIncrement(); diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h index 08c463d3c431d..b3d30acc3596d 100644 --- a/src/include/commands/tablecmds.h +++ b/src/include/commands/tablecmds.h @@ -61,6 +61,10 @@ extern void ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_ extern void SetRelationHasSubclass(Oid relationId, bool relhassubclass); +extern bool CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId); +extern void SetRelationTableSpace(Relation rel, Oid newTableSpaceId, + Oid newRelFileNode); + extern ObjectAddress renameatt(RenameStmt *stmt); extern ObjectAddress RenameConstraint(RenameStmt *stmt); From 32bef758296142ce0fff944c3478d63fdefdaf33 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Wed, 27 Jan 2021 13:40:33 +0900 Subject: [PATCH 186/240] doc: Remove reference to views for TRUNCATE privilege The page about privilege rights mentioned that TRUNCATE could be applied to views or even other relation types. This is confusing as this command can be used only on tables and on partitioned tables. Oversight in afc4a78. Reported-by: Harisai Hari Reviewed-by: Laurenz Albe Discussion: https://postgr.es/m/161157636877.14625.15340884663716426087@wrigleys.postgresql.org Backpatch-through: 12 --- doc/src/sgml/ddl.sgml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml index c12a32c8c7f02..02d2f42865172 100644 --- a/doc/src/sgml/ddl.sgml +++ b/doc/src/sgml/ddl.sgml @@ -1740,7 +1740,7 @@ REVOKE ALL ON accounts FROM PUBLIC; TRUNCATE - Allows TRUNCATE on a table, view, etc. + Allows TRUNCATE on a table. From e42b3c3bd6a9c6233ac4c8a2e9b040367ba2f97c Mon Sep 17 00:00:00 2001 From: Peter Geoghegan Date: Tue, 26 Jan 2021 23:24:37 -0800 Subject: [PATCH 187/240] Fix GiST index deletion assert issue. Avoid calling heap_index_delete_tuples() with an empty deltids array to avoid an assertion failure. This issue was arguably an oversight in commit b5f58cf2, though the failing assert itself was added by my recent commit d168b666. No backpatch, though, since the oversight is harmless in the back branches. Author: Peter Geoghegan Reported-By: Jaime Casanova Discussion: https://postgr.es/m/CAJKUy5jscES84n3puE=sYngyF+zpb4wv8UMtuLnLPv5z=6yyNw@mail.gmail.com --- src/backend/access/gist/gist.c | 13 +++++++------ src/backend/access/index/genam.c | 2 ++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index f203bb594cdb9..0683f42c25883 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -1645,7 +1645,6 @@ gistprunepage(Relation rel, Page page, Buffer buffer, Relation heapRel) int ndeletable = 0; OffsetNumber offnum, maxoff; - TransactionId latestRemovedXid = InvalidTransactionId; Assert(GistPageIsLeaf(page)); @@ -1664,13 +1663,15 @@ gistprunepage(Relation rel, Page page, Buffer buffer, Relation heapRel) deletable[ndeletable++] = offnum; } - if (XLogStandbyInfoActive() && RelationNeedsWAL(rel)) - latestRemovedXid = - index_compute_xid_horizon_for_tuples(rel, heapRel, buffer, - deletable, ndeletable); - if (ndeletable > 0) { + TransactionId latestRemovedXid = InvalidTransactionId; + + if (XLogStandbyInfoActive() && RelationNeedsWAL(rel)) + latestRemovedXid = + index_compute_xid_horizon_for_tuples(rel, heapRel, buffer, + deletable, ndeletable); + START_CRIT_SECTION(); PageIndexMultiDelete(page, deletable, ndeletable); diff --git a/src/backend/access/index/genam.c b/src/backend/access/index/genam.c index c911c705ba62f..1c3e937c61534 100644 --- a/src/backend/access/index/genam.c +++ b/src/backend/access/index/genam.c @@ -301,6 +301,8 @@ index_compute_xid_horizon_for_tuples(Relation irel, Page ipage = BufferGetPage(ibuf); IndexTuple itup; + Assert(nitems > 0); + delstate.bottomup = false; delstate.bottomupfreespace = 0; delstate.ndeltids = 0; From 1f113abdf87cd085dee3927960bb4f70442b7250 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Wed, 27 Jan 2021 12:20:46 -0500 Subject: [PATCH 188/240] Move StartupCLOG() calls to just after we initialize ShmemVariableCache. Previously, the hot_standby=off code path did this at end of recovery, while the hot_standby=on code path did it at the beginning of recovery. It's better to do this in only one place because (a) it's simpler, (b) StartupCLOG() is trivial so trying to postpone the work isn't useful, and (c) this will make it possible to simplify some other logic. Patch by me, reviewed by Heikki Linnakangas. Discussion: http://postgr.es/m/CA+TgmoZYig9+AQodhF5sRXuKkJ=RgFDugLr3XX_dz_F-p=TwTg@mail.gmail.com --- src/backend/access/transam/xlog.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index cc007b8963ef3..236a66f63875a 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -6855,6 +6855,13 @@ StartupXLOG(void) */ StartupReorderBuffer(); + /* + * Startup CLOG. This must be done after ShmemVariableCache->nextXid + * has been initialized and before we accept connections or begin WAL + * replay. + */ + StartupCLOG(); + /* * Startup MultiXact. We need to do this early to be able to replay * truncations. @@ -7125,11 +7132,10 @@ StartupXLOG(void) ProcArrayInitRecovery(XidFromFullTransactionId(ShmemVariableCache->nextXid)); /* - * Startup commit log and subtrans only. MultiXact and commit + * Startup subtrans only. CLOG, MultiXact and commit * timestamp have already been started up and other SLRUs are not * maintained during recovery and need not be started yet. */ - StartupCLOG(); StartupSUBTRANS(oldestActiveXID); /* @@ -7945,14 +7951,11 @@ StartupXLOG(void) LWLockRelease(ProcArrayLock); /* - * Start up the commit log and subtrans, if not already done for hot - * standby. (commit timestamps are started below, if necessary.) + * Start up subtrans, if not already done for hot standby. (commit + * timestamps are started below, if necessary.) */ if (standbyState == STANDBY_DISABLED) - { - StartupCLOG(); StartupSUBTRANS(oldestActiveXID); - } /* * Perform end of recovery actions for any SLRUs that need it. From 662affcfe9e816584e3d8602b3b4005236931bbb Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 27 Jan 2021 12:50:17 -0500 Subject: [PATCH 189/240] Doc: improve documentation for UNNEST(). Per a user question, spell out that UNNEST() returns array elements in storage order; also provide an example to clarify the behavior for multi-dimensional arrays. While here, also clarify the SELECT reference page's description of WITH ORDINALITY. These details were already given in 7.2.1.4, but a reference page should not omit details. Back-patch to v13; there's not room in the table in older versions. Discussion: https://postgr.es/m/FF1FB31F-0507-4F18-9559-2DE6E07E3B43@gmail.com --- doc/src/sgml/func.sgml | 19 +++++++++++++++---- doc/src/sgml/ref/select.sgml | 17 ++++++++++++----- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index aa99665e2eb79..4342c8e74fd1f 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -17905,7 +17905,8 @@ SELECT NULLIF(value, '(none)') ... setof anyelement - Expands an array to a set of rows. + Expands an array into a set of rows. + The array's elements are read out in storage order. unnest(ARRAY[1,2]) @@ -17913,6 +17914,16 @@ SELECT NULLIF(value, '(none)') ... 1 2 + + + + unnest(ARRAY[['foo','bar'],['baz','quux']]) + + + foo + bar + baz + quux @@ -17923,10 +17934,10 @@ SELECT NULLIF(value, '(none)') ... setof anyelement, anyelement [, ... ] - Expands multiple arrays (possibly of different data types) to a set of + Expands multiple arrays (possibly of different data types) into a set of rows. If the arrays are not all the same length then the shorter ones - are padded with NULLs. This is only allowed in a - query's FROM clause; see . + are padded with NULLs. This form is only allowed + in a query's FROM clause; see . select * from unnest(ARRAY[1,2], ARRAY['foo','bar','baz']) as x(a,b) diff --git a/doc/src/sgml/ref/select.sgml b/doc/src/sgml/ref/select.sgml index 6757033e096b8..c48ff6bc7e8ce 100644 --- a/doc/src/sgml/ref/select.sgml +++ b/doc/src/sgml/ref/select.sgml @@ -476,9 +476,17 @@ TABLE [ ONLY ] table_name [ * ] result sets, but any function can be used.) This acts as though the function's output were created as a temporary table for the duration of this single SELECT command. - When the optional WITH ORDINALITY clause is - added to the function call, a new column is appended after - all the function's output columns with numbering for each row. + If the function's result type is composite (including the case of a + function with multiple OUT parameters), each + attribute becomes a separate column in the implicit table. + + + + When the optional WITH ORDINALITY clause is added + to the function call, an additional column of type bigint + will be appended to the function's result column(s). This column + numbers the rows of the function's result set, starting from 1. + By default, this column is named ordinality. @@ -486,8 +494,7 @@ TABLE [ ONLY ] table_name [ * ] If an alias is written, a column alias list can also be written to provide substitute names for one or more attributes of the function's composite return - type, including the column added by ORDINALITY - if present. + type, including the ordinality column if present. From 0fcc2decd485a61321a3220d8f76cb108b082009 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Wed, 27 Jan 2021 13:07:41 -0500 Subject: [PATCH 190/240] In clog_redo(), don't set XactCtl->shared->latest_page_number. The comment is no longer accurate, and hasn't been entirely accurate since Hot Standby was introduced. The original idea here was that StartupCLOG() wouldn't be called until the end of recovery and therefore this value would be uninitialized when this code is reached, but Hot Standby made that true only when hot_standby=off, and commit 1f113abdf87cd085dee3927960bb4f70442b7250 means that this value is now always initialized before replay even starts. The original purpose of this code was to bypass the sanity check in SimpleLruTruncate(), which will no longer occur: now, if something is wrong, that sanity check might trip during recovery. That's probably a good thing, because in the current code base latest_page_number should always be initialized and therefore we expect that the sanity check should pass. If it doesn't, something has gone wrong, and complaining about it is appropriate. Patch by me, reviewed by Heikki Linnakangas. Discussion: http://postgr.es/m/CA+TgmoZYig9+AQodhF5sRXuKkJ=RgFDugLr3XX_dz_F-p=TwTg@mail.gmail.com --- src/backend/access/transam/clog.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c index 410d02a3943da..5ae962b86e115 100644 --- a/src/backend/access/transam/clog.c +++ b/src/backend/access/transam/clog.c @@ -1011,12 +1011,6 @@ clog_redo(XLogReaderState *record) memcpy(&xlrec, XLogRecGetData(record), sizeof(xl_clog_truncate)); - /* - * During XLOG replay, latest_page_number isn't set up yet; insert a - * suitable value to bypass the sanity test in SimpleLruTruncate. - */ - XactCtl->shared->latest_page_number = xlrec.pageno; - AdvanceOldestClogXid(xlrec.oldestXact); SimpleLruTruncate(XactCtl, xlrec.pageno); From 69059d3b2f0754c8e661ba479f7121e6631cdf4a Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Wed, 27 Jan 2021 15:52:34 -0500 Subject: [PATCH 191/240] In TrimCLOG(), don't reset XactCtl->shared->latest_page_number. Since the CLOG page number is not recorded directly in the checkpoint record, we have to use ShmemVariableCache->nextXid to figure out the latest CLOG page number at the start of recovery. However, as recovery progresses, replay of CLOG/EXTEND records will update our notion of the latest page number, and we should rely on that being accurate rather than recomputing the value based on an updated notion of nextXid. ShmemVariableCache->nextXid is only an approximation during recovery anyway, whereas CLOG/EXTEND records are an authoritative representation of how the SLRU has been updated. Commit 0fcc2decd485a61321a3220d8f76cb108b082009 makes this simplification possible, as before that change clog_redo() might have injected a bogus value here, and we'd want to get rid of that before entering normal running. Patch by me, reviewed by Heikki Linnakangas. Discussion: http://postgr.es/m/CA+TgmoZYig9+AQodhF5sRXuKkJ=RgFDugLr3XX_dz_F-p=TwTg@mail.gmail.com --- src/backend/access/transam/clog.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c index 5ae962b86e115..6fa4713fb4d8a 100644 --- a/src/backend/access/transam/clog.c +++ b/src/backend/access/transam/clog.c @@ -773,11 +773,6 @@ TrimCLOG(void) LWLockAcquire(XactSLRULock, LW_EXCLUSIVE); - /* - * Re-Initialize our idea of the latest page number. - */ - XactCtl->shared->latest_page_number = pageno; - /* * Zero out the remainder of the current clog page. Under normal * circumstances it should be zeroes already, but it seems at least From e19594c5c059d2e071b67d87ae84f569a52d2e32 Mon Sep 17 00:00:00 2001 From: Peter Geoghegan Date: Wed, 27 Jan 2021 15:11:13 -0800 Subject: [PATCH 192/240] Reduce the default value of vacuum_cost_page_miss. When commit f425b605 introduced cost based vacuum delays back in 2004, the defaults reflected then-current trends in hardware, as well as certain historical limitations in PostgreSQL. There have been enormous improvements in both areas since that time. The cost limit GUC defaults finally became much more representative of current trends following commit cbccac37, which decreased autovacuum_vacuum_cost_delay's default by 10x for PostgreSQL 12 (it went from 20ms to only 2ms). The relative costs have shifted too. This should also be accounted for by the defaults. More specifically, the relative importance of avoiding dirtying pages within VACUUM has greatly increased, primarily due to main memory capacity scaling and trends in flash storage. Within Postgres itself, improvements like sequential access during index vacuuming (at least in nbtree and GiST indexes) have also been contributing factors. To reflect all this, decrease the default of vacuum_cost_page_miss to 2. Since the default of vacuum_cost_page_dirty remains 20, dirtying a page is now considered 10x "costlier" than a page miss by default. Author: Peter Geoghegan Discussion: https://postgr.es/m/CAH2-WzmLPFnkWT8xMjmcsm7YS3+_Qi3iRWAb2+_Bc8UhVyHfuA@mail.gmail.com --- doc/src/sgml/config.sgml | 2 +- src/backend/utils/init/globals.c | 2 +- src/backend/utils/misc/guc.c | 2 +- src/backend/utils/misc/postgresql.conf.sample | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 82864bbb247f5..f1037df5a98e4 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -2116,7 +2116,7 @@ include_dir 'conf.d' The estimated cost for vacuuming a buffer that has to be read from disk. This represents the effort to lock the buffer pool, lookup the shared hash table, read the desired block in from - the disk and scan its content. The default value is 10. + the disk and scan its content. The default value is 2. diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c index ea28769d6a396..a5976ad5b11a8 100644 --- a/src/backend/utils/init/globals.c +++ b/src/backend/utils/init/globals.c @@ -137,7 +137,7 @@ int max_parallel_workers = 8; int MaxBackends = 0; int VacuumCostPageHit = 1; /* GUC parameters for vacuum */ -int VacuumCostPageMiss = 10; +int VacuumCostPageMiss = 2; int VacuumCostPageDirty = 20; int VacuumCostLimit = 200; double VacuumCostDelay = 0; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 17579eeaca9c6..eafdb1118ed57 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -2413,7 +2413,7 @@ static struct config_int ConfigureNamesInt[] = NULL }, &VacuumCostPageMiss, - 10, 0, 10000, + 2, 0, 10000, NULL, NULL, NULL }, diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 8930a94fff5a5..bd57e917e16ed 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -164,7 +164,7 @@ #vacuum_cost_delay = 0 # 0-100 milliseconds (0 disables) #vacuum_cost_page_hit = 1 # 0-10000 credits -#vacuum_cost_page_miss = 10 # 0-10000 credits +#vacuum_cost_page_miss = 2 # 0-10000 credits #vacuum_cost_page_dirty = 20 # 0-10000 credits #vacuum_cost_limit = 200 # 1-10000 credits From f854c69a5b36ba7aa85bee9e9590c3e517970156 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Thu, 28 Jan 2021 16:13:26 +0900 Subject: [PATCH 193/240] Refactor SQL functions of SHA-2 in cryptohashfuncs.c The same code pattern was repeated four times when compiling a SHA-2 hash. This refactoring has the advantage to issue a compilation warning if a new value is added to pg_cryptohash_type, so as anybody doing an addition in this area would need to consider if support for a new SQL function is needed or not. Author: Sehrope Sarkuni, Michael Paquier Discussion: https://postgr.es/m/YA7DvLRn2xnTgsMc@paquier.xyz --- src/backend/utils/adt/cryptohashfuncs.c | 138 ++++++++++-------------- 1 file changed, 54 insertions(+), 84 deletions(-) diff --git a/src/backend/utils/adt/cryptohashfuncs.c b/src/backend/utils/adt/cryptohashfuncs.c index d99485f4c6dd4..152adcbfb4ad0 100644 --- a/src/backend/utils/adt/cryptohashfuncs.c +++ b/src/backend/utils/adt/cryptohashfuncs.c @@ -68,65 +68,77 @@ md5_bytea(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(cstring_to_text(hexsum)); } - /* - * SHA-2 variants + * Internal routine to compute a cryptohash with the given bytea input. */ - -Datum -sha224_bytea(PG_FUNCTION_ARGS) +static inline bytea * +cryptohash_internal(pg_cryptohash_type type, bytea *input) { - bytea *in = PG_GETARG_BYTEA_PP(0); const uint8 *data; + const char *typestr = NULL; + int digest_len = 0; size_t len; pg_cryptohash_ctx *ctx; - unsigned char buf[PG_SHA224_DIGEST_LENGTH]; bytea *result; - len = VARSIZE_ANY_EXHDR(in); - data = (unsigned char *) VARDATA_ANY(in); - - ctx = pg_cryptohash_create(PG_SHA224); + switch (type) + { + case PG_SHA224: + typestr = "SHA224"; + digest_len = PG_SHA224_DIGEST_LENGTH; + break; + case PG_SHA256: + typestr = "SHA256"; + digest_len = PG_SHA256_DIGEST_LENGTH; + break; + case PG_SHA384: + typestr = "SHA384"; + digest_len = PG_SHA384_DIGEST_LENGTH; + break; + case PG_SHA512: + typestr = "SHA512"; + digest_len = PG_SHA512_DIGEST_LENGTH; + break; + case PG_MD5: + case PG_SHA1: + elog(ERROR, "unsupported cryptohash type %d", type); + break; + } + + result = palloc0(digest_len + VARHDRSZ); + len = VARSIZE_ANY_EXHDR(input); + data = (unsigned char *) VARDATA_ANY(input); + + ctx = pg_cryptohash_create(type); if (pg_cryptohash_init(ctx) < 0) - elog(ERROR, "could not initialize %s context", "SHA224"); + elog(ERROR, "could not initialize %s context", typestr); if (pg_cryptohash_update(ctx, data, len) < 0) - elog(ERROR, "could not update %s context", "SHA224"); - if (pg_cryptohash_final(ctx, buf) < 0) - elog(ERROR, "could not finalize %s context", "SHA224"); + elog(ERROR, "could not update %s context", typestr); + if (pg_cryptohash_final(ctx, (unsigned char *) VARDATA(result)) < 0) + elog(ERROR, "could not finalize %s context", typestr); pg_cryptohash_free(ctx); - result = palloc(sizeof(buf) + VARHDRSZ); - SET_VARSIZE(result, sizeof(buf) + VARHDRSZ); - memcpy(VARDATA(result), buf, sizeof(buf)); + SET_VARSIZE(result, digest_len + VARHDRSZ); - PG_RETURN_BYTEA_P(result); + return result; } +/* + * SHA-2 variants + */ + Datum -sha256_bytea(PG_FUNCTION_ARGS) +sha224_bytea(PG_FUNCTION_ARGS) { - bytea *in = PG_GETARG_BYTEA_PP(0); - const uint8 *data; - size_t len; - pg_cryptohash_ctx *ctx; - unsigned char buf[PG_SHA256_DIGEST_LENGTH]; - bytea *result; + bytea *result = cryptohash_internal(PG_SHA224, PG_GETARG_BYTEA_PP(0)); - len = VARSIZE_ANY_EXHDR(in); - data = (unsigned char *) VARDATA_ANY(in); - - ctx = pg_cryptohash_create(PG_SHA256); - if (pg_cryptohash_init(ctx) < 0) - elog(ERROR, "could not initialize %s context", "SHA256"); - if (pg_cryptohash_update(ctx, data, len) < 0) - elog(ERROR, "could not update %s context", "SHA256"); - if (pg_cryptohash_final(ctx, buf) < 0) - elog(ERROR, "could not finalize %s context", "SHA256"); - pg_cryptohash_free(ctx); + PG_RETURN_BYTEA_P(result); +} - result = palloc(sizeof(buf) + VARHDRSZ); - SET_VARSIZE(result, sizeof(buf) + VARHDRSZ); - memcpy(VARDATA(result), buf, sizeof(buf)); +Datum +sha256_bytea(PG_FUNCTION_ARGS) +{ + bytea *result = cryptohash_internal(PG_SHA256, PG_GETARG_BYTEA_PP(0)); PG_RETURN_BYTEA_P(result); } @@ -134,28 +146,7 @@ sha256_bytea(PG_FUNCTION_ARGS) Datum sha384_bytea(PG_FUNCTION_ARGS) { - bytea *in = PG_GETARG_BYTEA_PP(0); - const uint8 *data; - size_t len; - pg_cryptohash_ctx *ctx; - unsigned char buf[PG_SHA384_DIGEST_LENGTH]; - bytea *result; - - len = VARSIZE_ANY_EXHDR(in); - data = (unsigned char *) VARDATA_ANY(in); - - ctx = pg_cryptohash_create(PG_SHA384); - if (pg_cryptohash_init(ctx) < 0) - elog(ERROR, "could not initialize %s context", "SHA384"); - if (pg_cryptohash_update(ctx, data, len) < 0) - elog(ERROR, "could not update %s context", "SHA384"); - if (pg_cryptohash_final(ctx, buf) < 0) - elog(ERROR, "could not finalize %s context", "SHA384"); - pg_cryptohash_free(ctx); - - result = palloc(sizeof(buf) + VARHDRSZ); - SET_VARSIZE(result, sizeof(buf) + VARHDRSZ); - memcpy(VARDATA(result), buf, sizeof(buf)); + bytea *result = cryptohash_internal(PG_SHA384, PG_GETARG_BYTEA_PP(0)); PG_RETURN_BYTEA_P(result); } @@ -163,28 +154,7 @@ sha384_bytea(PG_FUNCTION_ARGS) Datum sha512_bytea(PG_FUNCTION_ARGS) { - bytea *in = PG_GETARG_BYTEA_PP(0); - const uint8 *data; - size_t len; - pg_cryptohash_ctx *ctx; - unsigned char buf[PG_SHA512_DIGEST_LENGTH]; - bytea *result; - - len = VARSIZE_ANY_EXHDR(in); - data = (unsigned char *) VARDATA_ANY(in); - - ctx = pg_cryptohash_create(PG_SHA512); - if (pg_cryptohash_init(ctx) < 0) - elog(ERROR, "could not initialize %s context", "SHA512"); - if (pg_cryptohash_update(ctx, data, len) < 0) - elog(ERROR, "could not update %s context", "SHA512"); - if (pg_cryptohash_final(ctx, buf) < 0) - elog(ERROR, "could not finalize %s context", "SHA512"); - pg_cryptohash_free(ctx); - - result = palloc(sizeof(buf) + VARHDRSZ); - SET_VARSIZE(result, sizeof(buf) + VARHDRSZ); - memcpy(VARDATA(result), buf, sizeof(buf)); + bytea *result = cryptohash_internal(PG_SHA512, PG_GETARG_BYTEA_PP(0)); PG_RETURN_BYTEA_P(result); } From bca96ddab57c7c64ce442b0f9f35558741c7f8bd Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Thu, 28 Jan 2021 16:22:34 +0900 Subject: [PATCH 194/240] Fix crash of pg_stat_statements_info() without library loaded Other code paths are already protected against this case, and _PG_init() warns about that in pg_stat_statements.c. While on it, I have checked the other extensions of the tree but did not notice any holes. Oversight in 9fbc3f3. Author: Jaime Casanova Reviewed-by: Julien Rouhaud Discussion: https://postgr.es/m/CAJKUy5gF4=_=qhJ1VX_tSGFfjKHb9BvzhRYWSApJD=Bfwp2SBw@mail.gmail.com --- contrib/pg_stat_statements/pg_stat_statements.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c index 72a117fc19712..62cccbfa44dbd 100644 --- a/contrib/pg_stat_statements/pg_stat_statements.c +++ b/contrib/pg_stat_statements/pg_stat_statements.c @@ -1898,6 +1898,11 @@ pg_stat_statements_info(PG_FUNCTION_ARGS) Datum values[PG_STAT_STATEMENTS_INFO_COLS]; bool nulls[PG_STAT_STATEMENTS_INFO_COLS]; + if (!pgss || !pgss_hash) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("pg_stat_statements must be loaded via shared_preload_libraries"))); + /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); From a3367aa3c4552170004c92369681730d85e384c6 Mon Sep 17 00:00:00 2001 From: Andrew Gierth Date: Thu, 28 Jan 2021 10:53:10 +0000 Subject: [PATCH 195/240] Don't add bailout adjustment for non-strict deserialize calls. When building aggregate expression steps, strict checks need a bailout jump for when a null value is encountered, so there is a list of steps that require later adjustment. Adding entries to that list for steps that aren't actually strict would be harmless, except that there is an Assert which catches them. This leads to spurious errors on asserts builds, for data sets that trigger parallel aggregation of an aggregate with a non-strict deserialization function (no such aggregates exist in the core system). Repair by not adding the adjustment entry when it's not needed. Backpatch back to 11 where the code was introduced. Per a report from Darafei (Komzpa) of the PostGIS project; analysis and patch by me. Discussion: https://postgr.es/m/87mty7peb3.fsf@news-spur.riddles.org.uk --- src/backend/executor/execExpr.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c index 8fc2a2666bd80..2e463f5499052 100644 --- a/src/backend/executor/execExpr.c +++ b/src/backend/executor/execExpr.c @@ -3067,8 +3067,10 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, scratch.resnull = &trans_fcinfo->args[argno + 1].isnull; ExprEvalPushStep(state, &scratch); - adjust_bailout = lappend_int(adjust_bailout, - state->steps_len - 1); + /* don't add an adjustment unless the function is strict */ + if (pertrans->deserialfn.fn_strict) + adjust_bailout = lappend_int(adjust_bailout, + state->steps_len - 1); /* restore normal settings of scratch fields */ scratch.resvalue = &state->resvalue; From b80e10638e36b9d2f0b39170c613837af2ca2aac Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Thu, 28 Jan 2021 14:40:07 +0200 Subject: [PATCH 196/240] Add mbverifystr() functions specific to each encoding. This makes pg_verify_mbstr() function faster, by allowing more efficient encoding-specific implementations. All the implementations included in this commit are pretty naive, they just call the same encoding-specific verifychar functions that were used previously, but that already gives a performance boost because the tight character-at-a-time loop is simpler. Reviewed-by: John Naylor Discussion: https://www.postgresql.org/message-id/e7861509-3960-538a-9025-b75a61188e01@iki.fi --- src/backend/commands/extension.c | 2 +- src/backend/utils/mb/conv.c | 2 +- .../euc2004_sjis2004/euc2004_sjis2004.c | 4 +- .../euc_jp_and_sjis/euc_jp_and_sjis.c | 10 +- .../euc_kr_and_mic/euc_kr_and_mic.c | 4 +- .../euc_tw_and_big5/euc_tw_and_big5.c | 8 +- src/backend/utils/mb/mbutils.c | 31 +- src/common/wchar.c | 523 +++++++++++++++--- src/include/mb/pg_wchar.h | 10 +- 9 files changed, 493 insertions(+), 101 deletions(-) diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c index bac7a9e9b9a2d..19db329fe6f08 100644 --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -682,7 +682,7 @@ read_extension_script_file(const ExtensionControlFile *control, src_encoding = control->encoding; /* make sure that source string is valid in the expected encoding */ - pg_verify_mbstr_len(src_encoding, src_str, len, false); + (void) pg_verify_mbstr(src_encoding, src_str, len, false); /* * Convert the encoding to the database encoding. read_whole_file diff --git a/src/backend/utils/mb/conv.c b/src/backend/utils/mb/conv.c index f204f2abf463b..a07b54bd3b85c 100644 --- a/src/backend/utils/mb/conv.c +++ b/src/backend/utils/mb/conv.c @@ -653,7 +653,7 @@ LocalToUtf(const unsigned char *iso, int len, continue; } - l = pg_encoding_verifymb(encoding, (const char *) iso, len); + l = pg_encoding_verifymbchar(encoding, (const char *) iso, len); if (l < 0) break; diff --git a/src/backend/utils/mb/conversion_procs/euc2004_sjis2004/euc2004_sjis2004.c b/src/backend/utils/mb/conversion_procs/euc2004_sjis2004/euc2004_sjis2004.c index 138ae4635fe8e..4d7fb116cfdbf 100644 --- a/src/backend/utils/mb/conversion_procs/euc2004_sjis2004/euc2004_sjis2004.c +++ b/src/backend/utils/mb/conversion_procs/euc2004_sjis2004/euc2004_sjis2004.c @@ -87,7 +87,7 @@ euc_jis_20042shift_jis_2004(const unsigned char *euc, unsigned char *p, int len) continue; } - l = pg_encoding_verifymb(PG_EUC_JIS_2004, (const char *) euc, len); + l = pg_encoding_verifymbchar(PG_EUC_JIS_2004, (const char *) euc, len); if (l < 0) report_invalid_encoding(PG_EUC_JIS_2004, @@ -238,7 +238,7 @@ shift_jis_20042euc_jis_2004(const unsigned char *sjis, unsigned char *p, int len continue; } - l = pg_encoding_verifymb(PG_SHIFT_JIS_2004, (const char *) sjis, len); + l = pg_encoding_verifymbchar(PG_SHIFT_JIS_2004, (const char *) sjis, len); if (l < 0 || l > len) report_invalid_encoding(PG_SHIFT_JIS_2004, diff --git a/src/backend/utils/mb/conversion_procs/euc_jp_and_sjis/euc_jp_and_sjis.c b/src/backend/utils/mb/conversion_procs/euc_jp_and_sjis/euc_jp_and_sjis.c index e90363b7bfa1a..5059f917a9828 100644 --- a/src/backend/utils/mb/conversion_procs/euc_jp_and_sjis/euc_jp_and_sjis.c +++ b/src/backend/utils/mb/conversion_procs/euc_jp_and_sjis/euc_jp_and_sjis.c @@ -291,7 +291,7 @@ mic2sjis(const unsigned char *mic, unsigned char *p, int len) len--; continue; } - l = pg_encoding_verifymb(PG_MULE_INTERNAL, (const char *) mic, len); + l = pg_encoding_verifymbchar(PG_MULE_INTERNAL, (const char *) mic, len); if (l < 0) report_invalid_encoding(PG_MULE_INTERNAL, (const char *) mic, len); @@ -381,7 +381,7 @@ euc_jp2mic(const unsigned char *euc, unsigned char *p, int len) len--; continue; } - l = pg_encoding_verifymb(PG_EUC_JP, (const char *) euc, len); + l = pg_encoding_verifymbchar(PG_EUC_JP, (const char *) euc, len); if (l < 0) report_invalid_encoding(PG_EUC_JP, (const char *) euc, len); @@ -431,7 +431,7 @@ mic2euc_jp(const unsigned char *mic, unsigned char *p, int len) len--; continue; } - l = pg_encoding_verifymb(PG_MULE_INTERNAL, (const char *) mic, len); + l = pg_encoding_verifymbchar(PG_MULE_INTERNAL, (const char *) mic, len); if (l < 0) report_invalid_encoding(PG_MULE_INTERNAL, (const char *) mic, len); @@ -485,7 +485,7 @@ euc_jp2sjis(const unsigned char *euc, unsigned char *p, int len) len--; continue; } - l = pg_encoding_verifymb(PG_EUC_JP, (const char *) euc, len); + l = pg_encoding_verifymbchar(PG_EUC_JP, (const char *) euc, len); if (l < 0) report_invalid_encoding(PG_EUC_JP, (const char *) euc, len); @@ -580,7 +580,7 @@ sjis2euc_jp(const unsigned char *sjis, unsigned char *p, int len) len--; continue; } - l = pg_encoding_verifymb(PG_SJIS, (const char *) sjis, len); + l = pg_encoding_verifymbchar(PG_SJIS, (const char *) sjis, len); if (l < 0) report_invalid_encoding(PG_SJIS, (const char *) sjis, len); diff --git a/src/backend/utils/mb/conversion_procs/euc_kr_and_mic/euc_kr_and_mic.c b/src/backend/utils/mb/conversion_procs/euc_kr_and_mic/euc_kr_and_mic.c index d868a1ef3910d..ac823d6c27018 100644 --- a/src/backend/utils/mb/conversion_procs/euc_kr_and_mic/euc_kr_and_mic.c +++ b/src/backend/utils/mb/conversion_procs/euc_kr_and_mic/euc_kr_and_mic.c @@ -76,7 +76,7 @@ euc_kr2mic(const unsigned char *euc, unsigned char *p, int len) c1 = *euc; if (IS_HIGHBIT_SET(c1)) { - l = pg_encoding_verifymb(PG_EUC_KR, (const char *) euc, len); + l = pg_encoding_verifymbchar(PG_EUC_KR, (const char *) euc, len); if (l != 2) report_invalid_encoding(PG_EUC_KR, (const char *) euc, len); @@ -122,7 +122,7 @@ mic2euc_kr(const unsigned char *mic, unsigned char *p, int len) len--; continue; } - l = pg_encoding_verifymb(PG_MULE_INTERNAL, (const char *) mic, len); + l = pg_encoding_verifymbchar(PG_MULE_INTERNAL, (const char *) mic, len); if (l < 0) report_invalid_encoding(PG_MULE_INTERNAL, (const char *) mic, len); diff --git a/src/backend/utils/mb/conversion_procs/euc_tw_and_big5/euc_tw_and_big5.c b/src/backend/utils/mb/conversion_procs/euc_tw_and_big5/euc_tw_and_big5.c index 64455a5d9eb4f..db9deb653ba68 100644 --- a/src/backend/utils/mb/conversion_procs/euc_tw_and_big5/euc_tw_and_big5.c +++ b/src/backend/utils/mb/conversion_procs/euc_tw_and_big5/euc_tw_and_big5.c @@ -148,7 +148,7 @@ euc_tw2mic(const unsigned char *euc, unsigned char *p, int len) c1 = *euc; if (IS_HIGHBIT_SET(c1)) { - l = pg_encoding_verifymb(PG_EUC_TW, (const char *) euc, len); + l = pg_encoding_verifymbchar(PG_EUC_TW, (const char *) euc, len); if (l < 0) report_invalid_encoding(PG_EUC_TW, (const char *) euc, len); @@ -213,7 +213,7 @@ mic2euc_tw(const unsigned char *mic, unsigned char *p, int len) len--; continue; } - l = pg_encoding_verifymb(PG_MULE_INTERNAL, (const char *) mic, len); + l = pg_encoding_verifymbchar(PG_MULE_INTERNAL, (const char *) mic, len); if (l < 0) report_invalid_encoding(PG_MULE_INTERNAL, (const char *) mic, len); @@ -272,7 +272,7 @@ big52mic(const unsigned char *big5, unsigned char *p, int len) len--; continue; } - l = pg_encoding_verifymb(PG_BIG5, (const char *) big5, len); + l = pg_encoding_verifymbchar(PG_BIG5, (const char *) big5, len); if (l < 0) report_invalid_encoding(PG_BIG5, (const char *) big5, len); @@ -321,7 +321,7 @@ mic2big5(const unsigned char *mic, unsigned char *p, int len) len--; continue; } - l = pg_encoding_verifymb(PG_MULE_INTERNAL, (const char *) mic, len); + l = pg_encoding_verifymbchar(PG_MULE_INTERNAL, (const char *) mic, len); if (l < 0) report_invalid_encoding(PG_MULE_INTERNAL, (const char *) mic, len); diff --git a/src/backend/utils/mb/mbutils.c b/src/backend/utils/mb/mbutils.c index 3b7b13f9486a0..2578573b0ab13 100644 --- a/src/backend/utils/mb/mbutils.c +++ b/src/backend/utils/mb/mbutils.c @@ -519,7 +519,7 @@ pg_convert(PG_FUNCTION_ARGS) /* make sure that source string is valid */ len = VARSIZE_ANY_EXHDR(string); src_str = VARDATA_ANY(string); - pg_verify_mbstr_len(src_encoding, src_str, len, false); + (void) pg_verify_mbstr(src_encoding, src_str, len, false); /* perform conversion */ dest_str = (char *) pg_do_encoding_conversion((unsigned char *) unconstify(char *, src_str), @@ -1215,10 +1215,10 @@ static bool pg_generic_charinc(unsigned char *charptr, int len) { unsigned char *lastbyte = charptr + len - 1; - mbverifier mbverify; + mbchar_verifier mbverify; /* We can just invoke the character verifier directly. */ - mbverify = pg_wchar_table[GetDatabaseEncoding()].mbverify; + mbverify = pg_wchar_table[GetDatabaseEncoding()].mbverifychar; while (*lastbyte < (unsigned char) 255) { @@ -1445,8 +1445,7 @@ pg_database_encoding_max_length(void) bool pg_verifymbstr(const char *mbstr, int len, bool noError) { - return - pg_verify_mbstr_len(GetDatabaseEncoding(), mbstr, len, noError) >= 0; + return pg_verify_mbstr(GetDatabaseEncoding(), mbstr, len, noError); } /* @@ -1456,7 +1455,18 @@ pg_verifymbstr(const char *mbstr, int len, bool noError) bool pg_verify_mbstr(int encoding, const char *mbstr, int len, bool noError) { - return pg_verify_mbstr_len(encoding, mbstr, len, noError) >= 0; + int oklen; + + Assert(PG_VALID_ENCODING(encoding)); + + oklen = pg_wchar_table[encoding].mbverifystr((const unsigned char *) mbstr, len); + if (oklen != len) + { + if (noError) + return false; + report_invalid_encoding(encoding, mbstr + oklen, len - oklen); + } + return true; } /* @@ -1469,11 +1479,14 @@ pg_verify_mbstr(int encoding, const char *mbstr, int len, bool noError) * If OK, return length of string in the encoding. * If a problem is found, return -1 when noError is * true; when noError is false, ereport() a descriptive message. + * + * Note: We cannot use the faster encoding-specific mbverifystr() function + * here, because we need to count the number of characters in the string. */ int pg_verify_mbstr_len(int encoding, const char *mbstr, int len, bool noError) { - mbverifier mbverify; + mbchar_verifier mbverifychar; int mb_len; Assert(PG_VALID_ENCODING(encoding)); @@ -1493,7 +1506,7 @@ pg_verify_mbstr_len(int encoding, const char *mbstr, int len, bool noError) } /* fetch function pointer just once */ - mbverify = pg_wchar_table[encoding].mbverify; + mbverifychar = pg_wchar_table[encoding].mbverifychar; mb_len = 0; @@ -1516,7 +1529,7 @@ pg_verify_mbstr_len(int encoding, const char *mbstr, int len, bool noError) report_invalid_encoding(encoding, mbstr, len); } - l = (*mbverify) ((const unsigned char *) mbstr, len); + l = (*mbverifychar) ((const unsigned char *) mbstr, len); if (l < 0) { diff --git a/src/common/wchar.c b/src/common/wchar.c index 0d6d071658d59..6e7d731e020fe 100644 --- a/src/common/wchar.c +++ b/src/common/wchar.c @@ -19,9 +19,9 @@ * Operations on multi-byte encodings are driven by a table of helper * functions. * - * To add an encoding support, define mblen(), dsplen() and verifier() for - * the encoding. For server-encodings, also define mb2wchar() and wchar2mb() - * conversion functions. + * To add an encoding support, define mblen(), dsplen(), verifychar() and + * verifystr() for the encoding. For server-encodings, also define mb2wchar() + * and wchar2mb() conversion functions. * * These functions generally assume that their input is validly formed. * The "verifier" functions, further down in the file, have to be more @@ -1087,29 +1087,45 @@ pg_gb18030_dsplen(const unsigned char *s) *------------------------------------------------------------------- * multibyte sequence validators * - * These functions accept "s", a pointer to the first byte of a string, - * and "len", the remaining length of the string. If there is a validly - * encoded character beginning at *s, return its length in bytes; else - * return -1. + * The verifychar functions accept "s", a pointer to the first byte of a + * string, and "len", the remaining length of the string. If there is a + * validly encoded character beginning at *s, return its length in bytes; + * else return -1. * - * The functions can assume that len > 0 and that *s != '\0', but they must - * test for and reject zeroes in any additional bytes of a multibyte character. + * The verifystr functions also accept "s", a pointer to a string and "len", + * the length of the string. They verify the whole string, and return the + * number of input bytes (<= len) that are valid. In other words, if the + * whole string is valid, verifystr returns "len", otherwise it returns the + * byte offset of the first invalid character. The verifystr functions must + * test for and reject zeroes in the input. * - * Note that this definition allows the function for a single-byte - * encoding to be just "return 1". + * The verifychar functions can assume that len > 0 and that *s != '\0', but + * they must test for and reject zeroes in any additional bytes of a + * multibyte character. Note that this definition allows the function for a + * single-byte encoding to be just "return 1". *------------------------------------------------------------------- */ - static int -pg_ascii_verifier(const unsigned char *s, int len) +pg_ascii_verifychar(const unsigned char *s, int len) { return 1; } +static int +pg_ascii_verifystr(const unsigned char *s, int len) +{ + const unsigned char *nullpos = memchr(s, 0, len); + + if (nullpos == NULL) + return len; + else + return nullpos - s; +} + #define IS_EUC_RANGE_VALID(c) ((c) >= 0xa1 && (c) <= 0xfe) static int -pg_eucjp_verifier(const unsigned char *s, int len) +pg_eucjp_verifychar(const unsigned char *s, int len) { int l; unsigned char c1, @@ -1164,7 +1180,36 @@ pg_eucjp_verifier(const unsigned char *s, int len) } static int -pg_euckr_verifier(const unsigned char *s, int len) +pg_eucjp_verifystr(const unsigned char *s, int len) +{ + const unsigned char *start = s; + + while (len > 0) + { + int l; + + /* fast path for ASCII-subset characters */ + if (!IS_HIGHBIT_SET(*s)) + { + if (*s == '\0') + break; + l = 1; + } + else + { + l = pg_eucjp_verifychar(s, len); + if (l == -1) + break; + } + s += l; + len -= l; + } + + return s - start; +} + +static int +pg_euckr_verifychar(const unsigned char *s, int len) { int l; unsigned char c1, @@ -1192,11 +1237,41 @@ pg_euckr_verifier(const unsigned char *s, int len) return l; } +static int +pg_euckr_verifystr(const unsigned char *s, int len) +{ + const unsigned char *start = s; + + while (len > 0) + { + int l; + + /* fast path for ASCII-subset characters */ + if (!IS_HIGHBIT_SET(*s)) + { + if (*s == '\0') + break; + l = 1; + } + else + { + l = pg_euckr_verifychar(s, len); + if (l == -1) + break; + } + s += l; + len -= l; + } + + return s - start; +} + /* EUC-CN byte sequences are exactly same as EUC-KR */ -#define pg_euccn_verifier pg_euckr_verifier +#define pg_euccn_verifychar pg_euckr_verifychar +#define pg_euccn_verifystr pg_euckr_verifystr static int -pg_euctw_verifier(const unsigned char *s, int len) +pg_euctw_verifychar(const unsigned char *s, int len) { int l; unsigned char c1, @@ -1246,7 +1321,36 @@ pg_euctw_verifier(const unsigned char *s, int len) } static int -pg_johab_verifier(const unsigned char *s, int len) +pg_euctw_verifystr(const unsigned char *s, int len) +{ + const unsigned char *start = s; + + while (len > 0) + { + int l; + + /* fast path for ASCII-subset characters */ + if (!IS_HIGHBIT_SET(*s)) + { + if (*s == '\0') + break; + l = 1; + } + else + { + l = pg_euctw_verifychar(s, len); + if (l == -1) + break; + } + s += l; + len -= l; + } + + return s - start; +} + +static int +pg_johab_verifychar(const unsigned char *s, int len) { int l, mbl; @@ -1270,7 +1374,36 @@ pg_johab_verifier(const unsigned char *s, int len) } static int -pg_mule_verifier(const unsigned char *s, int len) +pg_johab_verifystr(const unsigned char *s, int len) +{ + const unsigned char *start = s; + + while (len > 0) + { + int l; + + /* fast path for ASCII-subset characters */ + if (!IS_HIGHBIT_SET(*s)) + { + if (*s == '\0') + break; + l = 1; + } + else + { + l = pg_johab_verifychar(s, len); + if (l == -1) + break; + } + s += l; + len -= l; + } + + return s - start; +} + +static int +pg_mule_verifychar(const unsigned char *s, int len) { int l, mbl; @@ -1291,13 +1424,53 @@ pg_mule_verifier(const unsigned char *s, int len) } static int -pg_latin1_verifier(const unsigned char *s, int len) +pg_mule_verifystr(const unsigned char *s, int len) +{ + const unsigned char *start = s; + + while (len > 0) + { + int l; + + /* fast path for ASCII-subset characters */ + if (!IS_HIGHBIT_SET(*s)) + { + if (*s == '\0') + break; + l = 1; + } + else + { + l = pg_mule_verifychar(s, len); + if (l == -1) + break; + } + s += l; + len -= l; + } + + return s - start; +} + +static int +pg_latin1_verifychar(const unsigned char *s, int len) { return 1; } static int -pg_sjis_verifier(const unsigned char *s, int len) +pg_latin1_verifystr(const unsigned char *s, int len) +{ + const unsigned char *nullpos = memchr(s, 0, len); + + if (nullpos == NULL) + return len; + else + return nullpos - s; +} + +static int +pg_sjis_verifychar(const unsigned char *s, int len) { int l, mbl; @@ -1320,7 +1493,36 @@ pg_sjis_verifier(const unsigned char *s, int len) } static int -pg_big5_verifier(const unsigned char *s, int len) +pg_sjis_verifystr(const unsigned char *s, int len) +{ + const unsigned char *start = s; + + while (len > 0) + { + int l; + + /* fast path for ASCII-subset characters */ + if (!IS_HIGHBIT_SET(*s)) + { + if (*s == '\0') + break; + l = 1; + } + else + { + l = pg_sjis_verifychar(s, len); + if (l == -1) + break; + } + s += l; + len -= l; + } + + return s - start; +} + +static int +pg_big5_verifychar(const unsigned char *s, int len) { int l, mbl; @@ -1340,7 +1542,36 @@ pg_big5_verifier(const unsigned char *s, int len) } static int -pg_gbk_verifier(const unsigned char *s, int len) +pg_big5_verifystr(const unsigned char *s, int len) +{ + const unsigned char *start = s; + + while (len > 0) + { + int l; + + /* fast path for ASCII-subset characters */ + if (!IS_HIGHBIT_SET(*s)) + { + if (*s == '\0') + break; + l = 1; + } + else + { + l = pg_big5_verifychar(s, len); + if (l == -1) + break; + } + s += l; + len -= l; + } + + return s - start; +} + +static int +pg_gbk_verifychar(const unsigned char *s, int len) { int l, mbl; @@ -1360,7 +1591,36 @@ pg_gbk_verifier(const unsigned char *s, int len) } static int -pg_uhc_verifier(const unsigned char *s, int len) +pg_gbk_verifystr(const unsigned char *s, int len) +{ + const unsigned char *start = s; + + while (len > 0) + { + int l; + + /* fast path for ASCII-subset characters */ + if (!IS_HIGHBIT_SET(*s)) + { + if (*s == '\0') + break; + l = 1; + } + else + { + l = pg_gbk_verifychar(s, len); + if (l == -1) + break; + } + s += l; + len -= l; + } + + return s - start; +} + +static int +pg_uhc_verifychar(const unsigned char *s, int len) { int l, mbl; @@ -1380,7 +1640,36 @@ pg_uhc_verifier(const unsigned char *s, int len) } static int -pg_gb18030_verifier(const unsigned char *s, int len) +pg_uhc_verifystr(const unsigned char *s, int len) +{ + const unsigned char *start = s; + + while (len > 0) + { + int l; + + /* fast path for ASCII-subset characters */ + if (!IS_HIGHBIT_SET(*s)) + { + if (*s == '\0') + break; + l = 1; + } + else + { + l = pg_uhc_verifychar(s, len); + if (l == -1) + break; + } + s += l; + len -= l; + } + + return s - start; +} + +static int +pg_gb18030_verifychar(const unsigned char *s, int len) { int l; @@ -1411,11 +1700,55 @@ pg_gb18030_verifier(const unsigned char *s, int len) } static int -pg_utf8_verifier(const unsigned char *s, int len) +pg_gb18030_verifystr(const unsigned char *s, int len) { - int l = pg_utf_mblen(s); + const unsigned char *start = s; - if (len < l) + while (len > 0) + { + int l; + + /* fast path for ASCII-subset characters */ + if (!IS_HIGHBIT_SET(*s)) + { + if (*s == '\0') + break; + l = 1; + } + else + { + l = pg_gb18030_verifychar(s, len); + if (l == -1) + break; + } + s += l; + len -= l; + } + + return s - start; +} + +static int +pg_utf8_verifychar(const unsigned char *s, int len) +{ + int l; + + if ((*s & 0x80) == 0) + { + if (*s == '\0') + return -1; + return 1; + } + else if ((*s & 0xe0) == 0xc0) + l = 2; + else if ((*s & 0xf0) == 0xe0) + l = 3; + else if ((*s & 0xf8) == 0xf0) + l = 4; + else + l = 1; + + if (l > len) return -1; if (!pg_utf8_islegal(s, l)) @@ -1424,6 +1757,35 @@ pg_utf8_verifier(const unsigned char *s, int len) return l; } +static int +pg_utf8_verifystr(const unsigned char *s, int len) +{ + const unsigned char *start = s; + + while (len > 0) + { + int l; + + /* fast path for ASCII-subset characters */ + if (!IS_HIGHBIT_SET(*s)) + { + if (*s == '\0') + break; + l = 1; + } + else + { + l = pg_utf8_verifychar(s, len); + if (l == -1) + break; + } + s += l; + len -= l; + } + + return s - start; +} + /* * Check for validity of a single UTF-8 encoded character * @@ -1503,48 +1865,48 @@ pg_utf8_islegal(const unsigned char *source, int length) *------------------------------------------------------------------- */ const pg_wchar_tbl pg_wchar_table[] = { - {pg_ascii2wchar_with_len, pg_wchar2single_with_len, pg_ascii_mblen, pg_ascii_dsplen, pg_ascii_verifier, 1}, /* PG_SQL_ASCII */ - {pg_eucjp2wchar_with_len, pg_wchar2euc_with_len, pg_eucjp_mblen, pg_eucjp_dsplen, pg_eucjp_verifier, 3}, /* PG_EUC_JP */ - {pg_euccn2wchar_with_len, pg_wchar2euc_with_len, pg_euccn_mblen, pg_euccn_dsplen, pg_euccn_verifier, 2}, /* PG_EUC_CN */ - {pg_euckr2wchar_with_len, pg_wchar2euc_with_len, pg_euckr_mblen, pg_euckr_dsplen, pg_euckr_verifier, 3}, /* PG_EUC_KR */ - {pg_euctw2wchar_with_len, pg_wchar2euc_with_len, pg_euctw_mblen, pg_euctw_dsplen, pg_euctw_verifier, 4}, /* PG_EUC_TW */ - {pg_eucjp2wchar_with_len, pg_wchar2euc_with_len, pg_eucjp_mblen, pg_eucjp_dsplen, pg_eucjp_verifier, 3}, /* PG_EUC_JIS_2004 */ - {pg_utf2wchar_with_len, pg_wchar2utf_with_len, pg_utf_mblen, pg_utf_dsplen, pg_utf8_verifier, 4}, /* PG_UTF8 */ - {pg_mule2wchar_with_len, pg_wchar2mule_with_len, pg_mule_mblen, pg_mule_dsplen, pg_mule_verifier, 4}, /* PG_MULE_INTERNAL */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN1 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN2 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN3 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN4 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN5 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN6 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN7 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN8 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN9 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN10 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1256 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1258 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN866 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN874 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_KOI8R */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1251 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1252 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* ISO-8859-5 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* ISO-8859-6 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* ISO-8859-7 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* ISO-8859-8 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1250 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1253 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1254 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1255 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1257 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_KOI8U */ - {0, 0, pg_sjis_mblen, pg_sjis_dsplen, pg_sjis_verifier, 2}, /* PG_SJIS */ - {0, 0, pg_big5_mblen, pg_big5_dsplen, pg_big5_verifier, 2}, /* PG_BIG5 */ - {0, 0, pg_gbk_mblen, pg_gbk_dsplen, pg_gbk_verifier, 2}, /* PG_GBK */ - {0, 0, pg_uhc_mblen, pg_uhc_dsplen, pg_uhc_verifier, 2}, /* PG_UHC */ - {0, 0, pg_gb18030_mblen, pg_gb18030_dsplen, pg_gb18030_verifier, 4}, /* PG_GB18030 */ - {0, 0, pg_johab_mblen, pg_johab_dsplen, pg_johab_verifier, 3}, /* PG_JOHAB */ - {0, 0, pg_sjis_mblen, pg_sjis_dsplen, pg_sjis_verifier, 2} /* PG_SHIFT_JIS_2004 */ + {pg_ascii2wchar_with_len, pg_wchar2single_with_len, pg_ascii_mblen, pg_ascii_dsplen, pg_ascii_verifychar, pg_ascii_verifystr, 1}, /* PG_SQL_ASCII */ + {pg_eucjp2wchar_with_len, pg_wchar2euc_with_len, pg_eucjp_mblen, pg_eucjp_dsplen, pg_eucjp_verifychar, pg_eucjp_verifystr, 3}, /* PG_EUC_JP */ + {pg_euccn2wchar_with_len, pg_wchar2euc_with_len, pg_euccn_mblen, pg_euccn_dsplen, pg_euccn_verifychar, pg_euccn_verifystr, 2}, /* PG_EUC_CN */ + {pg_euckr2wchar_with_len, pg_wchar2euc_with_len, pg_euckr_mblen, pg_euckr_dsplen, pg_euckr_verifychar, pg_euckr_verifystr, 3}, /* PG_EUC_KR */ + {pg_euctw2wchar_with_len, pg_wchar2euc_with_len, pg_euctw_mblen, pg_euctw_dsplen, pg_euctw_verifychar, pg_euctw_verifystr, 4}, /* PG_EUC_TW */ + {pg_eucjp2wchar_with_len, pg_wchar2euc_with_len, pg_eucjp_mblen, pg_eucjp_dsplen, pg_eucjp_verifychar, pg_eucjp_verifystr, 3}, /* PG_EUC_JIS_2004 */ + {pg_utf2wchar_with_len, pg_wchar2utf_with_len, pg_utf_mblen, pg_utf_dsplen, pg_utf8_verifychar, pg_utf8_verifystr, 4}, /* PG_UTF8 */ + {pg_mule2wchar_with_len, pg_wchar2mule_with_len, pg_mule_mblen, pg_mule_dsplen, pg_mule_verifychar, pg_mule_verifystr, 4}, /* PG_MULE_INTERNAL */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_LATIN1 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_LATIN2 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_LATIN3 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_LATIN4 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_LATIN5 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_LATIN6 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_LATIN7 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_LATIN8 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_LATIN9 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_LATIN10 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_WIN1256 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_WIN1258 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_WIN866 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_WIN874 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_KOI8R */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_WIN1251 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_WIN1252 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* ISO-8859-5 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* ISO-8859-6 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* ISO-8859-7 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* ISO-8859-8 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_WIN1250 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_WIN1253 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_WIN1254 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_WIN1255 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_WIN1257 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_KOI8U */ + {0, 0, pg_sjis_mblen, pg_sjis_dsplen, pg_sjis_verifychar, pg_sjis_verifystr, 2}, /* PG_SJIS */ + {0, 0, pg_big5_mblen, pg_big5_dsplen, pg_big5_verifychar, pg_big5_verifystr, 2}, /* PG_BIG5 */ + {0, 0, pg_gbk_mblen, pg_gbk_dsplen, pg_gbk_verifychar, pg_gbk_verifystr, 2}, /* PG_GBK */ + {0, 0, pg_uhc_mblen, pg_uhc_dsplen, pg_uhc_verifychar, pg_uhc_verifystr, 2}, /* PG_UHC */ + {0, 0, pg_gb18030_mblen, pg_gb18030_dsplen, pg_gb18030_verifychar, pg_gb18030_verifystr, 4}, /* PG_GB18030 */ + {0, 0, pg_johab_mblen, pg_johab_dsplen, pg_johab_verifychar, pg_johab_verifystr, 3}, /* PG_JOHAB */ + {0, 0, pg_sjis_mblen, pg_sjis_dsplen, pg_sjis_verifychar, pg_sjis_verifystr, 2} /* PG_SHIFT_JIS_2004 */ }; /* @@ -1572,14 +1934,27 @@ pg_encoding_dsplen(int encoding, const char *mbstr) /* * Verify the first multibyte character of the given string. * Return its byte length if good, -1 if bad. (See comments above for - * full details of the mbverify API.) + * full details of the mbverifychar API.) + */ +int +pg_encoding_verifymbchar(int encoding, const char *mbstr, int len) +{ + return (PG_VALID_ENCODING(encoding) ? + pg_wchar_table[encoding].mbverifychar((const unsigned char *) mbstr, len) : + pg_wchar_table[PG_SQL_ASCII].mbverifychar((const unsigned char *) mbstr, len)); +} + +/* + * Verify that a string is valid for the given encoding. + * Returns the number of input bytes (<= len) that form a valid string. + * (See comments above for full details of the mbverifystr API.) */ int -pg_encoding_verifymb(int encoding, const char *mbstr, int len) +pg_encoding_verifymbstr(int encoding, const char *mbstr, int len) { return (PG_VALID_ENCODING(encoding) ? - pg_wchar_table[encoding].mbverify((const unsigned char *) mbstr, len) : - pg_wchar_table[PG_SQL_ASCII].mbverify((const unsigned char *) mbstr, len)); + pg_wchar_table[encoding].mbverifystr((const unsigned char *) mbstr, len) : + pg_wchar_table[PG_SQL_ASCII].mbverifystr((const unsigned char *) mbstr, len)); } /* diff --git a/src/include/mb/pg_wchar.h b/src/include/mb/pg_wchar.h index 9fc5e67595788..64b22e4b0d461 100644 --- a/src/include/mb/pg_wchar.h +++ b/src/include/mb/pg_wchar.h @@ -371,7 +371,9 @@ typedef int (*mbdisplaylen_converter) (const unsigned char *mbstr); typedef bool (*mbcharacter_incrementer) (unsigned char *mbstr, int len); -typedef int (*mbverifier) (const unsigned char *mbstr, int len); +typedef int (*mbchar_verifier) (const unsigned char *mbstr, int len); + +typedef int (*mbstr_verifier) (const unsigned char *mbstr, int len); typedef struct { @@ -381,7 +383,8 @@ typedef struct * to a multibyte */ mblen_converter mblen; /* get byte length of a char */ mbdisplaylen_converter dsplen; /* get display width of a char */ - mbverifier mbverify; /* verify multibyte sequence */ + mbchar_verifier mbverifychar; /* verify multibyte character */ + mbstr_verifier mbverifystr; /* verify multibyte string */ int maxmblen; /* max bytes for a char in this encoding */ } pg_wchar_tbl; @@ -554,7 +557,8 @@ extern int pg_valid_server_encoding_id(int encoding); */ extern int pg_encoding_mblen(int encoding, const char *mbstr); extern int pg_encoding_dsplen(int encoding, const char *mbstr); -extern int pg_encoding_verifymb(int encoding, const char *mbstr, int len); +extern int pg_encoding_verifymbchar(int encoding, const char *mbstr, int len); +extern int pg_encoding_verifymbstr(int encoding, const char *mbstr, int len); extern int pg_encoding_max_length(int encoding); extern int pg_valid_client_encoding(const char *name); extern int pg_valid_server_encoding(const char *name); From 6c5576075b0f93f2235ac8a82290fe3b6e82300d Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Thu, 28 Jan 2021 14:53:03 +0200 Subject: [PATCH 197/240] Add direct conversion routines between EUC_TW and Big5. Conversions between EUC_TW and Big5 were previously implemented by converting the whole input to MIC first, and then from MIC to the target encoding. Implement functions to convert directly between the two. The reason to do this now is that I'm working on a patch that will change the conversion function signature so that if the input is invalid, we convert as much as we can and return the number of bytes successfully converted. That's not possible if we use an intermediary format, because if an error happens in the intermediary -> final conversion, we lose track of the location of the invalid character in the original input. Avoiding the intermediate step makes the conversions faster, too. Reviewed-by: John Naylor Discussion: https://www.postgresql.org/message-id/b9e3167f-f84b-7aa4-5738-be578a4db924%40iki.fi --- .../euc_tw_and_big5/euc_tw_and_big5.c | 144 ++++++++++++++++-- 1 file changed, 134 insertions(+), 10 deletions(-) diff --git a/src/backend/utils/mb/conversion_procs/euc_tw_and_big5/euc_tw_and_big5.c b/src/backend/utils/mb/conversion_procs/euc_tw_and_big5/euc_tw_and_big5.c index db9deb653ba68..66c242d7f3688 100644 --- a/src/backend/utils/mb/conversion_procs/euc_tw_and_big5/euc_tw_and_big5.c +++ b/src/backend/utils/mb/conversion_procs/euc_tw_and_big5/euc_tw_and_big5.c @@ -37,6 +37,8 @@ PG_FUNCTION_INFO_V1(mic_to_big5); * ---------- */ +static void euc_tw2big5(const unsigned char *euc, unsigned char *p, int len); +static void big52euc_tw(const unsigned char *euc, unsigned char *p, int len); static void big52mic(const unsigned char *big5, unsigned char *p, int len); static void mic2big5(const unsigned char *mic, unsigned char *p, int len); static void euc_tw2mic(const unsigned char *euc, unsigned char *p, int len); @@ -48,14 +50,10 @@ euc_tw_to_big5(PG_FUNCTION_ARGS) unsigned char *src = (unsigned char *) PG_GETARG_CSTRING(2); unsigned char *dest = (unsigned char *) PG_GETARG_CSTRING(3); int len = PG_GETARG_INT32(4); - unsigned char *buf; CHECK_ENCODING_CONVERSION_ARGS(PG_EUC_TW, PG_BIG5); - buf = palloc(len * ENCODING_GROWTH_RATE + 1); - euc_tw2mic(src, buf, len); - mic2big5(buf, dest, strlen((char *) buf)); - pfree(buf); + euc_tw2big5(src, dest, len); PG_RETURN_VOID(); } @@ -66,14 +64,10 @@ big5_to_euc_tw(PG_FUNCTION_ARGS) unsigned char *src = (unsigned char *) PG_GETARG_CSTRING(2); unsigned char *dest = (unsigned char *) PG_GETARG_CSTRING(3); int len = PG_GETARG_INT32(4); - unsigned char *buf; CHECK_ENCODING_CONVERSION_ARGS(PG_BIG5, PG_EUC_TW); - buf = palloc(len * ENCODING_GROWTH_RATE + 1); - big52mic(src, buf, len); - mic2euc_tw(buf, dest, strlen((char *) buf)); - pfree(buf); + big52euc_tw(src, dest, len); PG_RETURN_VOID(); } @@ -134,6 +128,136 @@ mic_to_big5(PG_FUNCTION_ARGS) PG_RETURN_VOID(); } + +/* + * EUC_TW ---> Big5 + */ +static void +euc_tw2big5(const unsigned char *euc, unsigned char *p, int len) +{ + unsigned char c1; + unsigned short big5buf, + cnsBuf; + unsigned char lc; + int l; + + while (len > 0) + { + c1 = *euc; + if (IS_HIGHBIT_SET(c1)) + { + /* Verify and decode the next EUC_TW input character */ + l = pg_encoding_verifymbchar(PG_EUC_TW, (const char *) euc, len); + if (l < 0) + report_invalid_encoding(PG_EUC_TW, + (const char *) euc, len); + if (c1 == SS2) + { + c1 = euc[1]; /* plane No. */ + if (c1 == 0xa1) + lc = LC_CNS11643_1; + else if (c1 == 0xa2) + lc = LC_CNS11643_2; + else + lc = c1 - 0xa3 + LC_CNS11643_3; + cnsBuf = (euc[2] << 8) | euc[3]; + } + else + { /* CNS11643-1 */ + lc = LC_CNS11643_1; + cnsBuf = (c1 << 8) | euc[1]; + } + + /* Write it out in Big5 */ + big5buf = CNStoBIG5(cnsBuf, lc); + if (big5buf == 0) + report_untranslatable_char(PG_EUC_TW, PG_BIG5, + (const char *) euc, len); + *p++ = (big5buf >> 8) & 0x00ff; + *p++ = big5buf & 0x00ff; + + euc += l; + len -= l; + } + else + { /* should be ASCII */ + if (c1 == 0) + report_invalid_encoding(PG_EUC_TW, + (const char *) euc, len); + *p++ = c1; + euc++; + len--; + } + } + *p = '\0'; +} + +/* + * Big5 ---> EUC_TW + */ +static void +big52euc_tw(const unsigned char *big5, unsigned char *p, int len) +{ + unsigned short c1; + unsigned short big5buf, + cnsBuf; + unsigned char lc; + int l; + + while (len > 0) + { + /* Verify and decode the next Big5 input character */ + c1 = *big5; + if (IS_HIGHBIT_SET(c1)) + { + l = pg_encoding_verifymbchar(PG_BIG5, (const char *) big5, len); + if (l < 0) + report_invalid_encoding(PG_BIG5, + (const char *) big5, len); + big5buf = (c1 << 8) | big5[1]; + cnsBuf = BIG5toCNS(big5buf, &lc); + + if (lc == LC_CNS11643_1) + { + *p++ = (cnsBuf >> 8) & 0x00ff; + *p++ = cnsBuf & 0x00ff; + } + else if (lc == LC_CNS11643_2) + { + *p++ = SS2; + *p++ = 0xa2; + *p++ = (cnsBuf >> 8) & 0x00ff; + *p++ = cnsBuf & 0x00ff; + } + else if (lc >= LC_CNS11643_3 && lc <= LC_CNS11643_7) + { + *p++ = SS2; + *p++ = lc - LC_CNS11643_3 + 0xa3; + *p++ = (cnsBuf >> 8) & 0x00ff; + *p++ = cnsBuf & 0x00ff; + } + else + report_untranslatable_char(PG_BIG5, PG_EUC_TW, + (const char *) big5, len); + + big5 += l; + len -= l; + } + else + { + /* ASCII */ + if (c1 == 0) + report_invalid_encoding(PG_BIG5, + (const char *) big5, len); + *p++ = c1; + big5++; + len--; + continue; + } + } + *p = '\0'; +} + /* * EUC_TW ---> MIC */ From b034ef9b376dbe712caa076541d6a750f37d85ce Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Thu, 28 Jan 2021 14:01:41 +0100 Subject: [PATCH 198/240] Remove gratuitous uses of deprecated SELECT INTO CREATE TABLE AS has been preferred over SELECT INTO (outside of ecpg and PL/pgSQL) for a long time. There were still a few uses of SELECT INTO in tests and documentation, some old, some more recent. This changes them to CREATE TABLE AS. Some occurrences in the tests remain where they are specifically testing SELECT INTO parsing or similar. Discussion: https://www.postgresql.org/message-id/flat/96dc0df3-e13a-a85d-d045-d6e2c85218da%40enterprisedb.com --- contrib/sepgsql/expected/label.out | 2 +- contrib/sepgsql/sql/label.sql | 2 +- doc/src/sgml/hstore.sgml | 2 +- src/bin/pg_basebackup/t/010_pg_basebackup.pl | 4 ++-- src/bin/pg_checksums/t/002_actions.pl | 2 +- src/test/regress/expected/create_index.out | 2 +- src/test/regress/expected/create_misc.out | 2 +- src/test/regress/expected/random.out | 3 ++- src/test/regress/expected/select_implicit.out | 6 ++++-- src/test/regress/expected/select_implicit_1.out | 6 ++++-- src/test/regress/expected/select_implicit_2.out | 6 ++++-- src/test/regress/sql/create_index.sql | 2 +- src/test/regress/sql/create_misc.sql | 2 +- src/test/regress/sql/random.sql | 3 ++- src/test/regress/sql/select_implicit.sql | 6 ++++-- 15 files changed, 30 insertions(+), 20 deletions(-) diff --git a/contrib/sepgsql/expected/label.out b/contrib/sepgsql/expected/label.out index 0300bc6fb45e1..b1b7db55f67ab 100644 --- a/contrib/sepgsql/expected/label.out +++ b/contrib/sepgsql/expected/label.out @@ -6,7 +6,7 @@ -- CREATE TABLE t1 (a int, b text); INSERT INTO t1 VALUES (1, 'aaa'), (2, 'bbb'), (3, 'ccc'); -SELECT * INTO t2 FROM t1 WHERE a % 2 = 0; +CREATE TABLE t2 AS SELECT * FROM t1 WHERE a % 2 = 0; CREATE FUNCTION f1 () RETURNS text AS 'SELECT sepgsql_getcon()' LANGUAGE sql; diff --git a/contrib/sepgsql/sql/label.sql b/contrib/sepgsql/sql/label.sql index d19c6edb4ca8f..76e261bee8037 100644 --- a/contrib/sepgsql/sql/label.sql +++ b/contrib/sepgsql/sql/label.sql @@ -7,7 +7,7 @@ -- CREATE TABLE t1 (a int, b text); INSERT INTO t1 VALUES (1, 'aaa'), (2, 'bbb'), (3, 'ccc'); -SELECT * INTO t2 FROM t1 WHERE a % 2 = 0; +CREATE TABLE t2 AS SELECT * FROM t1 WHERE a % 2 = 0; CREATE FUNCTION f1 () RETURNS text AS 'SELECT sepgsql_getcon()' diff --git a/doc/src/sgml/hstore.sgml b/doc/src/sgml/hstore.sgml index 080706280e809..e867fcc5aee55 100644 --- a/doc/src/sgml/hstore.sgml +++ b/doc/src/sgml/hstore.sgml @@ -883,7 +883,7 @@ SELECT * FROM each('aaa=>bq, b=>NULL, ""=>1'); Using a table: -SELECT (each(h)).key, (each(h)).value INTO stat FROM testhstore; +CREATE TABLE stat AS SELECT (each(h)).key, (each(h)).value FROM testhstore; diff --git a/src/bin/pg_basebackup/t/010_pg_basebackup.pl b/src/bin/pg_basebackup/t/010_pg_basebackup.pl index f674a7c94e70e..9eba7d8d7d260 100644 --- a/src/bin/pg_basebackup/t/010_pg_basebackup.pl +++ b/src/bin/pg_basebackup/t/010_pg_basebackup.pl @@ -502,10 +502,10 @@ # create tables to corrupt and get their relfilenodes my $file_corrupt1 = $node->safe_psql('postgres', - q{SELECT a INTO corrupt1 FROM generate_series(1,10000) AS a; ALTER TABLE corrupt1 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt1')} + q{CREATE TABLE corrupt1 AS SELECT a FROM generate_series(1,10000) AS a; ALTER TABLE corrupt1 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt1')} ); my $file_corrupt2 = $node->safe_psql('postgres', - q{SELECT b INTO corrupt2 FROM generate_series(1,2) AS b; ALTER TABLE corrupt2 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt2')} + q{CREATE TABLE corrupt2 AS SELECT b FROM generate_series(1,2) AS b; ALTER TABLE corrupt2 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt2')} ); # set page header and block sizes diff --git a/src/bin/pg_checksums/t/002_actions.pl b/src/bin/pg_checksums/t/002_actions.pl index 4e4934532a30d..8a81f36a067fd 100644 --- a/src/bin/pg_checksums/t/002_actions.pl +++ b/src/bin/pg_checksums/t/002_actions.pl @@ -21,7 +21,7 @@ sub check_relation_corruption $node->safe_psql( 'postgres', - "SELECT a INTO $table FROM generate_series(1,10000) AS a; + "CREATE TABLE $table AS SELECT a FROM generate_series(1,10000) AS a; ALTER TABLE $table SET (autovacuum_enabled=false);"); $node->safe_psql('postgres', diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out index fc6afab58ab30..ce734f7ef36be 100644 --- a/src/test/regress/expected/create_index.out +++ b/src/test/regress/expected/create_index.out @@ -1582,7 +1582,7 @@ DROP TABLE syscol_table; -- -- Tests for IS NULL/IS NOT NULL with b-tree indexes -- -SELECT unique1, unique2 INTO onek_with_null FROM onek; +CREATE TABLE onek_with_null AS SELECT unique1, unique2 FROM onek; INSERT INTO onek_with_null (unique1,unique2) VALUES (NULL, -1), (NULL, NULL); CREATE UNIQUE INDEX onek_nulltest ON onek_with_null (unique2,unique1); SET enable_seqscan = OFF; diff --git a/src/test/regress/expected/create_misc.out b/src/test/regress/expected/create_misc.out index cee35ed02f161..41bc4d77507fb 100644 --- a/src/test/regress/expected/create_misc.out +++ b/src/test/regress/expected/create_misc.out @@ -5,7 +5,7 @@ -- (any resemblance to real life is purely coincidental) -- INSERT INTO tenk2 SELECT * FROM tenk1; -SELECT * INTO TABLE onek2 FROM onek; +CREATE TABLE onek2 AS SELECT * FROM onek; INSERT INTO fast_emp4000 SELECT * FROM slow_emp4000; SELECT * INTO TABLE Bprime diff --git a/src/test/regress/expected/random.out b/src/test/regress/expected/random.out index 302c3d61c7a59..a919b28d8daa8 100644 --- a/src/test/regress/expected/random.out +++ b/src/test/regress/expected/random.out @@ -23,7 +23,8 @@ INTERSECT (0 rows) -- count roughly 1/10 of the tuples -SELECT count(*) AS random INTO RANDOM_TBL +CREATE TABLE RANDOM_TBL AS + SELECT count(*) AS random FROM onek WHERE random() < 1.0/10; -- select again, the count should be different INSERT INTO RANDOM_TBL (random) diff --git a/src/test/regress/expected/select_implicit.out b/src/test/regress/expected/select_implicit.out index 61b485fdaae91..27c07de92cc94 100644 --- a/src/test/regress/expected/select_implicit.out +++ b/src/test/regress/expected/select_implicit.out @@ -202,7 +202,8 @@ SELECT count(*) FROM test_missing_target x, test_missing_target y -- group w/o existing GROUP BY target under ambiguous condition -- into a table -SELECT count(*) INTO TABLE test_missing_target2 +CREATE TABLE test_missing_target2 AS +SELECT count(*) FROM test_missing_target x, test_missing_target y WHERE x.a = y.a GROUP BY x.b ORDER BY x.b; @@ -318,7 +319,8 @@ LINE 1: SELECT count(b) FROM test_missing_target x, test_missing_tar... ^ -- group w/o existing GROUP BY target under ambiguous condition -- into a table -SELECT count(x.b) INTO TABLE test_missing_target3 +CREATE TABLE test_missing_target3 AS +SELECT count(x.b) FROM test_missing_target x, test_missing_target y WHERE x.a = y.a GROUP BY x.b/2 ORDER BY x.b/2; diff --git a/src/test/regress/expected/select_implicit_1.out b/src/test/regress/expected/select_implicit_1.out index f277375ebfc97..d67521e8f83c6 100644 --- a/src/test/regress/expected/select_implicit_1.out +++ b/src/test/regress/expected/select_implicit_1.out @@ -202,7 +202,8 @@ SELECT count(*) FROM test_missing_target x, test_missing_target y -- group w/o existing GROUP BY target under ambiguous condition -- into a table -SELECT count(*) INTO TABLE test_missing_target2 +CREATE TABLE test_missing_target2 AS +SELECT count(*) FROM test_missing_target x, test_missing_target y WHERE x.a = y.a GROUP BY x.b ORDER BY x.b; @@ -318,7 +319,8 @@ LINE 1: SELECT count(b) FROM test_missing_target x, test_missing_tar... ^ -- group w/o existing GROUP BY target under ambiguous condition -- into a table -SELECT count(x.b) INTO TABLE test_missing_target3 +CREATE TABLE test_missing_target3 AS +SELECT count(x.b) FROM test_missing_target x, test_missing_target y WHERE x.a = y.a GROUP BY x.b/2 ORDER BY x.b/2; diff --git a/src/test/regress/expected/select_implicit_2.out b/src/test/regress/expected/select_implicit_2.out index 91c3a24f92aa3..7a353d086271d 100644 --- a/src/test/regress/expected/select_implicit_2.out +++ b/src/test/regress/expected/select_implicit_2.out @@ -202,7 +202,8 @@ SELECT count(*) FROM test_missing_target x, test_missing_target y -- group w/o existing GROUP BY target under ambiguous condition -- into a table -SELECT count(*) INTO TABLE test_missing_target2 +CREATE TABLE test_missing_target2 AS +SELECT count(*) FROM test_missing_target x, test_missing_target y WHERE x.a = y.a GROUP BY x.b ORDER BY x.b; @@ -318,7 +319,8 @@ LINE 1: SELECT count(b) FROM test_missing_target x, test_missing_tar... ^ -- group w/o existing GROUP BY target under ambiguous condition -- into a table -SELECT count(x.b) INTO TABLE test_missing_target3 +CREATE TABLE test_missing_target3 AS +SELECT count(x.b) FROM test_missing_target x, test_missing_target y WHERE x.a = y.a GROUP BY x.b/2 ORDER BY x.b/2; diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql index 824cb9f9e82c8..fd4f30876e188 100644 --- a/src/test/regress/sql/create_index.sql +++ b/src/test/regress/sql/create_index.sql @@ -609,7 +609,7 @@ DROP TABLE syscol_table; -- Tests for IS NULL/IS NOT NULL with b-tree indexes -- -SELECT unique1, unique2 INTO onek_with_null FROM onek; +CREATE TABLE onek_with_null AS SELECT unique1, unique2 FROM onek; INSERT INTO onek_with_null (unique1,unique2) VALUES (NULL, -1), (NULL, NULL); CREATE UNIQUE INDEX onek_nulltest ON onek_with_null (unique2,unique1); diff --git a/src/test/regress/sql/create_misc.sql b/src/test/regress/sql/create_misc.sql index d0b04a821f811..c7d0d064c3784 100644 --- a/src/test/regress/sql/create_misc.sql +++ b/src/test/regress/sql/create_misc.sql @@ -8,7 +8,7 @@ INSERT INTO tenk2 SELECT * FROM tenk1; -SELECT * INTO TABLE onek2 FROM onek; +CREATE TABLE onek2 AS SELECT * FROM onek; INSERT INTO fast_emp4000 SELECT * FROM slow_emp4000; diff --git a/src/test/regress/sql/random.sql b/src/test/regress/sql/random.sql index ae6b70a157bd1..8187b2c288ab8 100644 --- a/src/test/regress/sql/random.sql +++ b/src/test/regress/sql/random.sql @@ -17,7 +17,8 @@ INTERSECT FROM onek ORDER BY random() LIMIT 1); -- count roughly 1/10 of the tuples -SELECT count(*) AS random INTO RANDOM_TBL +CREATE TABLE RANDOM_TBL AS + SELECT count(*) AS random FROM onek WHERE random() < 1.0/10; -- select again, the count should be different diff --git a/src/test/regress/sql/select_implicit.sql b/src/test/regress/sql/select_implicit.sql index d81550422292e..de3aef8d81c70 100644 --- a/src/test/regress/sql/select_implicit.sql +++ b/src/test/regress/sql/select_implicit.sql @@ -86,7 +86,8 @@ SELECT count(*) FROM test_missing_target x, test_missing_target y -- group w/o existing GROUP BY target under ambiguous condition -- into a table -SELECT count(*) INTO TABLE test_missing_target2 +CREATE TABLE test_missing_target2 AS +SELECT count(*) FROM test_missing_target x, test_missing_target y WHERE x.a = y.a GROUP BY x.b ORDER BY x.b; @@ -142,7 +143,8 @@ SELECT count(b) FROM test_missing_target x, test_missing_target y -- group w/o existing GROUP BY target under ambiguous condition -- into a table -SELECT count(x.b) INTO TABLE test_missing_target3 +CREATE TABLE test_missing_target3 AS +SELECT count(x.b) FROM test_missing_target x, test_missing_target y WHERE x.a = y.a GROUP BY x.b/2 ORDER BY x.b/2; From 6819b9042fe69154ff3fd2337c5028038d3cfab4 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Thu, 28 Jan 2021 12:50:40 -0300 Subject: [PATCH 199/240] pgbench: Remove dead code doConnect() never returns connections in state CONNECTION_BAD, so checking for that is pointless. Remove the code that does. This code has been dead since ba708ea3dc84, 20 years ago. Discussion: https://postgr.es/m/20210126195224.GA20361@alvherre.pgsql Reviewed-by: Tom Lane --- src/bin/pgbench/pgbench.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index 1be1ad3d6d959..a4a3f40048e82 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -6040,13 +6040,6 @@ main(int argc, char **argv) if (con == NULL) exit(1); - if (PQstatus(con) == CONNECTION_BAD) - { - pg_log_fatal("connection to database \"%s\" failed: %s", - dbName, PQerrorMessage(con)); - exit(1); - } - if (internal_script_used) GetTableInfo(con, scale_given); From 1b242f42ba1e732b202f35265ab1a1614ce7d859 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 28 Jan 2021 11:17:13 -0500 Subject: [PATCH 200/240] Make ecpg's rjulmdy() and rmdyjul() agree with their declarations. We had "short *mdy" in the extern declarations, but "short mdy[3]" in the actual function definitions. Per C99 these are equivalent, but recent versions of gcc have started to issue warnings about the inconsistency. Clean it up before the warnings get any more widespread. Back-patch, in case anyone wants to build older PG versions with bleeding-edge compilers. Discussion: https://postgr.es/m/2401575.1611764534@sss.pgh.pa.us --- src/interfaces/ecpg/compatlib/informix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/interfaces/ecpg/compatlib/informix.c b/src/interfaces/ecpg/compatlib/informix.c index 0bca383ebe573..dccf39582da55 100644 --- a/src/interfaces/ecpg/compatlib/informix.c +++ b/src/interfaces/ecpg/compatlib/informix.c @@ -513,7 +513,7 @@ rtoday(date * d) } int -rjulmdy(date d, short mdy[3]) +rjulmdy(date d, short *mdy) { int mdy_int[3]; @@ -564,7 +564,7 @@ rfmtdate(date d, const char *fmt, char *str) } int -rmdyjul(short mdy[3], date * d) +rmdyjul(short *mdy, date * d) { int mdy_int[3]; From 1d9351a87c9a9e82c7091aab03d9299982670ce0 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 28 Jan 2021 13:41:55 -0500 Subject: [PATCH 201/240] Fix hash partition pruning with asymmetric partition sets. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit perform_pruning_combine_step() was not taught about the number of partition indexes used in hash partitioning; more embarrassingly, get_matching_hash_bounds() also had it wrong. These errors are masked in the common case where all the partitions have the same modulus and no partition is missing. However, with missing or unequal-size partitions, we could erroneously prune some partitions that need to be scanned, leading to silently wrong query answers. While a minimal-footprint fix for this could be to export get_partition_bound_num_indexes and make the incorrect functions use it, I'm of the opinion that that function should never have existed in the first place. It's not reasonable data structure design that PartitionBoundInfoData lacks any explicit record of the length of its indexes[] array. Perhaps that was all right when it could always be assumed equal to ndatums, but something should have been done about it as soon as that stopped being true. Putting in an explicit "nindexes" field makes both partition_bounds_equal() and partition_bounds_copy() simpler, safer, and faster than before, and removes explicit knowledge of the number-of-partition-indexes rules from some other places too. This change also makes get_hash_partition_greatest_modulus obsolete. I left that in place in case any external code uses it, but no core code does anymore. Per bug #16840 from Michał Albrycht. Back-patch to v11 where the hash partitioning code came in. (In the back branches, add the new field at the end of PartitionBoundInfoData to minimize ABI risks.) Discussion: https://postgr.es/m/16840-571a22976f829ad4@postgresql.org --- src/backend/executor/execPartition.c | 4 +- src/backend/partitioning/partbounds.c | 115 +++++------------- src/backend/partitioning/partprune.c | 30 ++--- src/include/partitioning/partbounds.h | 29 +++-- src/test/regress/expected/partition_prune.out | 60 ++++++--- src/test/regress/sql/partition_prune.sql | 27 ++-- 6 files changed, 124 insertions(+), 141 deletions(-) diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index 1746cb87936ce..746cd1e9d7a1b 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -1323,16 +1323,14 @@ get_partition_for_tuple(PartitionDispatch pd, Datum *values, bool *isnull) { case PARTITION_STRATEGY_HASH: { - int greatest_modulus; uint64 rowHash; - greatest_modulus = get_hash_partition_greatest_modulus(boundinfo); rowHash = compute_partition_hash_value(key->partnatts, key->partsupfunc, key->partcollation, values, isnull); - part_index = boundinfo->indexes[rowHash % greatest_modulus]; + part_index = boundinfo->indexes[rowHash % boundinfo->nindexes]; } break; diff --git a/src/backend/partitioning/partbounds.c b/src/backend/partitioning/partbounds.c index b9aeb77bc2bad..0c3f212ff21e6 100644 --- a/src/backend/partitioning/partbounds.c +++ b/src/backend/partitioning/partbounds.c @@ -224,7 +224,6 @@ static int partition_range_bsearch(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, PartitionBoundInfo boundinfo, PartitionRangeBound *probe, int32 *cmpval); -static int get_partition_bound_num_indexes(PartitionBoundInfo b); static Expr *make_partition_op_expr(PartitionKey key, int keynum, uint16 strategy, Expr *arg1, Expr *arg2); static Oid get_partition_operator(PartitionKey key, int col, @@ -398,6 +397,7 @@ create_hash_bounds(PartitionBoundSpec **boundspecs, int nparts, boundinfo->ndatums = ndatums; boundinfo->datums = (Datum **) palloc0(ndatums * sizeof(Datum *)); + boundinfo->nindexes = greatest_modulus; boundinfo->indexes = (int *) palloc(greatest_modulus * sizeof(int)); for (i = 0; i < greatest_modulus; i++) boundinfo->indexes[i] = -1; @@ -530,6 +530,7 @@ create_list_bounds(PartitionBoundSpec **boundspecs, int nparts, boundinfo->ndatums = ndatums; boundinfo->datums = (Datum **) palloc0(ndatums * sizeof(Datum *)); + boundinfo->nindexes = ndatums; boundinfo->indexes = (int *) palloc(ndatums * sizeof(int)); /* @@ -725,8 +726,9 @@ create_range_bounds(PartitionBoundSpec **boundspecs, int nparts, /* * For range partitioning, an additional value of -1 is stored as the last - * element. + * element of the indexes[] array. */ + boundinfo->nindexes = ndatums + 1; boundinfo->indexes = (int *) palloc((ndatums + 1) * sizeof(int)); for (i = 0; i < ndatums; i++) @@ -807,45 +809,41 @@ partition_bounds_equal(int partnatts, int16 *parttyplen, bool *parttypbyval, if (b1->ndatums != b2->ndatums) return false; + if (b1->nindexes != b2->nindexes) + return false; + if (b1->null_index != b2->null_index) return false; if (b1->default_index != b2->default_index) return false; - if (b1->strategy == PARTITION_STRATEGY_HASH) + /* For all partition strategies, the indexes[] arrays have to match */ + for (i = 0; i < b1->nindexes; i++) { - int greatest_modulus = get_hash_partition_greatest_modulus(b1); - - /* - * If two hash partitioned tables have different greatest moduli, - * their partition schemes don't match. - */ - if (greatest_modulus != get_hash_partition_greatest_modulus(b2)) + if (b1->indexes[i] != b2->indexes[i]) return false; + } + /* Finally, compare the datums[] arrays */ + if (b1->strategy == PARTITION_STRATEGY_HASH) + { /* * We arrange the partitions in the ascending order of their moduli * and remainders. Also every modulus is factor of next larger * modulus. Therefore we can safely store index of a given partition * in indexes array at remainder of that partition. Also entries at * (remainder + N * modulus) positions in indexes array are all same - * for (modulus, remainder) specification for any partition. Thus - * datums array from both the given bounds are same, if and only if - * their indexes array will be same. So, it suffices to compare - * indexes array. - */ - for (i = 0; i < greatest_modulus; i++) - if (b1->indexes[i] != b2->indexes[i]) - return false; - -#ifdef USE_ASSERT_CHECKING - - /* - * Nonetheless make sure that the bounds are indeed same when the + * for (modulus, remainder) specification for any partition. Thus the + * datums arrays from the given bounds are the same, if and only if + * their indexes arrays are the same. So, it suffices to compare the + * indexes arrays. + * + * Nonetheless make sure that the bounds are indeed the same when the * indexes match. Hash partition bound stores modulus and remainder * at b1->datums[i][0] and b1->datums[i][1] position respectively. */ +#ifdef USE_ASSERT_CHECKING for (i = 0; i < b1->ndatums; i++) Assert((b1->datums[i][0] == b2->datums[i][0] && b1->datums[i][1] == b2->datums[i][1])); @@ -891,15 +889,7 @@ partition_bounds_equal(int partnatts, int16 *parttyplen, bool *parttypbyval, parttypbyval[j], parttyplen[j])) return false; } - - if (b1->indexes[i] != b2->indexes[i]) - return false; } - - /* There are ndatums+1 indexes in case of range partitions */ - if (b1->strategy == PARTITION_STRATEGY_RANGE && - b1->indexes[i] != b2->indexes[i]) - return false; } return true; } @@ -920,8 +910,8 @@ partition_bounds_copy(PartitionBoundInfo src, PartitionBoundInfo dest; int i; int ndatums; + int nindexes; int partnatts; - int num_indexes; bool hash_part; int natts; @@ -929,10 +919,9 @@ partition_bounds_copy(PartitionBoundInfo src, dest->strategy = src->strategy; ndatums = dest->ndatums = src->ndatums; + nindexes = dest->nindexes = src->nindexes; partnatts = key->partnatts; - num_indexes = get_partition_bound_num_indexes(src); - /* List partitioned tables have only a single partition key. */ Assert(key->strategy != PARTITION_STRATEGY_LIST || partnatts == 1); @@ -990,8 +979,8 @@ partition_bounds_copy(PartitionBoundInfo src, } } - dest->indexes = (int *) palloc(sizeof(int) * num_indexes); - memcpy(dest->indexes, src->indexes, sizeof(int) * num_indexes); + dest->indexes = (int *) palloc(sizeof(int) * nindexes); + memcpy(dest->indexes, src->indexes, sizeof(int) * nindexes); dest->null_index = src->null_index; dest->default_index = src->default_index; @@ -2456,6 +2445,7 @@ build_merged_partition_bounds(char strategy, List *merged_datums, } Assert(list_length(merged_indexes) == ndatums); + merged_bounds->nindexes = ndatums; merged_bounds->indexes = (int *) palloc(sizeof(int) * ndatums); pos = 0; foreach(lc, merged_indexes) @@ -2889,7 +2879,7 @@ check_new_partition_bound(char *relname, Relation parent, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("every hash partition modulus must be a factor of the next larger modulus"))); - greatest_modulus = get_hash_partition_greatest_modulus(boundinfo); + greatest_modulus = boundinfo->nindexes; remainder = spec->remainder; /* @@ -3282,18 +3272,15 @@ check_default_partition_contents(Relation parent, Relation default_rel, /* * get_hash_partition_greatest_modulus * - * Returns the greatest modulus of the hash partition bound. The greatest - * modulus will be at the end of the datums array because hash partitions are - * arranged in the ascending order of their moduli and remainders. + * Returns the greatest modulus of the hash partition bound. + * This is no longer used in the core code, but we keep it around + * in case external modules are using it. */ int get_hash_partition_greatest_modulus(PartitionBoundInfo bound) { Assert(bound && bound->strategy == PARTITION_STRATEGY_HASH); - Assert(bound->datums && bound->ndatums > 0); - Assert(DatumGetInt32(bound->datums[bound->ndatums - 1][0]) > 0); - - return DatumGetInt32(bound->datums[bound->ndatums - 1][0]); + return bound->nindexes; } /* @@ -3697,46 +3684,6 @@ qsort_partition_rbound_cmp(const void *a, const void *b, void *arg) b1, b2); } -/* - * get_partition_bound_num_indexes - * - * Returns the number of the entries in the partition bound indexes array. - */ -static int -get_partition_bound_num_indexes(PartitionBoundInfo bound) -{ - int num_indexes; - - Assert(bound); - - switch (bound->strategy) - { - case PARTITION_STRATEGY_HASH: - - /* - * The number of the entries in the indexes array is same as the - * greatest modulus. - */ - num_indexes = get_hash_partition_greatest_modulus(bound); - break; - - case PARTITION_STRATEGY_LIST: - num_indexes = bound->ndatums; - break; - - case PARTITION_STRATEGY_RANGE: - /* Range partitioned table has an extra index. */ - num_indexes = bound->ndatums + 1; - break; - - default: - elog(ERROR, "unexpected partition strategy: %d", - (int) bound->strategy); - } - - return num_indexes; -} - /* * get_partition_operator * diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c index fac921eea5b93..42c7c5f55412f 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -781,7 +781,10 @@ get_matching_partitions(PartitionPruneContext *context, List *pruning_steps) scan_default = final_result->scan_default; while ((i = bms_next_member(final_result->bound_offsets, i)) >= 0) { - int partindex = context->boundinfo->indexes[i]; + int partindex; + + Assert(i < context->boundinfo->nindexes); + partindex = context->boundinfo->indexes[i]; if (partindex < 0) { @@ -2514,20 +2517,19 @@ get_matching_hash_bounds(PartitionPruneContext *context, for (i = 0; i < partnatts; i++) isnull[i] = bms_is_member(i, nullkeys); - greatest_modulus = get_hash_partition_greatest_modulus(boundinfo); rowHash = compute_partition_hash_value(partnatts, partsupfunc, partcollation, values, isnull); + greatest_modulus = boundinfo->nindexes; if (partindices[rowHash % greatest_modulus] >= 0) result->bound_offsets = bms_make_singleton(rowHash % greatest_modulus); } else { - /* Getting here means at least one hash partition exists. */ - Assert(boundinfo->ndatums > 0); + /* Report all valid offsets into the boundinfo->indexes array. */ result->bound_offsets = bms_add_range(NULL, 0, - boundinfo->ndatums - 1); + boundinfo->nindexes - 1); } /* @@ -3388,30 +3390,20 @@ perform_pruning_combine_step(PartitionPruneContext *context, PartitionPruneStepCombine *cstep, PruneStepResult **step_results) { - ListCell *lc1; - PruneStepResult *result = NULL; + PruneStepResult *result = (PruneStepResult *) palloc0(sizeof(PruneStepResult)); bool firststep; + ListCell *lc1; /* * A combine step without any source steps is an indication to not perform * any partition pruning. Return all datum indexes in that case. */ - result = (PruneStepResult *) palloc0(sizeof(PruneStepResult)); - if (list_length(cstep->source_stepids) == 0) + if (cstep->source_stepids == NIL) { PartitionBoundInfo boundinfo = context->boundinfo; - int rangemax; - - /* - * Add all valid offsets into the boundinfo->indexes array. For range - * partitioning, boundinfo->indexes contains (boundinfo->ndatums + 1) - * valid entries; otherwise there are boundinfo->ndatums. - */ - rangemax = context->strategy == PARTITION_STRATEGY_RANGE ? - boundinfo->ndatums : boundinfo->ndatums - 1; result->bound_offsets = - bms_add_range(result->bound_offsets, 0, rangemax); + bms_add_range(NULL, 0, boundinfo->nindexes - 1); result->scan_default = partition_bound_has_default(boundinfo); result->scan_null = partition_bound_accepts_nulls(boundinfo); return result; diff --git a/src/include/partitioning/partbounds.h b/src/include/partitioning/partbounds.h index 6bd330dd938a9..ebf3ff1f4973c 100644 --- a/src/include/partitioning/partbounds.h +++ b/src/include/partitioning/partbounds.h @@ -30,7 +30,7 @@ struct RelOptInfo; /* avoid including pathnodes.h here */ * In the case of range partitioning, ndatums will typically be far less than * 2 * nparts, because a partition's upper bound and the next partition's lower * bound are the same in most common cases, and we only store one of them (the - * upper bound). In case of hash partitioning, ndatums will be same as the + * upper bound). In case of hash partitioning, ndatums will be the same as the * number of partitions. * * For range and list partitioned tables, datums is an array of datum-tuples @@ -46,24 +46,31 @@ struct RelOptInfo; /* avoid including pathnodes.h here */ * the partition key's operator classes and collations. * * In the case of list partitioning, the indexes array stores one entry for - * every datum, which is the index of the partition that accepts a given datum. - * In case of range partitioning, it stores one entry per distinct range - * datum, which is the index of the partition for which a given datum - * is an upper bound. In the case of hash partitioning, the number of the - * entries in the indexes array is same as the greatest modulus amongst all - * partitions. For a given partition key datum-tuple, the index of the - * partition which would accept that datum-tuple would be given by the entry - * pointed by remainder produced when hash value of the datum-tuple is divided - * by the greatest modulus. + * each datum-array entry, which is the index of the partition that accepts + * rows matching that datum. So nindexes == ndatums. + * + * In the case of range partitioning, the indexes array stores one entry per + * distinct range datum, which is the index of the partition for which that + * datum is an upper bound (or -1 for a "gap" that has no partition). It is + * convenient to have an extra -1 entry representing values above the last + * range datum, so nindexes == ndatums + 1. + * + * In the case of hash partitioning, the number of entries in the indexes + * array is the same as the greatest modulus amongst all partitions (which + * is a multiple of all partition moduli), so nindexes == greatest modulus. + * The indexes array is indexed according to the hash key's remainder modulo + * the greatest modulus, and it contains either the partition index accepting + * that remainder, or -1 if there is no partition for that remainder. */ typedef struct PartitionBoundInfoData { char strategy; /* hash, list or range? */ - int ndatums; /* Length of the datums following array */ + int ndatums; /* Length of the datums[] array */ Datum **datums; PartitionRangeDatumKind **kind; /* The kind of each range bound datum; * NULL for hash and list partitioned * tables */ + int nindexes; /* Length of the indexes[] array */ int *indexes; /* Partition indexes */ int null_index; /* Index of the null-accepting partition; -1 * if there isn't one */ diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out index c72a6d051f1dd..bde29e38a9436 100644 --- a/src/test/regress/expected/partition_prune.out +++ b/src/test/regress/expected/partition_prune.out @@ -1538,26 +1538,27 @@ drop table lp, coll_pruning, rlp, mc3p, mc2p, boolpart, boolrangep, rp, coll_pru -- result on different machines. See the definitions of -- part_part_test_int4_ops and part_test_text_ops in insert.sql. -- -create table hp (a int, b text) partition by hash (a part_test_int4_ops, b part_test_text_ops); +create table hp (a int, b text, c int) + partition by hash (a part_test_int4_ops, b part_test_text_ops); create table hp0 partition of hp for values with (modulus 4, remainder 0); create table hp3 partition of hp for values with (modulus 4, remainder 3); create table hp1 partition of hp for values with (modulus 4, remainder 1); create table hp2 partition of hp for values with (modulus 4, remainder 2); -insert into hp values (null, null); -insert into hp values (1, null); -insert into hp values (1, 'xxx'); -insert into hp values (null, 'xxx'); -insert into hp values (2, 'xxx'); -insert into hp values (1, 'abcde'); -select tableoid::regclass, * from hp order by 1; - tableoid | a | b -----------+---+------- - hp0 | | - hp0 | 1 | xxx - hp3 | 2 | xxx - hp1 | 1 | - hp2 | | xxx - hp2 | 1 | abcde +insert into hp values (null, null, 0); +insert into hp values (1, null, 1); +insert into hp values (1, 'xxx', 2); +insert into hp values (null, 'xxx', 3); +insert into hp values (2, 'xxx', 4); +insert into hp values (1, 'abcde', 5); +select tableoid::regclass, * from hp order by c; + tableoid | a | b | c +----------+---+-------+--- + hp0 | | | 0 + hp1 | 1 | | 1 + hp0 | 1 | xxx | 2 + hp2 | | xxx | 3 + hp3 | 2 | xxx | 4 + hp2 | 1 | abcde | 5 (6 rows) -- partial keys won't prune, nor would non-equality conditions @@ -1715,6 +1716,33 @@ explain (costs off) select * from hp where (a = 1 and b = 'abcde') or (a = 2 and Filter: (((a = 1) AND (b = 'abcde'::text)) OR ((a = 2) AND (b = 'xxx'::text)) OR ((a IS NULL) AND (b IS NULL))) (7 rows) +-- test pruning when not all the partitions exist +drop table hp1; +drop table hp3; +explain (costs off) select * from hp where a = 1 and b = 'abcde'; + QUERY PLAN +--------------------------------------------- + Seq Scan on hp2 hp + Filter: ((a = 1) AND (b = 'abcde'::text)) +(2 rows) + +explain (costs off) select * from hp where a = 1 and b = 'abcde' and + (c = 2 or c = 3); + QUERY PLAN +---------------------------------------------------------------------- + Seq Scan on hp2 hp + Filter: ((a = 1) AND (b = 'abcde'::text) AND ((c = 2) OR (c = 3))) +(2 rows) + +drop table hp2; +explain (costs off) select * from hp where a = 1 and b = 'abcde' and + (c = 2 or c = 3); + QUERY PLAN +-------------------------- + Result + One-Time Filter: false +(2 rows) + drop table hp; -- -- Test runtime partition pruning diff --git a/src/test/regress/sql/partition_prune.sql b/src/test/regress/sql/partition_prune.sql index ffd5fe8b0dc50..6ccb52ad1d674 100644 --- a/src/test/regress/sql/partition_prune.sql +++ b/src/test/regress/sql/partition_prune.sql @@ -304,19 +304,20 @@ drop table lp, coll_pruning, rlp, mc3p, mc2p, boolpart, boolrangep, rp, coll_pru -- part_part_test_int4_ops and part_test_text_ops in insert.sql. -- -create table hp (a int, b text) partition by hash (a part_test_int4_ops, b part_test_text_ops); +create table hp (a int, b text, c int) + partition by hash (a part_test_int4_ops, b part_test_text_ops); create table hp0 partition of hp for values with (modulus 4, remainder 0); create table hp3 partition of hp for values with (modulus 4, remainder 3); create table hp1 partition of hp for values with (modulus 4, remainder 1); create table hp2 partition of hp for values with (modulus 4, remainder 2); -insert into hp values (null, null); -insert into hp values (1, null); -insert into hp values (1, 'xxx'); -insert into hp values (null, 'xxx'); -insert into hp values (2, 'xxx'); -insert into hp values (1, 'abcde'); -select tableoid::regclass, * from hp order by 1; +insert into hp values (null, null, 0); +insert into hp values (1, null, 1); +insert into hp values (1, 'xxx', 2); +insert into hp values (null, 'xxx', 3); +insert into hp values (2, 'xxx', 4); +insert into hp values (1, 'abcde', 5); +select tableoid::regclass, * from hp order by c; -- partial keys won't prune, nor would non-equality conditions explain (costs off) select * from hp where a = 1; @@ -337,6 +338,16 @@ explain (costs off) select * from hp where a = 2 and b = 'xxx'; explain (costs off) select * from hp where a = 1 and b = 'abcde'; explain (costs off) select * from hp where (a = 1 and b = 'abcde') or (a = 2 and b = 'xxx') or (a is null and b is null); +-- test pruning when not all the partitions exist +drop table hp1; +drop table hp3; +explain (costs off) select * from hp where a = 1 and b = 'abcde'; +explain (costs off) select * from hp where a = 1 and b = 'abcde' and + (c = 2 or c = 3); +drop table hp2; +explain (costs off) select * from hp where a = 1 and b = 'abcde' and + (c = 2 or c = 3); + drop table hp; -- From 6f5c8a8ec23f8ab00da4d2b77bfc8af2a578c4d3 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Thu, 28 Jan 2021 16:56:07 -0300 Subject: [PATCH 202/240] Remove bogus restriction from BEFORE UPDATE triggers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In trying to protect the user from inconsistent behavior, commit 487e9861d0cf "Enable BEFORE row-level triggers for partitioned tables" tried to prevent BEFORE UPDATE FOR EACH ROW triggers from moving the row from one partition to another. However, it turns out that the restriction is wrong in two ways: first, it fails spuriously, preventing valid situations from working, as in bug #16794; and second, they don't protect from any misbehavior, because tuple routing would cope anyway. Fix by removing that restriction. We keep the same restriction on BEFORE INSERT FOR EACH ROW triggers, though. It is valid and useful there. In the future we could remove it by having tuple reroute work for inserts as it does for updates. Backpatch to 13. Author: Álvaro Herrera Reported-by: Phillip Menke Discussion: https://postgr.es/m/16794-350a655580fbb9ae@postgresql.org --- doc/src/sgml/ddl.sgml | 4 +- src/backend/commands/trigger.c | 10 ----- src/test/regress/expected/triggers.out | 57 ++++++++++++++++++++++---- src/test/regress/sql/triggers.sql | 28 ++++++++++++- 4 files changed, 77 insertions(+), 22 deletions(-) diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml index 02d2f42865172..1e9a4625cc631 100644 --- a/doc/src/sgml/ddl.sgml +++ b/doc/src/sgml/ddl.sgml @@ -4027,8 +4027,8 @@ ALTER INDEX measurement_city_id_logdate_key - BEFORE ROW triggers cannot change which partition - is the final destination for a new row. + BEFORE ROW triggers on INSERT + cannot change which partition is the final destination for a new row. diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 3e7086c5e5295..2d687f6dfb6bb 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -2799,16 +2799,6 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate, { ExecForceStoreHeapTuple(newtuple, newslot, false); - if (trigger->tgisclone && - !ExecPartitionCheck(relinfo, newslot, estate, false)) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("moving row to another partition during a BEFORE trigger is not supported"), - errdetail("Before executing trigger \"%s\", the row was to be in partition \"%s.%s\".", - trigger->tgname, - get_namespace_name(RelationGetNamespace(relinfo->ri_RelationDesc)), - RelationGetRelationName(relinfo->ri_RelationDesc)))); - /* * If the tuple returned by the trigger / being stored, is the old * row version, and the heap tuple passed to the trigger was diff --git a/src/test/regress/expected/triggers.out b/src/test/regress/expected/triggers.out index 1dc525251a9c6..b263002293bb8 100644 --- a/src/test/regress/expected/triggers.out +++ b/src/test/regress/expected/triggers.out @@ -2359,8 +2359,8 @@ insert into parted values (1, 1, 'uno uno v2'); -- fail ERROR: moving row to another partition during a BEFORE FOR EACH ROW trigger is not supported DETAIL: Before executing trigger "t", the row was to be in partition "public.parted_1_1". update parted set c = c || 'v3'; -- fail -ERROR: moving row to another partition during a BEFORE trigger is not supported -DETAIL: Before executing trigger "t", the row was to be in partition "public.parted_1_1". +ERROR: no partition of relation "parted" found for row +DETAIL: Partition key of the failing row contains (a) = (2). create or replace function parted_trigfunc() returns trigger language plpgsql as $$ begin new.b = new.b + 1; @@ -2371,23 +2371,62 @@ insert into parted values (1, 1, 'uno uno v4'); -- fail ERROR: moving row to another partition during a BEFORE FOR EACH ROW trigger is not supported DETAIL: Before executing trigger "t", the row was to be in partition "public.parted_1_1". update parted set c = c || 'v5'; -- fail -ERROR: moving row to another partition during a BEFORE trigger is not supported -DETAIL: Before executing trigger "t", the row was to be in partition "public.parted_1_1". +ERROR: no partition of relation "parted_1" found for row +DETAIL: Partition key of the failing row contains (b) = (2). create or replace function parted_trigfunc() returns trigger language plpgsql as $$ begin - new.c = new.c || ' and so'; + new.c = new.c || ' did '|| TG_OP; return new; end; $$; insert into parted values (1, 1, 'uno uno'); -- works update parted set c = c || ' v6'; -- works select tableoid::regclass, * from parted; - tableoid | a | b | c -------------+---+---+-------------------------- - parted_1_1 | 1 | 1 | uno uno v1 v6 and so - parted_1_1 | 1 | 1 | uno uno and so v6 and so + tableoid | a | b | c +------------+---+---+---------------------------------- + parted_1_1 | 1 | 1 | uno uno v1 v6 did UPDATE + parted_1_1 | 1 | 1 | uno uno did INSERT v6 did UPDATE (2 rows) +-- update itself moves tuple to new partition; trigger still works +truncate table parted; +create table parted_2 partition of parted for values in (2); +insert into parted values (1, 1, 'uno uno v5'); +update parted set a = 2; +select tableoid::regclass, * from parted; + tableoid | a | b | c +----------+---+---+--------------------------------------------- + parted_2 | 2 | 1 | uno uno v5 did INSERT did UPDATE did INSERT +(1 row) + +-- both trigger and update change the partition +create or replace function parted_trigfunc2() returns trigger language plpgsql as $$ +begin + new.a = new.a + 1; + return new; +end; +$$; +create trigger t2 before update on parted + for each row execute function parted_trigfunc2(); +truncate table parted; +insert into parted values (1, 1, 'uno uno v6'); +create table parted_3 partition of parted for values in (3); +update parted set a = a + 1; +select tableoid::regclass, * from parted; + tableoid | a | b | c +----------+---+---+--------------------------------------------- + parted_3 | 3 | 1 | uno uno v6 did INSERT did UPDATE did INSERT +(1 row) + +-- there's no partition for a=0, but this update works anyway because +-- the trigger causes the tuple to be routed to another partition +update parted set a = 0; +select tableoid::regclass, * from parted; + tableoid | a | b | c +------------+---+---+------------------------------------------------------------------- + parted_1_1 | 1 | 1 | uno uno v6 did INSERT did UPDATE did INSERT did UPDATE did INSERT +(1 row) + drop table parted; create table parted (a int, b int, c text) partition by list ((a + b)); create or replace function parted_trigfunc() returns trigger language plpgsql as $$ diff --git a/src/test/regress/sql/triggers.sql b/src/test/regress/sql/triggers.sql index bebe276ef4327..01f66af699cb4 100644 --- a/src/test/regress/sql/triggers.sql +++ b/src/test/regress/sql/triggers.sql @@ -1633,7 +1633,7 @@ insert into parted values (1, 1, 'uno uno v4'); -- fail update parted set c = c || 'v5'; -- fail create or replace function parted_trigfunc() returns trigger language plpgsql as $$ begin - new.c = new.c || ' and so'; + new.c = new.c || ' did '|| TG_OP; return new; end; $$; @@ -1641,6 +1641,32 @@ insert into parted values (1, 1, 'uno uno'); -- works update parted set c = c || ' v6'; -- works select tableoid::regclass, * from parted; +-- update itself moves tuple to new partition; trigger still works +truncate table parted; +create table parted_2 partition of parted for values in (2); +insert into parted values (1, 1, 'uno uno v5'); +update parted set a = 2; +select tableoid::regclass, * from parted; + +-- both trigger and update change the partition +create or replace function parted_trigfunc2() returns trigger language plpgsql as $$ +begin + new.a = new.a + 1; + return new; +end; +$$; +create trigger t2 before update on parted + for each row execute function parted_trigfunc2(); +truncate table parted; +insert into parted values (1, 1, 'uno uno v6'); +create table parted_3 partition of parted for values in (3); +update parted set a = a + 1; +select tableoid::regclass, * from parted; +-- there's no partition for a=0, but this update works anyway because +-- the trigger causes the tuple to be routed to another partition +update parted set a = 0; +select tableoid::regclass, * from parted; + drop table parted; create table parted (a int, b int, c text) partition by list ((a + b)); create or replace function parted_trigfunc() returns trigger language plpgsql as $$ From 1046dbedde2fc3fe55f007ff3255ab65ab98f858 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 28 Jan 2021 17:18:23 -0500 Subject: [PATCH 203/240] Silence another gcc 11 warning. Per buildfarm and local experimentation, bleeding-edge gcc isn't convinced that the MemSet in reorder_function_arguments() is safe. Shut it up by adding an explicit check that pronargs isn't negative, and by changing MemSet to memset. (It appears that either change is enough to quiet the warning at -O2, but let's do both to be sure.) --- src/backend/optimizer/util/clauses.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index d2470b7c6a7d6..f3786dd2b63bc 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -3805,9 +3805,9 @@ reorder_function_arguments(List *args, HeapTuple func_tuple) int i; Assert(nargsprovided <= pronargs); - if (pronargs > FUNC_MAX_ARGS) + if (pronargs < 0 || pronargs > FUNC_MAX_ARGS) elog(ERROR, "too many function arguments"); - MemSet(argarray, 0, pronargs * sizeof(Node *)); + memset(argarray, 0, pronargs * sizeof(Node *)); /* Deconstruct the argument list into an array indexed by argnumber */ i = 0; From 514b411a2b5226167add9ab139d3a96dbe98035d Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Fri, 29 Jan 2021 13:21:53 +1300 Subject: [PATCH 204/240] Retire pg_standby. pg_standby was useful more than a decade ago, but now it is obsolete. It has been proposed that we retire it many times. Now seems like a good time to finally do it, because "waiting restore commands" are incompatible with a proposed recovery prefetching feature. Discussion: https://postgr.es/m/20201029024412.GP5380%40telsasoft.com Author: Justin Pryzby Reviewed-by: Heikki Linnakangas Reviewed-by: Peter Eisentraut Reviewed-by: Michael Paquier Reviewed-by: Fujii Masao --- contrib/Makefile | 1 - contrib/pg_standby/.gitignore | 1 - contrib/pg_standby/Makefile | 20 - contrib/pg_standby/pg_standby.c | 907 ------------------------- doc/src/sgml/contrib.sgml | 7 +- doc/src/sgml/filelist.sgml | 1 - doc/src/sgml/high-availability.sgml | 17 +- doc/src/sgml/pgstandby.sgml | 394 ----------- doc/src/sgml/ref/pgarchivecleanup.sgml | 7 - src/backend/access/transam/xlog.c | 2 +- src/tools/msvc/Mkvcbuild.pm | 4 +- 11 files changed, 9 insertions(+), 1352 deletions(-) delete mode 100644 contrib/pg_standby/.gitignore delete mode 100644 contrib/pg_standby/Makefile delete mode 100644 contrib/pg_standby/pg_standby.c delete mode 100644 doc/src/sgml/pgstandby.sgml diff --git a/contrib/Makefile b/contrib/Makefile index 7a4866e338db0..cdc041c7db731 100644 --- a/contrib/Makefile +++ b/contrib/Makefile @@ -33,7 +33,6 @@ SUBDIRS = \ pg_buffercache \ pg_freespacemap \ pg_prewarm \ - pg_standby \ pg_stat_statements \ pg_surgery \ pg_trgm \ diff --git a/contrib/pg_standby/.gitignore b/contrib/pg_standby/.gitignore deleted file mode 100644 index a401b085a895d..0000000000000 --- a/contrib/pg_standby/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/pg_standby diff --git a/contrib/pg_standby/Makefile b/contrib/pg_standby/Makefile deleted file mode 100644 index 87732bedf185f..0000000000000 --- a/contrib/pg_standby/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# contrib/pg_standby/Makefile - -PGFILEDESC = "pg_standby - supports creation of a warm standby" -PGAPPICON = win32 - -PROGRAM = pg_standby -OBJS = \ - $(WIN32RES) \ - pg_standby.o - -ifdef USE_PGXS -PG_CONFIG = pg_config -PGXS := $(shell $(PG_CONFIG) --pgxs) -include $(PGXS) -else -subdir = contrib/pg_standby -top_builddir = ../.. -include $(top_builddir)/src/Makefile.global -include $(top_srcdir)/contrib/contrib-global.mk -endif diff --git a/contrib/pg_standby/pg_standby.c b/contrib/pg_standby/pg_standby.c deleted file mode 100644 index c9f33e4254c4b..0000000000000 --- a/contrib/pg_standby/pg_standby.c +++ /dev/null @@ -1,907 +0,0 @@ -/* - * contrib/pg_standby/pg_standby.c - * - * - * pg_standby.c - * - * Production-ready example of how to create a Warm Standby - * database server using continuous archiving as a - * replication mechanism - * - * We separate the parameters for archive and nextWALfile - * so that we can check the archive exists, even if the - * WAL file doesn't (yet). - * - * This program will be executed once in full for each file - * requested by the warm standby server. - * - * It is designed to cater to a variety of needs, as well - * providing a customizable section. - * - * Original author: Simon Riggs simon@2ndquadrant.com - * Current maintainer: Simon Riggs - */ -#include "postgres_fe.h" - -#include -#include -#include -#include -#include -#include - -#include "access/xlog_internal.h" -#include "pg_getopt.h" - -const char *progname; - -int WalSegSz = -1; - -/* Options and defaults */ -int sleeptime = 5; /* amount of time to sleep between file checks */ -int waittime = -1; /* how long we have been waiting, -1 no wait - * yet */ -int maxwaittime = 0; /* how long are we prepared to wait for? */ -int keepfiles = 0; /* number of WAL files to keep, 0 keep all */ -int maxretries = 3; /* number of retries on restore command */ -bool debug = false; /* are we debugging? */ -bool need_cleanup = false; /* do we need to remove files from - * archive? */ - -#ifndef WIN32 -static volatile sig_atomic_t signaled = false; -#endif - -char *archiveLocation; /* where to find the archive? */ -char *triggerPath; /* where to find the trigger file? */ -char *xlogFilePath; /* where we are going to restore to */ -char *nextWALFileName; /* the file we need to get from archive */ -char *restartWALFileName; /* the file from which we can restart restore */ -char WALFilePath[MAXPGPATH * 2]; /* the file path including archive */ -char restoreCommand[MAXPGPATH]; /* run this to restore */ -char exclusiveCleanupFileName[MAXFNAMELEN]; /* the file we need to get - * from archive */ - -/* - * Two types of failover are supported (smart and fast failover). - * - * The content of the trigger file determines the type of failover. If the - * trigger file contains the word "smart" (or the file is empty), smart - * failover is chosen: pg_standby acts as cp or ln command itself, on - * successful completion all the available WAL records will be applied - * resulting in zero data loss. But, it might take a long time to finish - * recovery if there's a lot of unapplied WAL. - * - * On the other hand, if the trigger file contains the word "fast", the - * recovery is finished immediately even if unapplied WAL files remain. Any - * transactions in the unapplied WAL files are lost. - * - * An empty trigger file performs smart failover. SIGUSR or SIGINT triggers - * fast failover. A timeout causes fast failover (smart failover would have - * the same effect, since if the timeout is reached there is no unapplied WAL). - */ -#define NoFailover 0 -#define SmartFailover 1 -#define FastFailover 2 - -static int Failover = NoFailover; - -#define RESTORE_COMMAND_COPY 0 -#define RESTORE_COMMAND_LINK 1 -int restoreCommandType; - -#define XLOG_DATA 0 -#define XLOG_HISTORY 1 -int nextWALFileType; - -#define SET_RESTORE_COMMAND(cmd, arg1, arg2) \ - snprintf(restoreCommand, MAXPGPATH, cmd " \"%s\" \"%s\"", arg1, arg2) - -struct stat stat_buf; - -static bool SetWALFileNameForCleanup(void); -static bool SetWALSegSize(void); - - -/* ===================================================================== - * - * Customizable section - * - * ===================================================================== - * - * Currently, this section assumes that the Archive is a locally - * accessible directory. If you want to make other assumptions, - * such as using a vendor-specific archive and access API, these - * routines are the ones you'll need to change. You're - * encouraged to submit any changes to pgsql-hackers@lists.postgresql.org - * or personally to the current maintainer. Those changes may be - * folded in to later versions of this program. - */ - -/* - * Initialize allows customized commands into the warm standby program. - * - * As an example, and probably the common case, we use either - * cp/ln commands on *nix, or copy/move command on Windows. - */ -static void -CustomizableInitialize(void) -{ -#ifdef WIN32 - snprintf(WALFilePath, MAXPGPATH, "%s\\%s", archiveLocation, nextWALFileName); - switch (restoreCommandType) - { - case RESTORE_COMMAND_LINK: - SET_RESTORE_COMMAND("mklink", WALFilePath, xlogFilePath); - break; - case RESTORE_COMMAND_COPY: - default: - SET_RESTORE_COMMAND("copy", WALFilePath, xlogFilePath); - break; - } -#else - snprintf(WALFilePath, MAXPGPATH, "%s/%s", archiveLocation, nextWALFileName); - switch (restoreCommandType) - { - case RESTORE_COMMAND_LINK: - SET_RESTORE_COMMAND("ln -s -f", WALFilePath, xlogFilePath); - break; - case RESTORE_COMMAND_COPY: - default: - SET_RESTORE_COMMAND("cp", WALFilePath, xlogFilePath); - break; - } -#endif - - /* - * This code assumes that archiveLocation is a directory You may wish to - * add code to check for tape libraries, etc.. So, since it is a - * directory, we use stat to test if it's accessible - */ - if (stat(archiveLocation, &stat_buf) != 0) - { - fprintf(stderr, "%s: archive location \"%s\" does not exist\n", progname, archiveLocation); - fflush(stderr); - exit(2); - } -} - -/* - * CustomizableNextWALFileReady() - * - * Is the requested file ready yet? - */ -static bool -CustomizableNextWALFileReady(void) -{ - if (stat(WALFilePath, &stat_buf) == 0) - { - /* - * If we've not seen any WAL segments, we don't know the WAL segment - * size, which we need. If it looks like a WAL segment, determine size - * of segments for the cluster. - */ - if (WalSegSz == -1 && IsXLogFileName(nextWALFileName)) - { - if (SetWALSegSize()) - { - /* - * Successfully determined WAL segment size. Can compute - * cleanup cutoff now. - */ - need_cleanup = SetWALFileNameForCleanup(); - if (debug) - { - fprintf(stderr, - _("WAL segment size: %d \n"), WalSegSz); - fprintf(stderr, "Keep archive history: "); - - if (need_cleanup) - fprintf(stderr, "%s and later\n", - exclusiveCleanupFileName); - else - fprintf(stderr, "no cleanup required\n"); - } - } - } - - /* - * Return only if it's the right size already. - */ - if (WalSegSz > 0 && stat_buf.st_size == WalSegSz) - { -#ifdef WIN32 - - /* - * Windows 'cp' sets the final file size before the copy is - * complete, and not yet ready to be opened by pg_standby. So we - * wait for sleeptime secs before attempting to restore. If that - * is not enough, we will rely on the retry/holdoff mechanism. - * GNUWin32's cp does not have this problem. - */ - pg_usleep(sleeptime * 1000000L); -#endif - nextWALFileType = XLOG_DATA; - return true; - } - - /* - * If still too small, wait until it is the correct size - */ - if (WalSegSz > 0 && stat_buf.st_size > WalSegSz) - { - if (debug) - { - fprintf(stderr, "file size greater than expected\n"); - fflush(stderr); - } - exit(3); - } - } - - return false; -} - -static void -CustomizableCleanupPriorWALFiles(void) -{ - /* - * Work out name of prior file from current filename - */ - if (nextWALFileType == XLOG_DATA) - { - int rc; - DIR *xldir; - struct dirent *xlde; - - /* - * Assume it's OK to keep failing. The failure situation may change - * over time, so we'd rather keep going on the main processing than - * fail because we couldn't clean up yet. - */ - if ((xldir = opendir(archiveLocation)) != NULL) - { - while (errno = 0, (xlde = readdir(xldir)) != NULL) - { - /* - * We ignore the timeline part of the XLOG segment identifiers - * in deciding whether a segment is still needed. This - * ensures that we won't prematurely remove a segment from a - * parent timeline. We could probably be a little more - * proactive about removing segments of non-parent timelines, - * but that would be a whole lot more complicated. - * - * We use the alphanumeric sorting property of the filenames - * to decide which ones are earlier than the - * exclusiveCleanupFileName file. Note that this means files - * are not removed in the order they were originally written, - * in case this worries you. - */ - if (IsXLogFileName(xlde->d_name) && - strcmp(xlde->d_name + 8, exclusiveCleanupFileName + 8) < 0) - { -#ifdef WIN32 - snprintf(WALFilePath, sizeof(WALFilePath), "%s\\%s", archiveLocation, xlde->d_name); -#else - snprintf(WALFilePath, sizeof(WALFilePath), "%s/%s", archiveLocation, xlde->d_name); -#endif - - if (debug) - fprintf(stderr, "\nremoving file \"%s\"", WALFilePath); - - rc = unlink(WALFilePath); - if (rc != 0) - { - fprintf(stderr, "\n%s: ERROR: could not remove file \"%s\": %s\n", - progname, WALFilePath, strerror(errno)); - break; - } - } - } - - if (errno) - fprintf(stderr, "%s: could not read archive location \"%s\": %s\n", - progname, archiveLocation, strerror(errno)); - if (debug) - fprintf(stderr, "\n"); - } - else - fprintf(stderr, "%s: could not open archive location \"%s\": %s\n", - progname, archiveLocation, strerror(errno)); - - if (closedir(xldir)) - fprintf(stderr, "%s: could not close archive location \"%s\": %s\n", - progname, archiveLocation, strerror(errno)); - - fflush(stderr); - } -} - -/* ===================================================================== - * End of Customizable section - * ===================================================================== - */ - -/* - * SetWALFileNameForCleanup() - * - * Set the earliest WAL filename that we want to keep on the archive - * and decide whether we need_cleanup - */ -static bool -SetWALFileNameForCleanup(void) -{ - uint32 tli = 1, - log = 0, - seg = 0; - uint32 log_diff = 0, - seg_diff = 0; - bool cleanup = false; - int max_segments_per_logfile = (0xFFFFFFFF / WalSegSz); - - if (restartWALFileName) - { - /* - * Don't do cleanup if the restartWALFileName provided is later than - * the xlog file requested. This is an error and we must not remove - * these files from archive. This shouldn't happen, but better safe - * than sorry. - */ - if (strcmp(restartWALFileName, nextWALFileName) > 0) - return false; - - strlcpy(exclusiveCleanupFileName, restartWALFileName, sizeof(exclusiveCleanupFileName)); - return true; - } - - if (keepfiles > 0) - { - sscanf(nextWALFileName, "%08X%08X%08X", &tli, &log, &seg); - if (tli > 0 && seg > 0) - { - log_diff = keepfiles / max_segments_per_logfile; - seg_diff = keepfiles % max_segments_per_logfile; - if (seg_diff > seg) - { - log_diff++; - seg = max_segments_per_logfile - (seg_diff - seg); - } - else - seg -= seg_diff; - - if (log >= log_diff) - { - log -= log_diff; - cleanup = true; - } - else - { - log = 0; - seg = 0; - } - } - } - - XLogFileNameById(exclusiveCleanupFileName, tli, log, seg); - - return cleanup; -} - -/* - * Try to set the wal segment size from the WAL file specified by WALFilePath. - * - * Return true if size could be determined, false otherwise. - */ -static bool -SetWALSegSize(void) -{ - bool ret_val = false; - int fd; - PGAlignedXLogBlock buf; - - Assert(WalSegSz == -1); - - if ((fd = open(WALFilePath, O_RDWR, 0)) < 0) - { - fprintf(stderr, "%s: could not open WAL file \"%s\": %s\n", - progname, WALFilePath, strerror(errno)); - return false; - } - - errno = 0; - if (read(fd, buf.data, XLOG_BLCKSZ) == XLOG_BLCKSZ) - { - XLogLongPageHeader longhdr = (XLogLongPageHeader) buf.data; - - WalSegSz = longhdr->xlp_seg_size; - - if (IsValidWalSegSize(WalSegSz)) - { - /* successfully retrieved WAL segment size */ - ret_val = true; - } - else - fprintf(stderr, - "%s: WAL segment size must be a power of two between 1MB and 1GB, but the WAL file header specifies %d bytes\n", - progname, WalSegSz); - } - else - { - /* - * Don't complain loudly, this is to be expected for segments being - * created. - */ - if (errno != 0) - { - if (debug) - fprintf(stderr, "could not read file \"%s\": %s\n", - WALFilePath, strerror(errno)); - } - else - { - if (debug) - fprintf(stderr, "not enough data in file \"%s\"\n", - WALFilePath); - } - } - - fflush(stderr); - - close(fd); - return ret_val; -} - -/* - * CheckForExternalTrigger() - * - * Is there a trigger file? Sets global 'Failover' variable to indicate - * what kind of a trigger file it was. A "fast" trigger file is turned - * into a "smart" file as a side-effect. - */ -static void -CheckForExternalTrigger(void) -{ - char buf[32]; - int fd; - int len; - - /* - * Look for a trigger file, if that option has been selected - * - * We use stat() here because triggerPath is always a file rather than - * potentially being in an archive - */ - if (!triggerPath || stat(triggerPath, &stat_buf) != 0) - return; - - /* - * An empty trigger file performs smart failover. There's a little race - * condition here: if the writer of the trigger file has just created the - * file, but not yet written anything to it, we'll treat that as smart - * shutdown even if the other process was just about to write "fast" to - * it. But that's fine: we'll restore one more WAL file, and when we're - * invoked next time, we'll see the word "fast" and fail over immediately. - */ - if (stat_buf.st_size == 0) - { - Failover = SmartFailover; - fprintf(stderr, "trigger file found: smart failover\n"); - fflush(stderr); - return; - } - - if ((fd = open(triggerPath, O_RDWR, 0)) < 0) - { - fprintf(stderr, "WARNING: could not open \"%s\": %s\n", - triggerPath, strerror(errno)); - fflush(stderr); - return; - } - - if ((len = read(fd, buf, sizeof(buf) - 1)) < 0) - { - fprintf(stderr, "WARNING: could not read \"%s\": %s\n", - triggerPath, strerror(errno)); - fflush(stderr); - close(fd); - return; - } - buf[len] = '\0'; - - if (strncmp(buf, "smart", 5) == 0) - { - Failover = SmartFailover; - fprintf(stderr, "trigger file found: smart failover\n"); - fflush(stderr); - close(fd); - return; - } - - if (strncmp(buf, "fast", 4) == 0) - { - Failover = FastFailover; - - fprintf(stderr, "trigger file found: fast failover\n"); - fflush(stderr); - - /* - * Turn it into a "smart" trigger by truncating the file. Otherwise if - * the server asks us again to restore a segment that was restored - * already, we would return "not found" and upset the server. - */ - if (ftruncate(fd, 0) < 0) - { - fprintf(stderr, "WARNING: could not read \"%s\": %s\n", - triggerPath, strerror(errno)); - fflush(stderr); - } - close(fd); - - return; - } - close(fd); - - fprintf(stderr, "WARNING: invalid content in \"%s\"\n", triggerPath); - fflush(stderr); -} - -/* - * RestoreWALFileForRecovery() - * - * Perform the action required to restore the file from archive - */ -static bool -RestoreWALFileForRecovery(void) -{ - int rc = 0; - int numretries = 0; - - if (debug) - { - fprintf(stderr, "running restore: "); - fflush(stderr); - } - - while (numretries <= maxretries) - { - rc = system(restoreCommand); - if (rc == 0) - { - if (debug) - { - fprintf(stderr, "OK\n"); - fflush(stderr); - } - return true; - } - pg_usleep(numretries++ * sleeptime * 1000000L); - } - - /* - * Allow caller to add additional info - */ - if (debug) - fprintf(stderr, "not restored\n"); - return false; -} - -static void -usage(void) -{ - printf("%s allows PostgreSQL warm standby servers to be configured.\n\n", progname); - printf("Usage:\n"); - printf(" %s [OPTION]... ARCHIVELOCATION NEXTWALFILE XLOGFILEPATH [RESTARTWALFILE]\n", progname); - printf("\nOptions:\n"); - printf(" -c copy file from archive (default)\n"); - printf(" -d generate lots of debugging output (testing only)\n"); - printf(" -k NUMFILESTOKEEP if RESTARTWALFILE is not used, remove files prior to limit\n" - " (0 keeps all)\n"); - printf(" -l does nothing; use of link is now deprecated\n"); - printf(" -r MAXRETRIES max number of times to retry, with progressive wait\n" - " (default=3)\n"); - printf(" -s SLEEPTIME seconds to wait between file checks (min=1, max=60,\n" - " default=5)\n"); - printf(" -t TRIGGERFILE trigger file to initiate failover (no default)\n"); - printf(" -V, --version output version information, then exit\n"); - printf(" -w MAXWAITTIME max seconds to wait for a file (0=no limit) (default=0)\n"); - printf(" -?, --help show this help, then exit\n"); - printf("\n" - "Main intended use as restore_command in postgresql.conf:\n" - " restore_command = 'pg_standby [OPTION]... ARCHIVELOCATION %%f %%p %%r'\n" - "e.g.\n" - " restore_command = 'pg_standby /mnt/server/archiverdir %%f %%p %%r'\n"); - printf("\nReport bugs to <%s>.\n", PACKAGE_BUGREPORT); - printf("%s home page: <%s>\n", PACKAGE_NAME, PACKAGE_URL); -} - -#ifndef WIN32 -static void -sighandler(int sig) -{ - signaled = true; -} - -/* We don't want SIGQUIT to core dump */ -static void -sigquit_handler(int sig) -{ - pqsignal(SIGINT, SIG_DFL); - kill(getpid(), SIGINT); -} -#endif - -/*------------ MAIN ----------------------------------------*/ -int -main(int argc, char **argv) -{ - int c; - - progname = get_progname(argv[0]); - - if (argc > 1) - { - if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) - { - usage(); - exit(0); - } - if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) - { - puts("pg_standby (PostgreSQL) " PG_VERSION); - exit(0); - } - } - -#ifndef WIN32 - - /* - * You can send SIGUSR1 to trigger failover. - * - * Postmaster uses SIGQUIT to request immediate shutdown. The default - * action is to core dump, but we don't want that, so trap it and commit - * suicide without core dump. - * - * We used to use SIGINT and SIGQUIT to trigger failover, but that turned - * out to be a bad idea because postmaster uses SIGQUIT to request - * immediate shutdown. We still trap SIGINT, but that may change in a - * future release. - * - * There's no way to trigger failover via signal on Windows. - */ - (void) pqsignal(SIGUSR1, sighandler); - (void) pqsignal(SIGINT, sighandler); /* deprecated, use SIGUSR1 */ - (void) pqsignal(SIGQUIT, sigquit_handler); -#endif - - while ((c = getopt(argc, argv, "cdk:lr:s:t:w:")) != -1) - { - switch (c) - { - case 'c': /* Use copy */ - restoreCommandType = RESTORE_COMMAND_COPY; - break; - case 'd': /* Debug mode */ - debug = true; - break; - case 'k': /* keepfiles */ - keepfiles = atoi(optarg); - if (keepfiles < 0) - { - fprintf(stderr, "%s: -k keepfiles must be >= 0\n", progname); - exit(2); - } - break; - case 'l': /* Use link */ - - /* - * Link feature disabled, possibly permanently. Linking causes - * a problem after recovery ends that is not currently - * resolved by PostgreSQL. 25 Jun 2009 - */ -#ifdef NOT_USED - restoreCommandType = RESTORE_COMMAND_LINK; -#endif - break; - case 'r': /* Retries */ - maxretries = atoi(optarg); - if (maxretries < 0) - { - fprintf(stderr, "%s: -r maxretries must be >= 0\n", progname); - exit(2); - } - break; - case 's': /* Sleep time */ - sleeptime = atoi(optarg); - if (sleeptime <= 0 || sleeptime > 60) - { - fprintf(stderr, "%s: -s sleeptime incorrectly set\n", progname); - exit(2); - } - break; - case 't': /* Trigger file */ - triggerPath = pg_strdup(optarg); - break; - case 'w': /* Max wait time */ - maxwaittime = atoi(optarg); - if (maxwaittime < 0) - { - fprintf(stderr, "%s: -w maxwaittime incorrectly set\n", progname); - exit(2); - } - break; - default: - fprintf(stderr, "Try \"%s --help\" for more information.\n", progname); - exit(2); - break; - } - } - - /* - * Parameter checking - after checking to see if trigger file present - */ - if (argc == 1) - { - fprintf(stderr, "%s: not enough command-line arguments\n", progname); - exit(2); - } - - /* - * We will go to the archiveLocation to get nextWALFileName. - * nextWALFileName may not exist yet, which would not be an error, so we - * separate the archiveLocation and nextWALFileName so we can check - * separately whether archiveLocation exists, if not that is an error - */ - if (optind < argc) - { - archiveLocation = argv[optind]; - optind++; - } - else - { - fprintf(stderr, "%s: must specify archive location\n", progname); - fprintf(stderr, "Try \"%s --help\" for more information.\n", progname); - exit(2); - } - - if (optind < argc) - { - nextWALFileName = argv[optind]; - optind++; - } - else - { - fprintf(stderr, "%s: must specify WAL file name as second non-option argument (use \"%%f\")\n", progname); - fprintf(stderr, "Try \"%s --help\" for more information.\n", progname); - exit(2); - } - - if (optind < argc) - { - xlogFilePath = argv[optind]; - optind++; - } - else - { - fprintf(stderr, "%s: must specify xlog destination as third non-option argument (use \"%%p\")\n", progname); - fprintf(stderr, "Try \"%s --help\" for more information.\n", progname); - exit(2); - } - - if (optind < argc) - { - restartWALFileName = argv[optind]; - optind++; - } - - CustomizableInitialize(); - - if (debug) - { - fprintf(stderr, "Trigger file: %s\n", triggerPath ? triggerPath : ""); - fprintf(stderr, "Waiting for WAL file: %s\n", nextWALFileName); - fprintf(stderr, "WAL file path: %s\n", WALFilePath); - fprintf(stderr, "Restoring to: %s\n", xlogFilePath); - fprintf(stderr, "Sleep interval: %d second%s\n", - sleeptime, (sleeptime > 1 ? "s" : " ")); - fprintf(stderr, "Max wait interval: %d %s\n", - maxwaittime, (maxwaittime > 0 ? "seconds" : "forever")); - fprintf(stderr, "Command for restore: %s\n", restoreCommand); - fflush(stderr); - } - - /* - * Check for initial history file: always the first file to be requested - * It's OK if the file isn't there - all other files need to wait - */ - if (IsTLHistoryFileName(nextWALFileName)) - { - nextWALFileType = XLOG_HISTORY; - if (RestoreWALFileForRecovery()) - exit(0); - else - { - if (debug) - { - fprintf(stderr, "history file not found\n"); - fflush(stderr); - } - exit(1); - } - } - - /* - * Main wait loop - */ - for (;;) - { - /* Check for trigger file or signal first */ - CheckForExternalTrigger(); -#ifndef WIN32 - if (signaled) - { - Failover = FastFailover; - if (debug) - { - fprintf(stderr, "signaled to exit: fast failover\n"); - fflush(stderr); - } - } -#endif - - /* - * Check for fast failover immediately, before checking if the - * requested WAL file is available - */ - if (Failover == FastFailover) - exit(1); - - if (CustomizableNextWALFileReady()) - { - /* - * Once we have restored this file successfully we can remove some - * prior WAL files. If this restore fails we mustn't remove any - * file because some of them will be requested again immediately - * after the failed restore, or when we restart recovery. - */ - if (RestoreWALFileForRecovery()) - { - if (need_cleanup) - CustomizableCleanupPriorWALFiles(); - - exit(0); - } - else - { - /* Something went wrong in copying the file */ - exit(1); - } - } - - /* Check for smart failover if the next WAL file was not available */ - if (Failover == SmartFailover) - exit(1); - - if (sleeptime <= 60) - pg_usleep(sleeptime * 1000000L); - - waittime += sleeptime; - if (waittime >= maxwaittime && maxwaittime > 0) - { - Failover = FastFailover; - if (debug) - { - fprintf(stderr, "Timed out after %d seconds: fast failover\n", - waittime); - fflush(stderr); - } - } - if (debug) - { - fprintf(stderr, "WAL file not present yet."); - if (triggerPath) - fprintf(stderr, " Checking for trigger file..."); - fprintf(stderr, "\n"); - fflush(stderr); - } - } -} diff --git a/doc/src/sgml/contrib.sgml b/doc/src/sgml/contrib.sgml index ae2759be55318..d3ca4b6932007 100644 --- a/doc/src/sgml/contrib.sgml +++ b/doc/src/sgml/contrib.sgml @@ -192,13 +192,12 @@ pages. Server Applications - This section covers PostgreSQL server-related - applications in contrib. They are typically run on the - host where the database server resides. See also PostgreSQL server + itself. Currently, no such applications are included in the + contrib directory. See also for information about server applications that are part of the core PostgreSQL distribution. - &pgstandby; diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml index 38e8aa0bbf90f..db1d369743e74 100644 --- a/doc/src/sgml/filelist.sgml +++ b/doc/src/sgml/filelist.sgml @@ -138,7 +138,6 @@ - diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml index dc263e4106761..9364dc74f71d0 100644 --- a/doc/src/sgml/high-availability.sgml +++ b/doc/src/sgml/high-availability.sgml @@ -699,11 +699,9 @@ protocol to make nodes agree on a serializable transactional order. - Do not use pg_standby or similar tools with the built-in standby mode - described here. should return immediately + should return immediately if the file does not exist; the server will retry the command again if - necessary. See - for using tools like pg_standby. + necessary. @@ -1494,8 +1492,7 @@ synchronous_standby_names = 'ANY 2 (s1, s2, s3)' An alternative to the built-in standby mode described in the previous sections is to use a restore_command that polls the archive location. - This was the only option available in versions 8.4 and below. See the - module for a reference implementation of this. + This was the only option available in versions 8.4 and below. @@ -1551,14 +1548,6 @@ if (!triggered) - - A working example of a waiting restore_command is provided - in the module. It - should be used as a reference on how to correctly implement the logic - described above. It can also be extended as needed to support specific - configurations and environments. - - The method for triggering failover is an important part of planning and design. One potential option is the restore_command diff --git a/doc/src/sgml/pgstandby.sgml b/doc/src/sgml/pgstandby.sgml deleted file mode 100644 index 66a62559303fd..0000000000000 --- a/doc/src/sgml/pgstandby.sgml +++ /dev/null @@ -1,394 +0,0 @@ - - - - - pg_standby - - - - pg_standby - 1 - Application - - - - pg_standby - supports the creation of a PostgreSQL warm standby server - - - - - pg_standby - option - archivelocation - nextwalfile - walfilepath - restartwalfile - - - - - Description - - - pg_standby supports creation of a warm standby - database server. It is designed to be a production-ready program, as well - as a customizable template should you require specific modifications. - - - - pg_standby is designed to be a waiting - restore_command, which is needed to turn a standard - archive recovery into a warm standby operation. Other - configuration is required as well, all of which is described in the main - server manual (see ). - - - - To configure a standby - server to use pg_standby, put this into its - postgresql.conf configuration file: - -restore_command = 'pg_standby archiveDir %f %p %r' - - where archiveDir is the directory from which WAL segment - files should be restored. - - - If restartwalfile is specified, normally by using the - %r macro, then all WAL files logically preceding this - file will be removed from archivelocation. This minimizes - the number of files that need to be retained, while preserving - crash-restart capability. Use of this parameter is appropriate if the - archivelocation is a transient staging area for this - particular standby server, but not when the - archivelocation is intended as a long-term WAL archive area. - - - pg_standby assumes that - archivelocation is a directory readable by the - server-owning user. If restartwalfile (or -k) - is specified, - the archivelocation directory must be writable too. - - - There are two ways to fail over to a warm standby database server - when the primary server fails: - - - - Smart Failover - - - In smart failover, the server is brought up after applying all WAL - files available in the archive. This results in zero data loss, even if - the standby server has fallen behind, but if there is a lot of - unapplied WAL it can be a long time before the standby server becomes - ready. To trigger a smart failover, create a trigger file containing - the word smart, or just create it and leave it empty. - - - - - Fast Failover - - - In fast failover, the server is brought up immediately. Any WAL files - in the archive that have not yet been applied will be ignored, and - all transactions in those files are lost. To trigger a fast failover, - create a trigger file and write the word fast into it. - pg_standby can also be configured to execute a fast - failover automatically if no new WAL file appears within a defined - interval. - - - - - - - - - - Options - - - pg_standby accepts the following command-line arguments: - - - - - - - - Use cp or copy command to restore WAL files - from archive. This is the only supported behavior so this option is useless. - - - - - - - - - Print lots of debug logging output on stderr. - - - - - - - - - Remove files from archivelocation so that - no more than this many WAL files before the current one are kept in the - archive. Zero (the default) means not to remove any files from - archivelocation. - This parameter will be silently ignored if - restartwalfile is specified, since that - specification method is more accurate in determining the correct - archive cut-off point. - Use of this parameter is deprecated as of - PostgreSQL 8.3; it is safer and more efficient to - specify a restartwalfile parameter. A too - small setting could result in removal of files that are still needed - for a restart of the standby server, while a too large setting wastes - archive space. - - - - - - maxretries - - - Set the maximum number of times to retry the copy command if - it fails (default 3). After each failure, we wait for - sleeptime * num_retries - so that the wait time increases progressively. So by default, - we will wait 5 secs, 10 secs, then 15 secs before reporting - the failure back to the standby server. This will be - interpreted as end of recovery and the standby will come - up fully as a result. - - - - - - sleeptime - - - Set the number of seconds (up to 60, default 5) to sleep between - tests to see if the WAL file to be restored is available in - the archive yet. The default setting is not necessarily - recommended; consult for discussion. - - - - - - triggerfile - - - Specify a trigger file whose presence should cause failover. - It is recommended that you use a structured file name to - avoid confusion as to which server is being triggered - when multiple servers exist on the same system; for example - /tmp/pgsql.trigger.5432. - - - - - - - - - - Print the pg_standby version and exit. - - - - - - maxwaittime - - - Set the maximum number of seconds to wait for the next WAL file, - after which a fast failover will be performed. - A setting of zero (the default) means wait forever. - The default setting is not necessarily recommended; - consult for discussion. - - - - - - - - - - Show help about pg_standby command line - arguments, and exit. - - - - - - - - - - Notes - - - pg_standby is designed to work with - PostgreSQL 8.2 and later. - - - PostgreSQL 8.3 provides the %r macro, - which is designed to let pg_standby know the - last file it needs to keep. With PostgreSQL 8.2, the - -k option must be used if archive cleanup is - required. This option remains available in 8.3, but its use is deprecated. - - - PostgreSQL 8.4 provides the - recovery_end_command option. Without this option - a leftover trigger file can be hazardous. - - - - pg_standby is written in C and has an - easy-to-modify source code, with specifically designated sections to modify - for your own needs - - - - - Examples - - On Linux or Unix systems, you might use: - - -archive_command = 'cp %p .../archive/%f' - -restore_command = 'pg_standby -d -s 2 -t /tmp/pgsql.trigger.5442 .../archive %f %p %r 2>>standby.log' - -recovery_end_command = 'rm -f /tmp/pgsql.trigger.5442' - - where the archive directory is physically located on the standby server, - so that the archive_command is accessing it across NFS, - but the files are local to the standby (enabling use of ln). - This will: - - - - produce debugging output in standby.log - - - - - sleep for 2 seconds between checks for next WAL file availability - - - - - stop waiting only when a trigger file called - /tmp/pgsql.trigger.5442 appears, - and perform failover according to its content - - - - - remove the trigger file when recovery ends - - - - - remove no-longer-needed files from the archive directory - - - - - - On Windows, you might use: - - -archive_command = 'copy %p ...\\archive\\%f' - -restore_command = 'pg_standby -d -s 5 -t C:\pgsql.trigger.5442 ...\archive %f %p %r 2>>standby.log' - -recovery_end_command = 'del C:\pgsql.trigger.5442' - - Note that backslashes need to be doubled in the - archive_command, but not in the - restore_command or recovery_end_command. - This will: - - - - use the copy command to restore WAL files from archive - - - - - produce debugging output in standby.log - - - - - sleep for 5 seconds between checks for next WAL file availability - - - - - stop waiting only when a trigger file called - C:\pgsql.trigger.5442 appears, - and perform failover according to its content - - - - - remove the trigger file when recovery ends - - - - - remove no-longer-needed files from the archive directory - - - - - - - The copy command on Windows sets the final file size - before the file is completely copied, which would ordinarily confuse - pg_standby. Therefore - pg_standby waits sleeptime - seconds once it sees the proper file size. GNUWin32's cp - sets the file size only after the file copy is complete. - - - - Since the Windows example uses copy at both ends, either - or both servers might be accessing the archive directory across the - network. - - - - - - Author - - - Simon Riggs simon@2ndquadrant.com - - - - - See Also - - - - - - diff --git a/doc/src/sgml/ref/pgarchivecleanup.sgml b/doc/src/sgml/ref/pgarchivecleanup.sgml index 56f02fc0e62e8..e27db3c077377 100644 --- a/doc/src/sgml/ref/pgarchivecleanup.sgml +++ b/doc/src/sgml/ref/pgarchivecleanup.sgml @@ -205,11 +205,4 @@ archive_cleanup_command = 'pg_archivecleanup -d /mnt/standby/archive %r 2>>clean - - See Also - - - - - diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 236a66f63875a..f03bd473e2b30 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -4199,7 +4199,7 @@ RemoveXlogFile(const char *segname, XLogSegNo recycleSegNo, /* * Before deleting the file, see if it can be recycled as a future log - * segment. Only recycle normal files, pg_standby for example can create + * segment. Only recycle normal files, because we don't want to recycle * symbolic links pointing to a separate archive directory. */ if (wal_recycle && diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm index 7213e65e08b1a..90328db04e90d 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -34,8 +34,8 @@ my @unlink_on_exit; # Set of variables for modules in contrib/ and src/test/modules/ my $contrib_defines = { 'refint' => 'REFINT_VERBOSE' }; my @contrib_uselibpq = ('dblink', 'oid2name', 'postgres_fdw', 'vacuumlo'); -my @contrib_uselibpgport = ('oid2name', 'pg_standby', 'vacuumlo'); -my @contrib_uselibpgcommon = ('oid2name', 'pg_standby', 'vacuumlo'); +my @contrib_uselibpgport = ('oid2name', 'vacuumlo'); +my @contrib_uselibpgcommon = ('oid2name', 'vacuumlo'); my $contrib_extralibs = undef; my $contrib_extraincludes = { 'dblink' => ['src/backend'] }; my $contrib_extrasource = { From 5c6d184213bb9feac0800eee1a16769bec9e8d58 Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Fri, 29 Jan 2021 14:16:29 +1300 Subject: [PATCH 205/240] Remove documentation of waiting restore_command. Following the removal of pg_standby, also remove the documentation section that describes how to write your own "waiting restore_command" along the same lines. Discussion: https://postgr.es/m/20201029024412.GP5380%40telsasoft.com Reviewed-by: Michael Paquier --- doc/src/sgml/high-availability.sgml | 137 ---------------------------- 1 file changed, 137 deletions(-) diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml index 9364dc74f71d0..f49f5c01081db 100644 --- a/doc/src/sgml/high-availability.sgml +++ b/doc/src/sgml/high-availability.sgml @@ -1486,143 +1486,6 @@ synchronous_standby_names = 'ANY 2 (s1, s2, s3)' - - Alternative Method for Log Shipping - - - An alternative to the built-in standby mode described in the previous - sections is to use a restore_command that polls the archive location. - This was the only option available in versions 8.4 and below. - - - - Note that in this mode, the server will apply WAL one file at a - time, so if you use the standby server for queries (see Hot Standby), - there is a delay between an action in the primary and when the - action becomes visible in the standby, corresponding to the time it takes - to fill up the WAL file. archive_timeout can be used to make that delay - shorter. Also note that you can't combine streaming replication with - this method. - - - - The operations that occur on both primary and standby servers are - normal continuous archiving and recovery tasks. The only point of - contact between the two database servers is the archive of WAL files - that both share: primary writing to the archive, standby reading from - the archive. Care must be taken to ensure that WAL archives from separate - primary servers do not become mixed together or confused. The archive - need not be large if it is only required for standby operation. - - - - The magic that makes the two loosely coupled servers work together is - simply a restore_command used on the standby that, - when asked for the next WAL file, waits for it to become available from - the primary. Normal recovery - processing would request a file from the WAL archive, reporting failure - if the file was unavailable. For standby processing it is normal for - the next WAL file to be unavailable, so the standby must wait for - it to appear. For files ending in - .history there is no need to wait, and a non-zero return - code must be returned. A waiting restore_command can be - written as a custom script that loops after polling for the existence of - the next WAL file. There must also be some way to trigger failover, which - should interrupt the restore_command, break the loop and - return a file-not-found error to the standby server. This ends recovery - and the standby will then come up as a normal server. - - - - Pseudocode for a suitable restore_command is: - -triggered = false; -while (!NextWALFileReady() && !triggered) -{ - sleep(100000L); /* wait for ~0.1 sec */ - if (CheckForExternalTrigger()) - triggered = true; -} -if (!triggered) - CopyWALFileForRecovery(); - - - - - The method for triggering failover is an important part of planning - and design. One potential option is the restore_command - command. It is executed once for each WAL file, but the process - running the restore_command is created and dies for - each file, so there is no daemon or server process, and - signals or a signal handler cannot be used. Therefore, the - restore_command is not suitable to trigger failover. - It is possible to use a simple timeout facility, especially if - used in conjunction with a known archive_timeout - setting on the primary. However, this is somewhat error prone - since a network problem or busy primary server might be sufficient - to initiate failover. A notification mechanism such as the explicit - creation of a trigger file is ideal, if this can be arranged. - - - - Implementation - - - The short procedure for configuring a standby server using this alternative - method is as follows. For - full details of each step, refer to previous sections as noted. - - - - Set up primary and standby systems as nearly identical as - possible, including two identical copies of - PostgreSQL at the same release level. - - - - - Set up continuous archiving from the primary to a WAL archive - directory on the standby server. Ensure that - , - and - - are set appropriately on the primary - (see ). - - - - - Make a base backup of the primary server (see ), and load this data onto the standby. - - - - - Begin recovery on the standby server from the local WAL - archive, using restore_command that waits - as described previously (see ). - - - - - - - Recovery treats the WAL archive as read-only, so once a WAL file has - been copied to the standby system it can be copied to tape at the same - time as it is being read by the standby database server. - Thus, running a standby server for high availability can be performed at - the same time as files are stored for longer term disaster recovery - purposes. - - - - For testing purposes, it is possible to run both primary and standby - servers on the same system. This does not provide any worthwhile - improvement in server robustness, nor would it be described as HA. - - - - Hot Standby From 24843297a96d7be16cc3f4b090aacfc6e5e6839e Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Fri, 29 Jan 2021 13:59:18 +0900 Subject: [PATCH 206/240] Adjust comments of CheckRelationTableSpaceMove() and SetRelationTableSpace() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 4c9c359, that introduced those two functions, has been overoptimistic on the point that only ShareUpdateExclusiveLock would be required when moving a relation to a new tablespace. AccessExclusiveLock is a requirement, but ShareUpdateExclusiveLock may be used under specific conditions like REINDEX CONCURRENTLY where waits on past transactions make the operation safe even with a lower-level lock. The current code does only the former, so update the existing comments to reflect that. Once a REINDEX (TABLESPACE) is introduced, those comments would require an extra refresh to mention their new use case. While on it, fix an incorrect variable name. Per discussion with Álvaro Herrera. Discussion: https://postgr.es/m/20210127140741.GA14174@alvherre.pgsql --- src/backend/commands/tablecmds.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 36747e7277da4..420991e31539c 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -3041,11 +3041,11 @@ SetRelationHasSubclass(Oid relationId, bool relhassubclass) * CheckRelationTableSpaceMove * Check if relation can be moved to new tablespace. * - * NOTE: Caller must be holding an appropriate lock on the relation. - * ShareUpdateExclusiveLock is sufficient. + * NOTE: The caller must hold AccessExclusiveLock on the relation. * - * Returns true if the relation can be moved to the new tablespace; - * false otherwise. + * Returns true if the relation can be moved to the new tablespace; raises + * an error if it is not possible to do the move; returns false if the move + * would have no effect. */ bool CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId) @@ -3094,11 +3094,10 @@ CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId) * Set new reltablespace and relfilenode in pg_class entry. * * newTableSpaceId is the new tablespace for the relation, and - * newRelFileNode its new filenode. If newrelfilenode is InvalidOid, + * newRelFileNode its new filenode. If newRelFileNode is InvalidOid, * this field is not updated. * - * NOTE: Caller must be holding an appropriate lock on the relation. - * ShareUpdateExclusiveLock is sufficient. + * NOTE: The caller must hold AccessExclusiveLock on the relation. * * The caller of this routine had better check if a relation can be * moved to this new tablespace by calling CheckRelationTableSpaceMove() From 2a5862f013647dd185de3e1b496fd4f614d12f0e Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Fri, 29 Jan 2021 14:24:49 +0900 Subject: [PATCH 207/240] doc: Improve wording of section for repslot statistics This documentation has been added in 9868167, so no backpatch is needed. Author: Justin Pryzby, Michael Paquier Discussion: https://postgr.es/m/20201222041153.GK30237@telsasoft.com --- doc/src/sgml/monitoring.sgml | 40 ++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index 9496f76b1fb0e..c602ee44277ba 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -317,7 +317,7 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser pg_stat_replication_slotspg_stat_replication_slots One row per replication slot, showing statistics about - replication slot usage. + the replication slot's usage. See pg_stat_replication_slots for details. @@ -2604,10 +2604,10 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i spill_txns bigint - Number of transactions spilled to disk after the memory used by - logical decoding of changes from WAL for this slot exceeds + Number of transactions spilled to disk once the memory used by + logical decoding to decode changes from WAL has exceeded logical_decoding_work_mem. The counter gets - incremented both for toplevel transactions and subtransactions. + incremented for both toplevel transactions and subtransactions. @@ -2616,9 +2616,10 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i spill_count bigint - Number of times transactions were spilled to disk while decoding changes - from WAL for this slot. Transactions may get spilled repeatedly, and - this counter gets incremented on every such invocation. + Number of times transactions were spilled to disk while decoding + changes from WAL for this slot. This counter is incremented each time + a transaction is spilled, and the same transaction may be spilled + multiple times. @@ -2639,11 +2640,12 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i stream_txns bigint - Number of in-progress transactions streamed to the decoding output plugin - after the memory used by logical decoding of changes from WAL for this - slot exceeds logical_decoding_work_mem. Streaming only + Number of in-progress transactions streamed to the decoding output + plugin after the memory used by logical decoding to decode changes + from WAL for this slot has exceeded + logical_decoding_work_mem. Streaming only works with toplevel transactions (subtransactions can't be streamed - independently), so the counter does not get incremented for subtransactions. + independently), so the counter is not incremented for subtransactions. @@ -2653,9 +2655,9 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i Number of times in-progress transactions were streamed to the decoding - output plugin while decoding changes from WAL for this slot. Transactions - may get streamed repeatedly, and this counter gets incremented on every - such invocation. + output plugin while decoding changes from WAL for this slot. This + counter is incremented each time a transaction is streamed, and the + same transaction may be streamed multiple times. @@ -5042,7 +5044,7 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i - + pg_stat_reset_replication_slot @@ -5050,11 +5052,9 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i void - Resets statistics to zero for a single replication slot, or for all - replication slots in the cluster. The argument can be either the name - of the slot to reset the stats or NULL. If the argument is NULL, all - counters shown in the pg_stat_replication_slots - view for all replication slots are reset. + Resets statistics of the replication slot defined by the argument. If + the argument is NULL, resets statistics for all + the replication slots. This function is restricted to superusers by default, but other users From 2592be8be5aed6448a1e2b386fffd75ad69eb6c5 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Fri, 29 Jan 2021 09:43:21 +0100 Subject: [PATCH 208/240] Fix typo --- src/bin/pg_dump/pg_dump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 798d14580e6d1..39da742e32c60 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -290,7 +290,7 @@ static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer); static bool nonemptyReloptions(const char *reloptions); static void appendIndexCollationVersion(PQExpBuffer buffer, IndxInfo *indxinfo, int enc, bool coll_unknown, - Archive *fount); + Archive *fout); static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions, const char *prefix, Archive *fout); static char *get_synchronized_snapshot(Archive *fout); From b41645460af563cfd4e4f57f354058cf69ef3b14 Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Fri, 29 Jan 2021 15:27:55 +0300 Subject: [PATCH 209/240] Document behavior of the .** jsonpath accessor in the lax mode When the .** jsonpath accessor handles the array, it selects both array and each of its elements. When using lax mode, subsequent accessors automatically unwrap arrays. So, the content of each array element may be selected twice. Even though this behavior is counterintuitive, it's correct because everything works as designed. This commit documents it. Backpatch to 12 where the jsonpath language was introduced. Reported-by: Thomas Kellerer Bug: #16828 Discussion: https://postgr.es/m/16828-2b0229babfad2d8c%40postgresql.org Discussion: https://postgr.es/m/CAPpHfdtS-nNidT%3DEqZbAYOPcnNOWh_sd6skVdu2CAQUGdvpT8Q%40mail.gmail.com Author: Alexandex Korotkov, revised by Tom Lane Reviewed-by: Alvaro Herrera, Thomas Kellerer, Tom Lane Backpatch-through: 12 --- doc/src/sgml/func.sgml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 4342c8e74fd1f..de1b1b6debda1 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -16277,6 +16277,24 @@ strict $.track.segments[*].location + + The .** accessor can lead to surprising results + when using the lax mode. For instance, the following query selects every + HR value twice: + +lax $.**.HR + + This happens because the .** accessor selects both + the segments array and each of its elements, while + the .HR accessor automatically unwraps arrays when + using the lax mode. To avoid surprising results, we recommend using + the .** accessor only in the strict mode. The + following query selects each HR value just once: + +strict $.**.HR + + + From f743a2bbd4e511ad58b6ce01f81841e5e1611474 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 29 Jan 2021 10:46:14 -0500 Subject: [PATCH 210/240] Doc: improve cross-references for SET/SHOW. The corresponding functions set_config and current_setting were mostly not hyperlinked. Clarify their descriptions a tad, too. Discussion: https://postgr.es/m/161183356250.4077.687338658090583892@wrigleys.postgresql.org --- doc/src/sgml/config.sgml | 10 ++++++---- doc/src/sgml/func.sgml | 13 +++++++------ doc/src/sgml/ref/set.sgml | 2 +- doc/src/sgml/ref/show.sgml | 2 +- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index f1037df5a98e4..e17cdcc8167e8 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -263,8 +263,9 @@ shared_buffers = 128MB The SHOW command allows inspection of the - current value of all parameters. The corresponding function is - current_setting(setting_name text). + current value of any parameter. The corresponding SQL function is + current_setting(setting_name text) + (see ). @@ -273,8 +274,9 @@ shared_buffers = 128MB The SET command allows modification of the current value of those parameters that can be set locally to a session; it has no effect on other sessions. - The corresponding function is - set_config(setting_name, new_value, is_local). + The corresponding SQL function is + set_config(setting_name, new_value, is_local) + (see ). diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index de1b1b6debda1..f30eaa3e4bac6 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -24593,8 +24593,9 @@ SELECT collation for ('foo' COLLATE "de_DE"); setting setting_name. If there is no such setting, current_setting throws an error unless missing_ok is supplied and - is true. This function corresponds to - the SQL command SHOW. + is true (in which case NULL is returned). + This function corresponds to + the SQL command . current_setting('datestyle') @@ -24617,10 +24618,10 @@ SELECT collation for ('foo' COLLATE "de_DE"); Sets the parameter setting_name to new_value, and returns that value. If is_local is true, the new - value will only apply for the current transaction. If you want the new - value to apply for the current session, use false - instead. This function corresponds to the SQL - command SET. + value will only apply during the current transaction. If you want the + new value to apply for the rest of the current session, + use false instead. This function corresponds to + the SQL command . set_config('log_statement_stats', 'off', false) diff --git a/doc/src/sgml/ref/set.sgml b/doc/src/sgml/ref/set.sgml index 63f312e812a87..339ee9eec9480 100644 --- a/doc/src/sgml/ref/set.sgml +++ b/doc/src/sgml/ref/set.sgml @@ -267,7 +267,7 @@ SELECT setseed(value); The function set_config provides equivalent - functionality; see . + functionality; see . Also, it is possible to UPDATE the pg_settings system view to perform the equivalent of SET. diff --git a/doc/src/sgml/ref/show.sgml b/doc/src/sgml/ref/show.sgml index 945b0491b14ec..93789ee0be058 100644 --- a/doc/src/sgml/ref/show.sgml +++ b/doc/src/sgml/ref/show.sgml @@ -129,7 +129,7 @@ SHOW ALL The function current_setting produces - equivalent output; see . + equivalent output; see . Also, the pg_settings system view produces the same information. From f77717b2985aa529a185e6988de26b885ca10ddb Mon Sep 17 00:00:00 2001 From: Fujii Masao Date: Sat, 30 Jan 2021 10:12:22 +0900 Subject: [PATCH 211/240] postgres_fdw: Fix tests for CLOBBER_CACHE_ALWAYS. The regression tests added in commits 708d165ddb and 411ae64997 caused buildfarm failures when CLOBBER_CACHE_ALWAYS was enabled. This commit stabilizes those tests. The foreign server connections established by postgres_fdw behaves differently depending on whether CLOBBER_CACHE_ALWAYS is enabled or not. If it's not enabled, those connections are cached. On the other hand, if it's enabled, when the connections are established outside transaction block, they are not cached (i.e., they are immediately closed at the end of query that established them). So the subsequent postgres_fdw_get_connections() cannot list those connections and postgres_fdw_disconnect() cannot close them (because they are already closed). When the connections are established inside transaction block, they are cached whether CLOBBER_CACHE_ALWAYS was enabled or not. But if it's enabled, they are immediately marked as invalid, otherwise not. This causes the subsequent postgres_fdw_get_connections() to return different result in "valid" column depending on whether CLOBBER_CACHE_ALWAYS was enabled or not. This commit prevents the above differences of behavior from affecting the regression tests. Per buildfarm failure on trilobite. Original patch by Bharath Rupireddy. I (Fujii Masao) extracted the regression test fix from that and revised it a bit. Reported-by: Tom Lane Author: Bharath Rupireddy Reviewed-by: Fujii Masao Discussion: https://postgr.es/m/2688508.1611865371@sss.pgh.pa.us --- .../postgres_fdw/expected/postgres_fdw.out | 223 +++++++----------- contrib/postgres_fdw/sql/postgres_fdw.sql | 97 +++----- 2 files changed, 121 insertions(+), 199 deletions(-) diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index 07e06e5bf7310..b09dce63f5ffa 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -17,10 +17,6 @@ DO $d$ OPTIONS (dbname '$$||current_database()||$$', port '$$||current_setting('port')||$$' )$$; - EXECUTE $$CREATE SERVER loopback4 FOREIGN DATA WRAPPER postgres_fdw - OPTIONS (dbname '$$||current_database()||$$', - port '$$||current_setting('port')||$$' - )$$; END; $d$; CREATE USER MAPPING FOR public SERVER testserver1 @@ -28,7 +24,6 @@ CREATE USER MAPPING FOR public SERVER testserver1 CREATE USER MAPPING FOR CURRENT_USER SERVER loopback; CREATE USER MAPPING FOR CURRENT_USER SERVER loopback2; CREATE USER MAPPING FOR public SERVER loopback3; -CREATE USER MAPPING FOR public SERVER loopback4; -- =================================================================== -- create objects used through FDW loopback server -- =================================================================== @@ -144,11 +139,6 @@ CREATE FOREIGN TABLE ft7 ( c2 int NOT NULL, c3 text ) SERVER loopback3 OPTIONS (schema_name 'S 1', table_name 'T 4'); -CREATE FOREIGN TABLE ft8 ( - c1 int NOT NULL, - c2 int NOT NULL, - c3 text -) SERVER loopback4 OPTIONS (schema_name 'S 1', table_name 'T 4'); -- =================================================================== -- tests for validator -- =================================================================== @@ -220,8 +210,7 @@ ALTER FOREIGN TABLE ft2 ALTER COLUMN c1 OPTIONS (column_name 'C 1'); public | ft5 | loopback | (schema_name 'S 1', table_name 'T 4') | public | ft6 | loopback2 | (schema_name 'S 1', table_name 'T 4') | public | ft7 | loopback3 | (schema_name 'S 1', table_name 'T 4') | - public | ft8 | loopback4 | (schema_name 'S 1', table_name 'T 4') | -(7 rows) +(6 rows) -- Test that alteration of server options causes reconnection -- Remote's errors might be non-English, so hide them to ensure stable results @@ -9066,15 +9055,21 @@ DROP PROCEDURE terminate_backend_and_wait(text); -- ============================================================================= -- test connection invalidation cases and postgres_fdw_get_connections function -- ============================================================================= --- This test case is for closing the connection in pgfdw_xact_callback -BEGIN; --- List all the existing cached connections. Only loopback2 should be output. -SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; - server_name | valid --------------+------- - loopback2 | t +-- Let's ensure to close all the existing cached connections. +SELECT 1 FROM postgres_fdw_disconnect_all(); + ?column? +---------- + 1 (1 row) +-- No cached connections, so no records should be output. +SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1; + server_name +------------- +(0 rows) + +-- This test case is for closing the connection in pgfdw_xact_callback +BEGIN; -- Connection xact depth becomes 1 i.e. the connection is in midst of the xact. SELECT 1 FROM ft1 LIMIT 1; ?column? @@ -9088,19 +9083,18 @@ SELECT 1 FROM ft7 LIMIT 1; 1 (1 row) --- List all the existing cached connections. loopback and loopback3 --- also should be output as valid connections. -SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; - server_name | valid --------------+------- - loopback | t - loopback2 | t - loopback3 | t -(3 rows) +-- List all the existing cached connections. loopback and loopback3 should be +-- output. +SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1; + server_name +------------- + loopback + loopback3 +(2 rows) --- Connection is not closed at the end of the alter statement in --- pgfdw_inval_callback. That's because the connection is in midst of this --- xact, it is just marked as invalid. +-- Connections are not closed at the end of the alter and drop statements. +-- That's because the connections are in midst of this xact, +-- they are just marked as invalid in pgfdw_inval_callback. ALTER SERVER loopback OPTIONS (ADD use_remote_estimate 'off'); DROP SERVER loopback3 CASCADE; NOTICE: drop cascades to 2 other objects @@ -9113,31 +9107,22 @@ SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; server_name | valid -------------+------- loopback | f - loopback2 | t | f -(3 rows) +(2 rows) --- The invalid connection gets closed in pgfdw_xact_callback during commit. +-- The invalid connections get closed in pgfdw_xact_callback during commit. COMMIT; --- List all the existing cached connections. loopback and loopback3 --- should not be output because they should be closed at the end of --- the above transaction. -SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; - server_name | valid --------------+------- - loopback2 | t -(1 row) +-- All cached connections were closed while committing above xact, so no +-- records should be output. +SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1; + server_name +------------- +(0 rows) -- ======================================================================= -- test postgres_fdw_disconnect and postgres_fdw_disconnect_all functions -- ======================================================================= --- Return true as all cached connections are closed. -SELECT postgres_fdw_disconnect_all(); - postgres_fdw_disconnect_all ------------------------------ - t -(1 row) - +BEGIN; -- Ensure to cache loopback connection. SELECT 1 FROM ft1 LIMIT 1; ?column? @@ -9145,7 +9130,6 @@ SELECT 1 FROM ft1 LIMIT 1; 1 (1 row) -BEGIN; -- Ensure to cache loopback2 connection. SELECT 1 FROM ft6 LIMIT 1; ?column? @@ -9155,66 +9139,31 @@ SELECT 1 FROM ft6 LIMIT 1; -- List all the existing cached connections. loopback and loopback2 should be -- output. -SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; - server_name | valid --------------+------- - loopback | t - loopback2 | t +SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1; + server_name +------------- + loopback + loopback2 (2 rows) --- Issue a warning and return false as loopback2 connection is still in use and +-- Issue a warning and return false as loopback connection is still in use and -- can not be closed. -SELECT postgres_fdw_disconnect('loopback2'); -WARNING: cannot close connection for server "loopback2" because it is still in use +SELECT postgres_fdw_disconnect('loopback'); +WARNING: cannot close connection for server "loopback" because it is still in use postgres_fdw_disconnect ------------------------- f (1 row) --- Close loopback connection, return true and issue a warning as loopback2 --- connection is still in use and can not be closed. -SELECT postgres_fdw_disconnect_all(); -WARNING: cannot close connection for server "loopback2" because it is still in use - postgres_fdw_disconnect_all ------------------------------ - t -(1 row) - --- List all the existing cached connections. loopback2 should be output. -SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; - server_name | valid --------------+------- - loopback2 | t -(1 row) - --- Ensure to cache loopback connection. -SELECT 1 FROM ft1 LIMIT 1; - ?column? ----------- - 1 -(1 row) - --- Ensure to cache loopback4 connection. -SELECT 1 FROM ft8 LIMIT 1; - ?column? ----------- - 1 -(1 row) - --- List all the existing cached connections. loopback, loopback2, loopback4 --- should be output. -SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; - server_name | valid --------------+------- - loopback | t - loopback2 | t - loopback4 | t -(3 rows) +-- List all the existing cached connections. loopback and loopback2 should be +-- output. +SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1; + server_name +------------- + loopback + loopback2 +(2 rows) -DROP SERVER loopback4 CASCADE; -NOTICE: drop cascades to 2 other objects -DETAIL: drop cascades to user mapping for public on server loopback4 -drop cascades to foreign table ft8 -- Return false as connections are still in use, warnings are issued. -- But disable warnings temporarily because the order of them is not stable. SET client_min_messages = 'ERROR'; @@ -9226,21 +9175,19 @@ SELECT postgres_fdw_disconnect_all(); RESET client_min_messages; COMMIT; --- Close loopback2 connection and return true. -SELECT postgres_fdw_disconnect('loopback2'); - postgres_fdw_disconnect -------------------------- - t +-- Ensure that loopback2 connection is closed. +SELECT 1 FROM postgres_fdw_disconnect('loopback2'); + ?column? +---------- + 1 (1 row) --- List all the existing cached connections. loopback should be output. -SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; - server_name | valid --------------+------- - loopback | t -(1 row) +SELECT server_name FROM postgres_fdw_get_connections() WHERE server_name = 'loopback2'; + server_name +------------- +(0 rows) --- Return false as loopback2 connectin is closed already. +-- Return false as loopback2 connection is closed already. SELECT postgres_fdw_disconnect('loopback2'); postgres_fdw_disconnect ------------------------- @@ -9250,18 +9197,17 @@ SELECT postgres_fdw_disconnect('loopback2'); -- Return an error as there is no foreign server with given name. SELECT postgres_fdw_disconnect('unknownserver'); ERROR: server "unknownserver" does not exist --- Close loopback connection and return true. -SELECT postgres_fdw_disconnect_all(); - postgres_fdw_disconnect_all ------------------------------ - t +-- Let's ensure to close all the existing cached connections. +SELECT 1 FROM postgres_fdw_disconnect_all(); + ?column? +---------- + 1 (1 row) --- List all the existing cached connections. No connection exists, so NULL --- should be output. -SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; - server_name | valid --------------+------- +-- No cached connections, so no records should be output. +SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1; + server_name +------------- (0 rows) -- ============================================================================= @@ -9271,6 +9217,7 @@ CREATE ROLE regress_multi_conn_user1 SUPERUSER; CREATE ROLE regress_multi_conn_user2 SUPERUSER; CREATE USER MAPPING FOR regress_multi_conn_user1 SERVER loopback; CREATE USER MAPPING FOR regress_multi_conn_user2 SERVER loopback; +BEGIN; -- Will cache loopback connection with user mapping for regress_multi_conn_user1 SET ROLE regress_multi_conn_user1; SELECT 1 FROM ft1 LIMIT 1; @@ -9290,25 +9237,25 @@ SELECT 1 FROM ft1 LIMIT 1; RESET ROLE; -- Should output two connections for loopback server -SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; - server_name | valid --------------+------- - loopback | t - loopback | t +SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1; + server_name +------------- + loopback + loopback (2 rows) --- Close loopback connections and return true. -SELECT postgres_fdw_disconnect('loopback'); - postgres_fdw_disconnect -------------------------- - t +COMMIT; +-- Let's ensure to close all the existing cached connections. +SELECT 1 FROM postgres_fdw_disconnect_all(); + ?column? +---------- + 1 (1 row) --- List all the existing cached connections. No connection exists, so NULL --- should be output. -SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; - server_name | valid --------------+------- +-- No cached connections, so no records should be output. +SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1; + server_name +------------- (0 rows) -- Clean up diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql index 647192cf6ace6..319c15d635c06 100644 --- a/contrib/postgres_fdw/sql/postgres_fdw.sql +++ b/contrib/postgres_fdw/sql/postgres_fdw.sql @@ -19,10 +19,6 @@ DO $d$ OPTIONS (dbname '$$||current_database()||$$', port '$$||current_setting('port')||$$' )$$; - EXECUTE $$CREATE SERVER loopback4 FOREIGN DATA WRAPPER postgres_fdw - OPTIONS (dbname '$$||current_database()||$$', - port '$$||current_setting('port')||$$' - )$$; END; $d$; @@ -31,7 +27,6 @@ CREATE USER MAPPING FOR public SERVER testserver1 CREATE USER MAPPING FOR CURRENT_USER SERVER loopback; CREATE USER MAPPING FOR CURRENT_USER SERVER loopback2; CREATE USER MAPPING FOR public SERVER loopback3; -CREATE USER MAPPING FOR public SERVER loopback4; -- =================================================================== -- create objects used through FDW loopback server @@ -158,12 +153,6 @@ CREATE FOREIGN TABLE ft7 ( c3 text ) SERVER loopback3 OPTIONS (schema_name 'S 1', table_name 'T 4'); -CREATE FOREIGN TABLE ft8 ( - c1 int NOT NULL, - c2 int NOT NULL, - c3 text -) SERVER loopback4 OPTIONS (schema_name 'S 1', table_name 'T 4'); - -- =================================================================== -- tests for validator -- =================================================================== @@ -2723,80 +2712,67 @@ DROP PROCEDURE terminate_backend_and_wait(text); -- ============================================================================= -- test connection invalidation cases and postgres_fdw_get_connections function -- ============================================================================= +-- Let's ensure to close all the existing cached connections. +SELECT 1 FROM postgres_fdw_disconnect_all(); +-- No cached connections, so no records should be output. +SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1; -- This test case is for closing the connection in pgfdw_xact_callback BEGIN; --- List all the existing cached connections. Only loopback2 should be output. -SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; -- Connection xact depth becomes 1 i.e. the connection is in midst of the xact. SELECT 1 FROM ft1 LIMIT 1; SELECT 1 FROM ft7 LIMIT 1; --- List all the existing cached connections. loopback and loopback3 --- also should be output as valid connections. -SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; --- Connection is not closed at the end of the alter statement in --- pgfdw_inval_callback. That's because the connection is in midst of this --- xact, it is just marked as invalid. +-- List all the existing cached connections. loopback and loopback3 should be +-- output. +SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1; +-- Connections are not closed at the end of the alter and drop statements. +-- That's because the connections are in midst of this xact, +-- they are just marked as invalid in pgfdw_inval_callback. ALTER SERVER loopback OPTIONS (ADD use_remote_estimate 'off'); DROP SERVER loopback3 CASCADE; -- List all the existing cached connections. loopback and loopback3 -- should be output as invalid connections. Also the server name for -- loopback3 should be NULL because the server was dropped. SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; --- The invalid connection gets closed in pgfdw_xact_callback during commit. +-- The invalid connections get closed in pgfdw_xact_callback during commit. COMMIT; --- List all the existing cached connections. loopback and loopback3 --- should not be output because they should be closed at the end of --- the above transaction. -SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; +-- All cached connections were closed while committing above xact, so no +-- records should be output. +SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1; -- ======================================================================= -- test postgres_fdw_disconnect and postgres_fdw_disconnect_all functions -- ======================================================================= --- Return true as all cached connections are closed. -SELECT postgres_fdw_disconnect_all(); +BEGIN; -- Ensure to cache loopback connection. SELECT 1 FROM ft1 LIMIT 1; -BEGIN; -- Ensure to cache loopback2 connection. SELECT 1 FROM ft6 LIMIT 1; -- List all the existing cached connections. loopback and loopback2 should be -- output. -SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; --- Issue a warning and return false as loopback2 connection is still in use and +SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1; +-- Issue a warning and return false as loopback connection is still in use and -- can not be closed. -SELECT postgres_fdw_disconnect('loopback2'); --- Close loopback connection, return true and issue a warning as loopback2 --- connection is still in use and can not be closed. -SELECT postgres_fdw_disconnect_all(); --- List all the existing cached connections. loopback2 should be output. -SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; --- Ensure to cache loopback connection. -SELECT 1 FROM ft1 LIMIT 1; --- Ensure to cache loopback4 connection. -SELECT 1 FROM ft8 LIMIT 1; --- List all the existing cached connections. loopback, loopback2, loopback4 --- should be output. -SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; -DROP SERVER loopback4 CASCADE; +SELECT postgres_fdw_disconnect('loopback'); +-- List all the existing cached connections. loopback and loopback2 should be +-- output. +SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1; -- Return false as connections are still in use, warnings are issued. -- But disable warnings temporarily because the order of them is not stable. SET client_min_messages = 'ERROR'; SELECT postgres_fdw_disconnect_all(); RESET client_min_messages; COMMIT; --- Close loopback2 connection and return true. -SELECT postgres_fdw_disconnect('loopback2'); --- List all the existing cached connections. loopback should be output. -SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; --- Return false as loopback2 connectin is closed already. +-- Ensure that loopback2 connection is closed. +SELECT 1 FROM postgres_fdw_disconnect('loopback2'); +SELECT server_name FROM postgres_fdw_get_connections() WHERE server_name = 'loopback2'; +-- Return false as loopback2 connection is closed already. SELECT postgres_fdw_disconnect('loopback2'); -- Return an error as there is no foreign server with given name. SELECT postgres_fdw_disconnect('unknownserver'); --- Close loopback connection and return true. -SELECT postgres_fdw_disconnect_all(); --- List all the existing cached connections. No connection exists, so NULL --- should be output. -SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; +-- Let's ensure to close all the existing cached connections. +SELECT 1 FROM postgres_fdw_disconnect_all(); +-- No cached connections, so no records should be output. +SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1; -- ============================================================================= -- test case for having multiple cached connections for a foreign server @@ -2806,6 +2782,7 @@ CREATE ROLE regress_multi_conn_user2 SUPERUSER; CREATE USER MAPPING FOR regress_multi_conn_user1 SERVER loopback; CREATE USER MAPPING FOR regress_multi_conn_user2 SERVER loopback; +BEGIN; -- Will cache loopback connection with user mapping for regress_multi_conn_user1 SET ROLE regress_multi_conn_user1; SELECT 1 FROM ft1 LIMIT 1; @@ -2817,14 +2794,12 @@ SELECT 1 FROM ft1 LIMIT 1; RESET ROLE; -- Should output two connections for loopback server -SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; - --- Close loopback connections and return true. -SELECT postgres_fdw_disconnect('loopback'); - --- List all the existing cached connections. No connection exists, so NULL --- should be output. -SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; +SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1; +COMMIT; +-- Let's ensure to close all the existing cached connections. +SELECT 1 FROM postgres_fdw_disconnect_all(); +-- No cached connections, so no records should be output. +SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1; -- Clean up DROP USER MAPPING FOR regress_multi_conn_user1 SERVER loopback; From 8a54e12a38d1545d249f1402f66c8cde2837d97c Mon Sep 17 00:00:00 2001 From: Noah Misch Date: Sat, 30 Jan 2021 00:00:27 -0800 Subject: [PATCH 212/240] Fix CREATE INDEX CONCURRENTLY for simultaneous prepared transactions. In a cluster having used CREATE INDEX CONCURRENTLY while having enabled prepared transactions, queries that use the resulting index can silently fail to find rows. Fix this for future CREATE INDEX CONCURRENTLY by making it wait for prepared transactions like it waits for ordinary transactions. This expands the VirtualTransactionId structure domain to admit prepared transactions. It may be necessary to reindex to recover from past occurrences. Back-patch to 9.5 (all supported versions). Andrey Borodin, reviewed (in earlier versions) by Tom Lane and Michael Paquier. Discussion: https://postgr.es/m/2E712143-97F7-4890-B470-4A35142ABC82@yandex-team.ru --- src/backend/storage/lmgr/lmgr.c | 3 +- src/backend/storage/lmgr/lock.c | 43 +++++++++++-------- src/include/storage/lock.h | 17 ++++---- src/test/isolation/Makefile | 11 +++-- src/test/isolation/README | 6 +-- .../expected/prepared-transactions-cic.out | 18 ++++++++ .../specs/prepared-transactions-cic.spec | 37 ++++++++++++++++ 7 files changed, 98 insertions(+), 37 deletions(-) create mode 100644 src/test/isolation/expected/prepared-transactions-cic.out create mode 100644 src/test/isolation/specs/prepared-transactions-cic.spec diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c index 7407672c9d316..5736d03083f1a 100644 --- a/src/backend/storage/lmgr/lmgr.c +++ b/src/backend/storage/lmgr/lmgr.c @@ -904,8 +904,7 @@ WaitForLockersMultiple(List *locktags, LOCKMODE lockmode, bool progress) /* * Note: GetLockConflicts() never reports our own xid, hence we need not - * check for that. Also, prepared xacts are not reported, which is fine - * since they certainly aren't going to do anything anymore. + * check for that. Also, prepared xacts are reported and awaited. */ /* Finally wait for each such transaction to complete */ diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c index 20e50247ea491..79c1cf9b8b4e3 100644 --- a/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@ -2903,9 +2903,7 @@ FastPathGetRelationLockEntry(LOCALLOCK *locallock) * so use of this function has to be thought about carefully. * * Note we never include the current xact's vxid in the result array, - * since an xact never blocks itself. Also, prepared transactions are - * ignored, which is a bit more debatable but is appropriate for current - * uses of the result. + * since an xact never blocks itself. */ VirtualTransactionId * GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp) @@ -2930,19 +2928,21 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp) /* * Allocate memory to store results, and fill with InvalidVXID. We only - * need enough space for MaxBackends + a terminator, since prepared xacts - * don't count. InHotStandby allocate once in TopMemoryContext. + * need enough space for MaxBackends + max_prepared_xacts + a terminator. + * InHotStandby allocate once in TopMemoryContext. */ if (InHotStandby) { if (vxids == NULL) vxids = (VirtualTransactionId *) MemoryContextAlloc(TopMemoryContext, - sizeof(VirtualTransactionId) * (MaxBackends + 1)); + sizeof(VirtualTransactionId) * + (MaxBackends + max_prepared_xacts + 1)); } else vxids = (VirtualTransactionId *) - palloc0(sizeof(VirtualTransactionId) * (MaxBackends + 1)); + palloc0(sizeof(VirtualTransactionId) * + (MaxBackends + max_prepared_xacts + 1)); /* Compute hash code and partition lock, and look up conflicting modes. */ hashcode = LockTagHashCode(locktag); @@ -3017,13 +3017,9 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp) /* Conflict! */ GET_VXID_FROM_PGPROC(vxid, *proc); - /* - * If we see an invalid VXID, then either the xact has already - * committed (or aborted), or it's a prepared xact. In either - * case we may ignore it. - */ if (VirtualTransactionIdIsValid(vxid)) vxids[count++] = vxid; + /* else, xact already committed or aborted */ /* No need to examine remaining slots. */ break; @@ -3082,11 +3078,6 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp) GET_VXID_FROM_PGPROC(vxid, *proc); - /* - * If we see an invalid VXID, then either the xact has already - * committed (or aborted), or it's a prepared xact. In either - * case we may ignore it. - */ if (VirtualTransactionIdIsValid(vxid)) { int i; @@ -3098,6 +3089,7 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp) if (i >= fast_count) vxids[count++] = vxid; } + /* else, xact already committed or aborted */ } } @@ -3107,7 +3099,7 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp) LWLockRelease(partitionLock); - if (count > MaxBackends) /* should never happen */ + if (count > MaxBackends + max_prepared_xacts) /* should never happen */ elog(PANIC, "too many conflicting locks found"); vxids[count].backendId = InvalidBackendId; @@ -4464,6 +4456,21 @@ VirtualXactLock(VirtualTransactionId vxid, bool wait) Assert(VirtualTransactionIdIsValid(vxid)); + if (VirtualTransactionIdIsPreparedXact(vxid)) + { + LockAcquireResult lar; + + /* + * Prepared transactions don't hold vxid locks. The + * LocalTransactionId is always a normal, locked XID. + */ + SET_LOCKTAG_TRANSACTION(tag, vxid.localTransactionId); + lar = LockAcquire(&tag, ShareLock, false, !wait); + if (lar != LOCKACQUIRE_NOT_AVAIL) + LockRelease(&tag, ShareLock, false); + return lar != LOCKACQUIRE_NOT_AVAIL; + } + SET_LOCKTAG_VIRTUALTRANSACTION(tag, vxid); /* diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h index 2e6ef174e9a72..68a3487d49f3c 100644 --- a/src/include/storage/lock.h +++ b/src/include/storage/lock.h @@ -46,10 +46,10 @@ extern bool Debug_deadlocks; /* * Top-level transactions are identified by VirtualTransactionIDs comprising - * the BackendId of the backend running the xact, plus a locally-assigned - * LocalTransactionId. These are guaranteed unique over the short term, - * but will be reused after a database restart; hence they should never - * be stored on disk. + * PGPROC fields backendId and lxid. For prepared transactions, the + * LocalTransactionId is an ordinary XID. These are guaranteed unique over + * the short term, but will be reused after a database restart or XID + * wraparound; hence they should never be stored on disk. * * Note that struct VirtualTransactionId can not be assumed to be atomically * assignable as a whole. However, type LocalTransactionId is assumed to @@ -61,15 +61,16 @@ extern bool Debug_deadlocks; */ typedef struct { - BackendId backendId; /* determined at backend startup */ - LocalTransactionId localTransactionId; /* backend-local transaction id */ + BackendId backendId; /* backendId from PGPROC */ + LocalTransactionId localTransactionId; /* lxid from PGPROC */ } VirtualTransactionId; #define InvalidLocalTransactionId 0 #define LocalTransactionIdIsValid(lxid) ((lxid) != InvalidLocalTransactionId) #define VirtualTransactionIdIsValid(vxid) \ - (((vxid).backendId != InvalidBackendId) && \ - LocalTransactionIdIsValid((vxid).localTransactionId)) + (LocalTransactionIdIsValid((vxid).localTransactionId)) +#define VirtualTransactionIdIsPreparedXact(vxid) \ + ((vxid).backendId == InvalidBackendId) #define VirtualTransactionIdEquals(vxid1, vxid2) \ ((vxid1).backendId == (vxid2).backendId && \ (vxid1).localTransactionId == (vxid2).localTransactionId) diff --git a/src/test/isolation/Makefile b/src/test/isolation/Makefile index d23e2cec64009..edff04f041cdf 100644 --- a/src/test/isolation/Makefile +++ b/src/test/isolation/Makefile @@ -62,12 +62,11 @@ installcheck: all check: all $(pg_isolation_regress_check) --schedule=$(srcdir)/isolation_schedule -# Versions of the check tests that include the prepared-transactions test -# It only makes sense to run these if set up to use prepared transactions, -# via TEMP_CONFIG for the check case, or via the postgresql.conf for the -# installcheck case. +# Non-default tests. It only makes sense to run these if set up to use +# prepared transactions, via TEMP_CONFIG for the check case, or via the +# postgresql.conf for the installcheck case. installcheck-prepared-txns: all temp-install - $(pg_isolation_regress_installcheck) --schedule=$(srcdir)/isolation_schedule prepared-transactions + $(pg_isolation_regress_installcheck) --schedule=$(srcdir)/isolation_schedule prepared-transactions prepared-transactions-cic check-prepared-txns: all temp-install - $(pg_isolation_regress_check) --schedule=$(srcdir)/isolation_schedule prepared-transactions + $(pg_isolation_regress_check) --schedule=$(srcdir)/isolation_schedule prepared-transactions prepared-transactions-cic diff --git a/src/test/isolation/README b/src/test/isolation/README index 217953d1834ad..6ae71523258a5 100644 --- a/src/test/isolation/README +++ b/src/test/isolation/README @@ -23,9 +23,9 @@ you can do something like ./pg_isolation_regress fk-contention fk-deadlock (look into the specs/ subdirectory to see the available tests). -The prepared-transactions test requires the server's -max_prepared_transactions parameter to be set to at least 3; therefore it -is not run by default. To include it in the test run, use +Certain tests require the server's max_prepared_transactions parameter to be +set to at least 3; therefore they are not run by default. To include them in +the test run, use make check-prepared-txns or make installcheck-prepared-txns diff --git a/src/test/isolation/expected/prepared-transactions-cic.out b/src/test/isolation/expected/prepared-transactions-cic.out new file mode 100644 index 0000000000000..043ec3c36362e --- /dev/null +++ b/src/test/isolation/expected/prepared-transactions-cic.out @@ -0,0 +1,18 @@ +Parsed test spec with 2 sessions + +starting permutation: w1 p1 cic2 c1 r2 +step w1: BEGIN; INSERT INTO cic_test VALUES (1); +step p1: PREPARE TRANSACTION 's1'; +step cic2: + CREATE INDEX CONCURRENTLY on cic_test(a); + +ERROR: canceling statement due to lock timeout +step c1: COMMIT PREPARED 's1'; +step r2: + SET enable_seqscan to off; + SET enable_bitmapscan to off; + SELECT * FROM cic_test WHERE a = 1; + +a + +1 diff --git a/src/test/isolation/specs/prepared-transactions-cic.spec b/src/test/isolation/specs/prepared-transactions-cic.spec new file mode 100644 index 0000000000000..c39eaf5ad0c52 --- /dev/null +++ b/src/test/isolation/specs/prepared-transactions-cic.spec @@ -0,0 +1,37 @@ +# This test verifies that CREATE INDEX CONCURRENTLY interacts with prepared +# transactions correctly. +setup +{ + CREATE TABLE cic_test (a int); +} + +teardown +{ + DROP TABLE cic_test; +} + + +# Sessions for CREATE INDEX CONCURRENTLY test +session "s1" +step "w1" { BEGIN; INSERT INTO cic_test VALUES (1); } +step "p1" { PREPARE TRANSACTION 's1'; } +step "c1" { COMMIT PREPARED 's1'; } + +session "s2" +# The isolation tester never recognizes that a lock of s1 blocks s2, because a +# prepared transaction's locks have no pid associated. While there's a slight +# chance of timeout while waiting for an autovacuum-held lock, that wouldn't +# change the output. Hence, no timeout is too short. +setup { SET lock_timeout = 10; } +step "cic2" +{ + CREATE INDEX CONCURRENTLY on cic_test(a); +} +step "r2" +{ + SET enable_seqscan to off; + SET enable_bitmapscan to off; + SELECT * FROM cic_test WHERE a = 1; +} + +permutation "w1" "p1" "cic2" "c1" "r2" From 360bd2321b1ad9c47466bc485ee5eb2f4515372e Mon Sep 17 00:00:00 2001 From: Noah Misch Date: Sat, 30 Jan 2021 00:11:38 -0800 Subject: [PATCH 213/240] Fix error with CREATE PUBLICATION, wal_level=minimal, and new tables. CREATE PUBLICATION has failed spuriously when applied to a permanent relation created or rewritten in the current transaction. Make the same change to another site having the same semantic intent; the second instance has no user-visible consequences. Back-patch to v13, where commit c6b92041d38512a4176ed76ad06f713d2e6c01a8 broke this. Kyotaro Horiguchi Discussion: https://postgr.es/m/20210113.160705.2225256954956139776.horikyota.ntt@gmail.com --- src/backend/catalog/pg_publication.c | 2 +- src/backend/optimizer/util/plancat.c | 3 ++- src/test/subscription/t/001_rep_changes.pl | 20 +++++++++++++++++++- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c index 5f8e1c64e18f1..84d2efcfd2f16 100644 --- a/src/backend/catalog/pg_publication.c +++ b/src/backend/catalog/pg_publication.c @@ -67,7 +67,7 @@ check_publication_add_relation(Relation targetrel) errdetail("System tables cannot be added to publications."))); /* UNLOGGED and TEMP relations cannot be part of publication. */ - if (!RelationNeedsWAL(targetrel)) + if (targetrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("table \"%s\" cannot be replicated", diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index da322b453ea74..177e6e336ab9d 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -126,7 +126,8 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, relation = table_open(relationObjectId, NoLock); /* Temporary and unlogged relations are inaccessible during recovery. */ - if (!RelationNeedsWAL(relation) && RecoveryInProgress()) + if (relation->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT && + RecoveryInProgress()) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot access temporary or unlogged relations during recovery"))); diff --git a/src/test/subscription/t/001_rep_changes.pl b/src/test/subscription/t/001_rep_changes.pl index c20fadcb0e340..04635e93e9959 100644 --- a/src/test/subscription/t/001_rep_changes.pl +++ b/src/test/subscription/t/001_rep_changes.pl @@ -3,7 +3,7 @@ use warnings; use PostgresNode; use TestLib; -use Test::More tests => 27; +use Test::More tests => 28; # Initialize publisher node my $node_publisher = get_new_node('publisher'); @@ -451,3 +451,21 @@ $node_subscriber->stop('fast'); $node_publisher->stop('fast'); + +# CREATE PUBLICATION while wal_level=minimal should succeed, with a WARNING +$node_publisher->append_conf( + 'postgresql.conf', qq( +wal_level=minimal +max_wal_senders=0 +)); +$node_publisher->start; +($result, my $retout, my $reterr) = $node_publisher->psql( + 'postgres', qq{ +BEGIN; +CREATE TABLE skip_wal(); +CREATE PUBLICATION tap_pub2 FOR TABLE skip_wal; +ROLLBACK; +}); +ok( $reterr =~ + m/WARNING: wal_level is insufficient to publish logical changes/, + 'CREATE PUBLICATION while wal_level=minimal'); From 7da83415e5bc01bba0093f34f4f612b70c70b678 Mon Sep 17 00:00:00 2001 From: Noah Misch Date: Sat, 30 Jan 2021 00:12:18 -0800 Subject: [PATCH 214/240] Revive "snapshot too old" with wal_level=minimal and SET TABLESPACE. Given a permanent relation rewritten in the current transaction, the old_snapshot_threshold mechanism assumed the relation had never been subject to early pruning. Hence, a query could fail to report "snapshot too old" when the rewrite followed an early truncation. ALTER TABLE SET TABLESPACE is probably the only rewrite mechanism capable of exposing this bug. REINDEX sets indcheckxmin, avoiding the problem. CLUSTER has zeroed page LSNs since before old_snapshot_threshold existed, so old_snapshot_threshold has never cooperated with it. ALTER TABLE ... SET DATA TYPE makes the table look empty to every past snapshot, which is strictly worse. Back-patch to v13, where commit c6b92041d38512a4176ed76ad06f713d2e6c01a8 broke this. Kyotaro Horiguchi and Noah Misch Discussion: https://postgr.es/m/20210113.160705.2225256954956139776.horikyota.ntt@gmail.com --- src/backend/utils/time/snapmgr.c | 6 +++++- src/include/utils/snapmgr.h | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c index ae16c3ed7d60b..95704265b6785 100644 --- a/src/backend/utils/time/snapmgr.c +++ b/src/backend/utils/time/snapmgr.c @@ -1764,7 +1764,11 @@ TransactionIdLimitedForOldSnapshots(TransactionId recentXmin, Assert(OldSnapshotThresholdActive()); Assert(limit_ts != NULL && limit_xid != NULL); - if (!RelationAllowsEarlyPruning(relation)) + /* + * TestForOldSnapshot() assumes early pruning advances the page LSN, so we + * can't prune early when skipping WAL. + */ + if (!RelationAllowsEarlyPruning(relation) || !RelationNeedsWAL(relation)) return false; ts = GetSnapshotCurrentTimestamp(); diff --git a/src/include/utils/snapmgr.h b/src/include/utils/snapmgr.h index 579be352c5f46..c21ee3c289c96 100644 --- a/src/include/utils/snapmgr.h +++ b/src/include/utils/snapmgr.h @@ -37,7 +37,7 @@ */ #define RelationAllowsEarlyPruning(rel) \ ( \ - RelationNeedsWAL(rel) \ + (rel)->rd_rel->relpersistence == RELPERSISTENCE_PERMANENT \ && !IsCatalogRelation(rel) \ && !RelationIsAccessibleInLogicalDecoding(rel) \ ) From 6aaaa76bb47db11cd6f567eafa3d1ee81ca59556 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Sat, 30 Jan 2021 09:41:44 +0100 Subject: [PATCH 215/240] Allow GRANTED BY clause in normal GRANT and REVOKE statements The SQL standard allows a GRANTED BY clause on GRANT and REVOKE (privilege) statements that can specify CURRENT_USER or CURRENT_ROLE. In PostgreSQL, both of these are the default behavior. Since we already have all the parsing support for this for the GRANT (role) statement, we might as well add basic support for this for the privilege variant as well. This allows us to check off SQL feature T332. In the future, perhaps more interesting things could be done with this, too. Reviewed-by: Simon Riggs Discussion: https://www.postgresql.org/message-id/flat/f2feac44-b4c5-f38f-3699-2851d6a76dc9@2ndquadrant.com --- doc/src/sgml/ref/grant.sgml | 25 +++++++++++++++++++++--- doc/src/sgml/ref/revoke.sgml | 13 ++++++++++++ src/backend/catalog/aclchk.c | 16 +++++++++++++++ src/backend/catalog/sql_features.txt | 2 +- src/backend/nodes/copyfuncs.c | 1 + src/backend/nodes/equalfuncs.c | 1 + src/backend/parser/gram.y | 13 +++++++----- src/include/nodes/parsenodes.h | 1 + src/test/regress/expected/privileges.out | 6 ++++-- src/test/regress/sql/privileges.sql | 6 ++++-- 10 files changed, 71 insertions(+), 13 deletions(-) diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml index c3db393bdea70..a897712de2e5c 100644 --- a/doc/src/sgml/ref/grant.sgml +++ b/doc/src/sgml/ref/grant.sgml @@ -26,58 +26,71 @@ GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER } ON { [ TABLE ] table_name [, ...] | ALL TABLES IN SCHEMA schema_name [, ...] } TO role_specification [, ...] [ WITH GRANT OPTION ] + [ GRANTED BY role_specification ] GRANT { { SELECT | INSERT | UPDATE | REFERENCES } ( column_name [, ...] ) [, ...] | ALL [ PRIVILEGES ] ( column_name [, ...] ) } ON [ TABLE ] table_name [, ...] TO role_specification [, ...] [ WITH GRANT OPTION ] + [ GRANTED BY role_specification ] GRANT { { USAGE | SELECT | UPDATE } [, ...] | ALL [ PRIVILEGES ] } ON { SEQUENCE sequence_name [, ...] | ALL SEQUENCES IN SCHEMA schema_name [, ...] } TO role_specification [, ...] [ WITH GRANT OPTION ] + [ GRANTED BY role_specification ] GRANT { { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] | ALL [ PRIVILEGES ] } ON DATABASE database_name [, ...] TO role_specification [, ...] [ WITH GRANT OPTION ] + [ GRANTED BY role_specification ] GRANT { USAGE | ALL [ PRIVILEGES ] } ON DOMAIN domain_name [, ...] TO role_specification [, ...] [ WITH GRANT OPTION ] + [ GRANTED BY role_specification ] GRANT { USAGE | ALL [ PRIVILEGES ] } ON FOREIGN DATA WRAPPER fdw_name [, ...] TO role_specification [, ...] [ WITH GRANT OPTION ] + [ GRANTED BY role_specification ] GRANT { USAGE | ALL [ PRIVILEGES ] } ON FOREIGN SERVER server_name [, ...] TO role_specification [, ...] [ WITH GRANT OPTION ] + [ GRANTED BY role_specification ] GRANT { EXECUTE | ALL [ PRIVILEGES ] } ON { { FUNCTION | PROCEDURE | ROUTINE } routine_name [ ( [ [ argmode ] [ arg_name ] arg_type [, ...] ] ) ] [, ...] | ALL { FUNCTIONS | PROCEDURES | ROUTINES } IN SCHEMA schema_name [, ...] } TO role_specification [, ...] [ WITH GRANT OPTION ] + [ GRANTED BY role_specification ] GRANT { USAGE | ALL [ PRIVILEGES ] } ON LANGUAGE lang_name [, ...] TO role_specification [, ...] [ WITH GRANT OPTION ] + [ GRANTED BY role_specification ] GRANT { { SELECT | UPDATE } [, ...] | ALL [ PRIVILEGES ] } ON LARGE OBJECT loid [, ...] TO role_specification [, ...] [ WITH GRANT OPTION ] + [ GRANTED BY role_specification ] GRANT { { CREATE | USAGE } [, ...] | ALL [ PRIVILEGES ] } ON SCHEMA schema_name [, ...] TO role_specification [, ...] [ WITH GRANT OPTION ] + [ GRANTED BY role_specification ] GRANT { CREATE | ALL [ PRIVILEGES ] } ON TABLESPACE tablespace_name [, ...] TO role_specification [, ...] [ WITH GRANT OPTION ] + [ GRANTED BY role_specification ] GRANT { USAGE | ALL [ PRIVILEGES ] } ON TYPE type_name [, ...] TO role_specification [, ...] [ WITH GRANT OPTION ] + [ GRANTED BY role_specification ] GRANT role_name [, ...] TO role_specification [, ...] [ WITH ADMIN OPTION ] @@ -133,6 +146,12 @@ GRANT role_name [, ...] TO PUBLIC. + + If GRANTED BY is specified, the specified grantor must + be the current user. This clause is currently present in this form only + for SQL compatibility. + + There is no need to grant privileges to the owner of an object (usually the user that created it), @@ -410,9 +429,9 @@ GRANT admins TO joe; The SQL standard allows the GRANTED BY option to - be used in all forms of GRANT. PostgreSQL only - supports it when granting role membership, and even then only superusers - may use it in nontrivial ways. + specify only CURRENT_USER or + CURRENT_ROLE. The other variants are PostgreSQL + extensions. diff --git a/doc/src/sgml/ref/revoke.sgml b/doc/src/sgml/ref/revoke.sgml index 35ff87a4f5e26..3014c864ea3ca 100644 --- a/doc/src/sgml/ref/revoke.sgml +++ b/doc/src/sgml/ref/revoke.sgml @@ -27,6 +27,7 @@ REVOKE [ GRANT OPTION FOR ] ON { [ TABLE ] table_name [, ...] | ALL TABLES IN SCHEMA schema_name [, ...] } FROM role_specification [, ...] + [ GRANTED BY role_specification ] [ CASCADE | RESTRICT ] REVOKE [ GRANT OPTION FOR ] @@ -34,6 +35,7 @@ REVOKE [ GRANT OPTION FOR ] [, ...] | ALL [ PRIVILEGES ] ( column_name [, ...] ) } ON [ TABLE ] table_name [, ...] FROM role_specification [, ...] + [ GRANTED BY role_specification ] [ CASCADE | RESTRICT ] REVOKE [ GRANT OPTION FOR ] @@ -42,30 +44,35 @@ REVOKE [ GRANT OPTION FOR ] ON { SEQUENCE sequence_name [, ...] | ALL SEQUENCES IN SCHEMA schema_name [, ...] } FROM role_specification [, ...] + [ GRANTED BY role_specification ] [ CASCADE | RESTRICT ] REVOKE [ GRANT OPTION FOR ] { { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] | ALL [ PRIVILEGES ] } ON DATABASE database_name [, ...] FROM role_specification [, ...] + [ GRANTED BY role_specification ] [ CASCADE | RESTRICT ] REVOKE [ GRANT OPTION FOR ] { USAGE | ALL [ PRIVILEGES ] } ON DOMAIN domain_name [, ...] FROM role_specification [, ...] + [ GRANTED BY role_specification ] [ CASCADE | RESTRICT ] REVOKE [ GRANT OPTION FOR ] { USAGE | ALL [ PRIVILEGES ] } ON FOREIGN DATA WRAPPER fdw_name [, ...] FROM role_specification [, ...] + [ GRANTED BY role_specification ] [ CASCADE | RESTRICT ] REVOKE [ GRANT OPTION FOR ] { USAGE | ALL [ PRIVILEGES ] } ON FOREIGN SERVER server_name [, ...] FROM role_specification [, ...] + [ GRANTED BY role_specification ] [ CASCADE | RESTRICT ] REVOKE [ GRANT OPTION FOR ] @@ -73,36 +80,42 @@ REVOKE [ GRANT OPTION FOR ] ON { { FUNCTION | PROCEDURE | ROUTINE } function_name [ ( [ [ argmode ] [ arg_name ] arg_type [, ...] ] ) ] [, ...] | ALL { FUNCTIONS | PROCEDURES | ROUTINES } IN SCHEMA schema_name [, ...] } FROM role_specification [, ...] + [ GRANTED BY role_specification ] [ CASCADE | RESTRICT ] REVOKE [ GRANT OPTION FOR ] { USAGE | ALL [ PRIVILEGES ] } ON LANGUAGE lang_name [, ...] FROM role_specification [, ...] + [ GRANTED BY role_specification ] [ CASCADE | RESTRICT ] REVOKE [ GRANT OPTION FOR ] { { SELECT | UPDATE } [, ...] | ALL [ PRIVILEGES ] } ON LARGE OBJECT loid [, ...] FROM role_specification [, ...] + [ GRANTED BY role_specification ] [ CASCADE | RESTRICT ] REVOKE [ GRANT OPTION FOR ] { { CREATE | USAGE } [, ...] | ALL [ PRIVILEGES ] } ON SCHEMA schema_name [, ...] FROM role_specification [, ...] + [ GRANTED BY role_specification ] [ CASCADE | RESTRICT ] REVOKE [ GRANT OPTION FOR ] { CREATE | ALL [ PRIVILEGES ] } ON TABLESPACE tablespace_name [, ...] FROM role_specification [, ...] + [ GRANTED BY role_specification ] [ CASCADE | RESTRICT ] REVOKE [ GRANT OPTION FOR ] { USAGE | ALL [ PRIVILEGES ] } ON TYPE type_name [, ...] FROM role_specification [, ...] + [ GRANTED BY role_specification ] [ CASCADE | RESTRICT ] REVOKE [ ADMIN OPTION FOR ] diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index f3c1ca18ae747..add3d147e766c 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -363,6 +363,22 @@ ExecuteGrantStmt(GrantStmt *stmt) const char *errormsg; AclMode all_privileges; + if (stmt->grantor) + { + Oid grantor; + + grantor = get_rolespec_oid(stmt->grantor, false); + + /* + * Currently, this clause is only for SQL compatibility, not very + * interesting otherwise. + */ + if (grantor != GetUserId()) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("grantor must be current user"))); + } + /* * Turn the regular GrantStmt into the InternalGrant form. */ diff --git a/src/backend/catalog/sql_features.txt b/src/backend/catalog/sql_features.txt index caa971c4356ac..86519ad2974a0 100644 --- a/src/backend/catalog/sql_features.txt +++ b/src/backend/catalog/sql_features.txt @@ -475,7 +475,7 @@ T324 Explicit security for SQL routines NO T325 Qualified SQL parameter references YES T326 Table functions NO T331 Basic roles YES -T332 Extended roles NO mostly supported +T332 Extended roles YES T341 Overloading of SQL-invoked functions and procedures YES T351 Bracketed SQL comments (/*...*/ comments) YES T431 Extended grouping capabilities YES diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index ba3ccc712c888..21e09c667a369 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -3270,6 +3270,7 @@ _copyGrantStmt(const GrantStmt *from) COPY_NODE_FIELD(privileges); COPY_NODE_FIELD(grantees); COPY_SCALAR_FIELD(grant_option); + COPY_NODE_FIELD(grantor); COPY_SCALAR_FIELD(behavior); return newnode; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index a2ef853dc2a02..5a5237c6c3099 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1145,6 +1145,7 @@ _equalGrantStmt(const GrantStmt *a, const GrantStmt *b) COMPARE_NODE_FIELD(privileges); COMPARE_NODE_FIELD(grantees); COMPARE_SCALAR_FIELD(grant_option); + COMPARE_NODE_FIELD(grantor); COMPARE_SCALAR_FIELD(behavior); return true; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 7574d545e0e02..b2f447bf9a277 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -6772,7 +6772,7 @@ opt_from_in: from_in *****************************************************************************/ GrantStmt: GRANT privileges ON privilege_target TO grantee_list - opt_grant_grant_option + opt_grant_grant_option opt_granted_by { GrantStmt *n = makeNode(GrantStmt); n->is_grant = true; @@ -6782,13 +6782,14 @@ GrantStmt: GRANT privileges ON privilege_target TO grantee_list n->objects = ($4)->objs; n->grantees = $6; n->grant_option = $7; + n->grantor = $8; $$ = (Node*)n; } ; RevokeStmt: REVOKE privileges ON privilege_target - FROM grantee_list opt_drop_behavior + FROM grantee_list opt_granted_by opt_drop_behavior { GrantStmt *n = makeNode(GrantStmt); n->is_grant = false; @@ -6798,11 +6799,12 @@ RevokeStmt: n->objtype = ($4)->objtype; n->objects = ($4)->objs; n->grantees = $6; - n->behavior = $7; + n->grantor = $7; + n->behavior = $8; $$ = (Node *)n; } | REVOKE GRANT OPTION FOR privileges ON privilege_target - FROM grantee_list opt_drop_behavior + FROM grantee_list opt_granted_by opt_drop_behavior { GrantStmt *n = makeNode(GrantStmt); n->is_grant = false; @@ -6812,7 +6814,8 @@ RevokeStmt: n->objtype = ($7)->objtype; n->objects = ($7)->objs; n->grantees = $9; - n->behavior = $10; + n->grantor = $10; + n->behavior = $11; $$ = (Node *)n; } ; diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index dc2bb40926a4a..068c6ec440135 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1949,6 +1949,7 @@ typedef struct GrantStmt /* privileges == NIL denotes ALL PRIVILEGES */ List *grantees; /* list of RoleSpec nodes */ bool grant_option; /* grant or revoke grant option */ + RoleSpec *grantor; DropBehavior behavior; /* drop behavior (for REVOKE) */ } GrantStmt; diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out index 8f2fc89851bc1..ed98fa8376ff1 100644 --- a/src/test/regress/expected/privileges.out +++ b/src/test/regress/expected/privileges.out @@ -70,8 +70,10 @@ SELECT * FROM atest1; CREATE TABLE atest2 (col1 varchar(10), col2 boolean); GRANT SELECT ON atest2 TO regress_priv_user2; GRANT UPDATE ON atest2 TO regress_priv_user3; -GRANT INSERT ON atest2 TO regress_priv_user4; -GRANT TRUNCATE ON atest2 TO regress_priv_user5; +GRANT INSERT ON atest2 TO regress_priv_user4 GRANTED BY CURRENT_USER; +GRANT TRUNCATE ON atest2 TO regress_priv_user5 GRANTED BY CURRENT_ROLE; +GRANT TRUNCATE ON atest2 TO regress_priv_user4 GRANTED BY regress_priv_user5; -- error +ERROR: grantor must be current user SET SESSION AUTHORIZATION regress_priv_user2; SELECT session_user, current_user; session_user | current_user diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql index 1c250a11fe1ac..becbc196713a0 100644 --- a/src/test/regress/sql/privileges.sql +++ b/src/test/regress/sql/privileges.sql @@ -64,8 +64,10 @@ SELECT * FROM atest1; CREATE TABLE atest2 (col1 varchar(10), col2 boolean); GRANT SELECT ON atest2 TO regress_priv_user2; GRANT UPDATE ON atest2 TO regress_priv_user3; -GRANT INSERT ON atest2 TO regress_priv_user4; -GRANT TRUNCATE ON atest2 TO regress_priv_user5; +GRANT INSERT ON atest2 TO regress_priv_user4 GRANTED BY CURRENT_USER; +GRANT TRUNCATE ON atest2 TO regress_priv_user5 GRANTED BY CURRENT_ROLE; + +GRANT TRUNCATE ON atest2 TO regress_priv_user4 GRANTED BY regress_priv_user5; -- error SET SESSION AUTHORIZATION regress_priv_user2; From 65330622441d7ee08f768c4326825ae903f2595a Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Sat, 30 Jan 2021 11:05:15 +0100 Subject: [PATCH 216/240] doc: Clarify status of SELECT INTO on reference page The documentation as well as source code comments weren't entirely clear whether SELECT INTO was truly deprecated (thus in theory destined to be removed eventually), or just a less recommended variant. After discussion, it appears that other implementations also use SELECT INTO in direct SQL in a way similar to PostgreSQL, so it seems worth keeping it for compatibility. Update the language in the documentation to that effect. Discussion: https://www.postgresql.org/message-id/flat/96dc0df3-e13a-a85d-d045-d6e2c85218da%40enterprisedb.com --- doc/src/sgml/ref/select_into.sgml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/src/sgml/ref/select_into.sgml b/doc/src/sgml/ref/select_into.sgml index 7b327d9eeef32..acc6401485b77 100644 --- a/doc/src/sgml/ref/select_into.sgml +++ b/doc/src/sgml/ref/select_into.sgml @@ -138,9 +138,11 @@ SELECT * INTO films_recent FROM films WHERE date_prod >= '2002-01-01'; in ECPG (see ) and PL/pgSQL (see ). The PostgreSQL usage of SELECT - INTO to represent table creation is historical. It is - best to use CREATE TABLE AS for this purpose in - new code. + INTO to represent table creation is historical. Some other SQL + implementations also use SELECT INTO in this way (but + most SQL implementations support CREATE TABLE AS + instead). Apart from such compatibility considerations, it is best to use + CREATE TABLE AS for this purpose in new code. From dfb75e478cacb33d277432e0df5e2f9a2a2b52d9 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Sat, 30 Jan 2021 19:14:31 +0100 Subject: [PATCH 217/240] Add primary keys and unique constraints to system catalogs For those system catalogs that have a unique indexes, make a primary key and unique constraint, using ALTER TABLE ... PRIMARY KEY/UNIQUE USING INDEX. This can be helpful for GUI tools that look for a primary key, and it might in the future allow declaring foreign keys, for making schema diagrams. The constraint creation statements are automatically created by genbki.pl from DECLARE_UNIQUE_INDEX directives. To specify which one of the available unique indexes is the primary key, use the new directive DECLARE_UNIQUE_INDEX_PKEY instead. By convention, we usually make a catalog's OID column its primary key, if it has one. Reviewed-by: Tom Lane Discussion: https://www.postgresql.org/message-id/flat/dc5f44d9-5ec1-a596-0251-dadadcdede98@2ndquadrant.com --- src/backend/catalog/.gitignore | 1 + src/backend/catalog/Catalog.pm | 11 ++-- src/backend/catalog/Makefile | 9 +-- src/backend/catalog/genbki.pl | 23 +++++++ src/bin/initdb/initdb.c | 60 +++++-------------- src/include/catalog/genbki.h | 12 ++-- src/include/catalog/pg_aggregate.h | 2 +- src/include/catalog/pg_am.h | 2 +- src/include/catalog/pg_amop.h | 2 +- src/include/catalog/pg_amproc.h | 2 +- src/include/catalog/pg_attrdef.h | 2 +- src/include/catalog/pg_attribute.h | 2 +- src/include/catalog/pg_auth_members.h | 2 +- src/include/catalog/pg_authid.h | 2 +- src/include/catalog/pg_cast.h | 2 +- src/include/catalog/pg_class.h | 2 +- src/include/catalog/pg_collation.h | 2 +- src/include/catalog/pg_constraint.h | 2 +- src/include/catalog/pg_conversion.h | 2 +- src/include/catalog/pg_database.h | 2 +- src/include/catalog/pg_db_role_setting.h | 2 +- src/include/catalog/pg_default_acl.h | 2 +- src/include/catalog/pg_description.h | 2 +- src/include/catalog/pg_enum.h | 2 +- src/include/catalog/pg_event_trigger.h | 2 +- src/include/catalog/pg_extension.h | 2 +- src/include/catalog/pg_foreign_data_wrapper.h | 2 +- src/include/catalog/pg_foreign_server.h | 2 +- src/include/catalog/pg_foreign_table.h | 2 +- src/include/catalog/pg_index.h | 2 +- src/include/catalog/pg_inherits.h | 2 +- src/include/catalog/pg_init_privs.h | 2 +- src/include/catalog/pg_language.h | 2 +- src/include/catalog/pg_largeobject.h | 2 +- src/include/catalog/pg_largeobject_metadata.h | 2 +- src/include/catalog/pg_namespace.h | 2 +- src/include/catalog/pg_opclass.h | 2 +- src/include/catalog/pg_operator.h | 2 +- src/include/catalog/pg_opfamily.h | 2 +- src/include/catalog/pg_partitioned_table.h | 2 +- src/include/catalog/pg_policy.h | 2 +- src/include/catalog/pg_proc.h | 2 +- src/include/catalog/pg_publication.h | 2 +- src/include/catalog/pg_publication_rel.h | 2 +- src/include/catalog/pg_range.h | 2 +- src/include/catalog/pg_replication_origin.h | 2 +- src/include/catalog/pg_rewrite.h | 2 +- src/include/catalog/pg_seclabel.h | 2 +- src/include/catalog/pg_sequence.h | 2 +- src/include/catalog/pg_shdescription.h | 2 +- src/include/catalog/pg_shseclabel.h | 2 +- src/include/catalog/pg_statistic.h | 2 +- src/include/catalog/pg_statistic_ext.h | 2 +- src/include/catalog/pg_statistic_ext_data.h | 2 +- src/include/catalog/pg_subscription.h | 2 +- src/include/catalog/pg_subscription_rel.h | 2 +- src/include/catalog/pg_tablespace.h | 2 +- src/include/catalog/pg_transform.h | 2 +- src/include/catalog/pg_trigger.h | 2 +- src/include/catalog/pg_ts_config.h | 2 +- src/include/catalog/pg_ts_config_map.h | 2 +- src/include/catalog/pg_ts_dict.h | 2 +- src/include/catalog/pg_ts_parser.h | 2 +- src/include/catalog/pg_ts_template.h | 2 +- src/include/catalog/pg_type.h | 2 +- src/include/catalog/pg_user_mapping.h | 2 +- .../expected/alter_system_table.out | 6 +- .../unsafe_tests/sql/alter_system_table.sql | 5 +- src/test/regress/expected/misc_sanity.out | 31 +++++++++- src/test/regress/sql/misc_sanity.sql | 24 ++++++++ src/tools/msvc/clean.bat | 1 + 71 files changed, 177 insertions(+), 126 deletions(-) diff --git a/src/backend/catalog/.gitignore b/src/backend/catalog/.gitignore index 11e2e5202326b..4bd3ee9d7f391 100644 --- a/src/backend/catalog/.gitignore +++ b/src/backend/catalog/.gitignore @@ -1,4 +1,5 @@ /postgres.bki /schemapg.h +/system_constraints.sql /pg_*_d.h /bki-stamp diff --git a/src/backend/catalog/Catalog.pm b/src/backend/catalog/Catalog.pm index a37c3271229ce..061f3d8c21ebd 100644 --- a/src/backend/catalog/Catalog.pm +++ b/src/backend/catalog/Catalog.pm @@ -94,14 +94,15 @@ sub ParseHeader push @{ $catalog{toasting} }, { parent_table => $1, toast_oid => $2, toast_index_oid => $3 }; } - elsif (/^DECLARE_(UNIQUE_)?INDEX\(\s*(\w+),\s*(\d+),\s*(.+)\)/) + elsif (/^DECLARE_(UNIQUE_)?INDEX(_PKEY)?\(\s*(\w+),\s*(\d+),\s*(.+)\)/) { push @{ $catalog{indexing} }, - { + { is_unique => $1 ? 1 : 0, - index_name => $2, - index_oid => $3, - index_decl => $4 + is_pkey => $2 ? 1 : 0, + index_name => $3, + index_oid => $4, + index_decl => $5 }; } elsif (/^CATALOG\((\w+),(\d+),(\w+)\)/) diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index c85f0ca7b66de..995ddf128523f 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -121,6 +121,7 @@ $(top_builddir)/src/include/catalog/header-stamp: bki-stamp .PHONY: install-data install-data: bki-stamp installdirs $(INSTALL_DATA) $(call vpathsearch,postgres.bki) '$(DESTDIR)$(datadir)/postgres.bki' + $(INSTALL_DATA) $(call vpathsearch,system_constraints.sql) '$(DESTDIR)$(datadir)/system_constraints.sql' $(INSTALL_DATA) $(srcdir)/system_views.sql '$(DESTDIR)$(datadir)/system_views.sql' $(INSTALL_DATA) $(srcdir)/information_schema.sql '$(DESTDIR)$(datadir)/information_schema.sql' $(INSTALL_DATA) $(srcdir)/sql_features.txt '$(DESTDIR)$(datadir)/sql_features.txt' @@ -130,11 +131,11 @@ installdirs: .PHONY: uninstall-data uninstall-data: - rm -f $(addprefix '$(DESTDIR)$(datadir)'/, postgres.bki system_views.sql information_schema.sql sql_features.txt) + rm -f $(addprefix '$(DESTDIR)$(datadir)'/, postgres.bki system_constraints.sql system_views.sql information_schema.sql sql_features.txt) -# postgres.bki and the generated headers are in the distribution tarball, -# so they are not cleaned here. +# postgres.bki, system_constraints.sql, and the generated headers are +# in the distribution tarball, so they are not cleaned here. clean: maintainer-clean: clean - rm -f bki-stamp postgres.bki $(GENERATED_HEADERS) + rm -f bki-stamp postgres.bki system_constraints.sql $(GENERATED_HEADERS) diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl index 009e215da1c0b..b68c1752c0098 100644 --- a/src/backend/catalog/genbki.pl +++ b/src/backend/catalog/genbki.pl @@ -55,6 +55,7 @@ my @toast_decls; my @index_decls; my %oidcounts; +my @system_constraints; foreach my $header (@ARGV) { @@ -137,6 +138,17 @@ $index->{index_name}, $index->{index_oid}, $index->{index_decl}; $oidcounts{ $index->{index_oid} }++; + + if ($index->{is_unique}) + { + $index->{index_decl} =~ /on (\w+) using/; + my $tblname = $1; + push @system_constraints, + sprintf "ALTER TABLE %s ADD %s USING INDEX %s;", + $tblname, + $index->{is_pkey} ? "PRIMARY KEY" : "UNIQUE", + $index->{index_name}; + } } } @@ -388,6 +400,9 @@ my $schemafile = $output_path . 'schemapg.h'; open my $schemapg, '>', $schemafile . $tmpext or die "can't open $schemafile$tmpext: $!"; +my $constraints_file = $output_path . 'system_constraints.sql'; +open my $constraints, '>', $constraints_file . $tmpext + or die "can't open $constraints_file$tmpext: $!"; # Generate postgres.bki and pg_*_d.h headers. @@ -648,6 +663,12 @@ "genbki OID counter reached $GenbkiNextOid, overrunning FirstBootstrapObjectId\n" if $GenbkiNextOid > $FirstBootstrapObjectId; +# Now generate system_constraints.sql + +foreach my $c (@system_constraints) +{ + print $constraints $c, "\n"; +} # Now generate schemapg.h @@ -688,10 +709,12 @@ # We're done emitting data close $bki; close $schemapg; +close $constraints; # Finally, rename the completed files into place. Catalog::RenameTempFile($bkifile, $tmpext); Catalog::RenameTempFile($schemafile, $tmpext); +Catalog::RenameTempFile($constraints_file, $tmpext); exit 0; diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index e242a4a5b586a..62540a1b37d5e 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -159,6 +159,7 @@ static char *conf_file; static char *dictionary_file; static char *info_schema_file; static char *features_file; +static char *system_constraints_file; static char *system_views_file; static bool success = false; static bool made_new_pgdata = false; @@ -251,10 +252,9 @@ static void bootstrap_template1(void); static void setup_auth(FILE *cmdfd); static void get_su_pwd(void); static void setup_depend(FILE *cmdfd); -static void setup_sysviews(FILE *cmdfd); +static void setup_run_file(FILE *cmdfd, const char *filename); static void setup_description(FILE *cmdfd); static void setup_collation(FILE *cmdfd); -static void setup_dictionary(FILE *cmdfd); static void setup_privileges(FILE *cmdfd); static void set_info_version(void); static void setup_schema(FILE *cmdfd); @@ -1600,17 +1600,16 @@ setup_depend(FILE *cmdfd) } /* - * set up system views + * Run external file */ static void -setup_sysviews(FILE *cmdfd) +setup_run_file(FILE *cmdfd, const char *filename) { - char **line; - char **sysviews_setup; + char **lines; - sysviews_setup = readfile(system_views_file); + lines = readfile(filename); - for (line = sysviews_setup; *line != NULL; line++) + for (char **line = lines; *line != NULL; line++) { PG_CMD_PUTS(*line); free(*line); @@ -1618,7 +1617,7 @@ setup_sysviews(FILE *cmdfd) PG_CMD_PUTS("\n\n"); - free(sysviews_setup); + free(lines); } /* @@ -1661,27 +1660,6 @@ setup_collation(FILE *cmdfd) PG_CMD_PUTS("SELECT pg_import_system_collations('pg_catalog');\n\n"); } -/* - * load extra dictionaries (Snowball stemmers) - */ -static void -setup_dictionary(FILE *cmdfd) -{ - char **line; - char **conv_lines; - - conv_lines = readfile(dictionary_file); - for (line = conv_lines; *line != NULL; line++) - { - PG_CMD_PUTS(*line); - free(*line); - } - - PG_CMD_PUTS("\n\n"); - - free(conv_lines); -} - /* * Set up privileges * @@ -1882,20 +1860,7 @@ set_info_version(void) static void setup_schema(FILE *cmdfd) { - char **line; - char **lines; - - lines = readfile(info_schema_file); - - for (line = lines; *line != NULL; line++) - { - PG_CMD_PUTS(*line); - free(*line); - } - - PG_CMD_PUTS("\n\n"); - - free(lines); + setup_run_file(cmdfd, info_schema_file); PG_CMD_PRINTF("UPDATE information_schema.sql_implementation_info " " SET character_value = '%s' " @@ -2534,6 +2499,7 @@ setup_data_file_paths(void) set_input(&dictionary_file, "snowball_create.sql"); set_input(&info_schema_file, "information_schema.sql"); set_input(&features_file, "sql_features.txt"); + set_input(&system_constraints_file, "system_constraints.sql"); set_input(&system_views_file, "system_views.sql"); if (show_setting || debug) @@ -2895,6 +2861,8 @@ initialize_data_directory(void) setup_auth(cmdfd); + setup_run_file(cmdfd, system_constraints_file); + setup_depend(cmdfd); /* @@ -2902,13 +2870,13 @@ initialize_data_directory(void) * They are all droppable at the whim of the DBA. */ - setup_sysviews(cmdfd); + setup_run_file(cmdfd, system_views_file); setup_description(cmdfd); setup_collation(cmdfd); - setup_dictionary(cmdfd); + setup_run_file(cmdfd, dictionary_file); setup_privileges(cmdfd); diff --git a/src/include/catalog/genbki.h b/src/include/catalog/genbki.h index e26bde6d09b2c..5d05fafb5dae9 100644 --- a/src/include/catalog/genbki.h +++ b/src/include/catalog/genbki.h @@ -55,12 +55,15 @@ #define DECLARE_TOAST(name,toastoid,indexoid) extern int no_such_variable /* - * These lines processed by genbki.pl to create the statements + * These lines are processed by genbki.pl to create the statements * the bootstrap parser will turn into DefineIndex calls. * - * The keyword is DECLARE_INDEX or DECLARE_UNIQUE_INDEX. The first two - * arguments are the index name and OID, the rest is much like a standard - * 'create index' SQL command. + * The keyword is DECLARE_INDEX or DECLARE_UNIQUE_INDEX or + * DECLARE_UNIQUE_INDEX_PKEY. ("PKEY" marks the index as being the catalog's + * primary key; currently this is only cosmetically different from a regular + * unique index. By convention, we usually make a catalog's OID column its + * pkey, if it has one.) The first two arguments are the index's name and + * OID, the rest is much like a standard 'create index' SQL command. * * For each index, we also provide a #define for its OID. References to * the index in the C code should always use these #defines, not the actual @@ -70,6 +73,7 @@ */ #define DECLARE_INDEX(name,oid,decl) extern int no_such_variable #define DECLARE_UNIQUE_INDEX(name,oid,decl) extern int no_such_variable +#define DECLARE_UNIQUE_INDEX_PKEY(name,oid,decl) extern int no_such_variable /* The following are never defined; they are here only for documentation. */ diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h index e90c3f847e1ff..8b03cdeea2429 100644 --- a/src/include/catalog/pg_aggregate.h +++ b/src/include/catalog/pg_aggregate.h @@ -110,7 +110,7 @@ typedef FormData_pg_aggregate *Form_pg_aggregate; DECLARE_TOAST(pg_aggregate, 4159, 4160); -DECLARE_UNIQUE_INDEX(pg_aggregate_fnoid_index, 2650, on pg_aggregate using btree(aggfnoid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_aggregate_fnoid_index, 2650, on pg_aggregate using btree(aggfnoid oid_ops)); #define AggregateFnoidIndexId 2650 #ifdef EXPOSE_TO_CLIENT_CODE diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h index 358f5aac8fc42..ced86faef8494 100644 --- a/src/include/catalog/pg_am.h +++ b/src/include/catalog/pg_am.h @@ -49,7 +49,7 @@ typedef FormData_pg_am *Form_pg_am; DECLARE_UNIQUE_INDEX(pg_am_name_index, 2651, on pg_am using btree(amname name_ops)); #define AmNameIndexId 2651 -DECLARE_UNIQUE_INDEX(pg_am_oid_index, 2652, on pg_am using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_am_oid_index, 2652, on pg_am using btree(oid oid_ops)); #define AmOidIndexId 2652 #ifdef EXPOSE_TO_CLIENT_CODE diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h index 3ccd75f67b587..554fc41497d62 100644 --- a/src/include/catalog/pg_amop.h +++ b/src/include/catalog/pg_amop.h @@ -91,7 +91,7 @@ DECLARE_UNIQUE_INDEX(pg_amop_fam_strat_index, 2653, on pg_amop using btree(amopf #define AccessMethodStrategyIndexId 2653 DECLARE_UNIQUE_INDEX(pg_amop_opr_fam_index, 2654, on pg_amop using btree(amopopr oid_ops, amoppurpose char_ops, amopfamily oid_ops)); #define AccessMethodOperatorIndexId 2654 -DECLARE_UNIQUE_INDEX(pg_amop_oid_index, 2756, on pg_amop using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_amop_oid_index, 2756, on pg_amop using btree(oid oid_ops)); #define AccessMethodOperatorOidIndexId 2756 #ifdef EXPOSE_TO_CLIENT_CODE diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h index 86f1f25d17f90..8a727c359a4e7 100644 --- a/src/include/catalog/pg_amproc.h +++ b/src/include/catalog/pg_amproc.h @@ -69,7 +69,7 @@ typedef FormData_pg_amproc *Form_pg_amproc; DECLARE_UNIQUE_INDEX(pg_amproc_fam_proc_index, 2655, on pg_amproc using btree(amprocfamily oid_ops, amproclefttype oid_ops, amprocrighttype oid_ops, amprocnum int2_ops)); #define AccessMethodProcedureIndexId 2655 -DECLARE_UNIQUE_INDEX(pg_amproc_oid_index, 2757, on pg_amproc using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_amproc_oid_index, 2757, on pg_amproc using btree(oid oid_ops)); #define AccessMethodProcedureOidIndexId 2757 #endif /* PG_AMPROC_H */ diff --git a/src/include/catalog/pg_attrdef.h b/src/include/catalog/pg_attrdef.h index fe3aa289927f8..03efaaded9cc1 100644 --- a/src/include/catalog/pg_attrdef.h +++ b/src/include/catalog/pg_attrdef.h @@ -50,7 +50,7 @@ DECLARE_TOAST(pg_attrdef, 2830, 2831); DECLARE_UNIQUE_INDEX(pg_attrdef_adrelid_adnum_index, 2656, on pg_attrdef using btree(adrelid oid_ops, adnum int2_ops)); #define AttrDefaultIndexId 2656 -DECLARE_UNIQUE_INDEX(pg_attrdef_oid_index, 2657, on pg_attrdef using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_attrdef_oid_index, 2657, on pg_attrdef using btree(oid oid_ops)); #define AttrDefaultOidIndexId 2657 #endif /* PG_ATTRDEF_H */ diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h index 059dec3647dad..ba0efff08c02b 100644 --- a/src/include/catalog/pg_attribute.h +++ b/src/include/catalog/pg_attribute.h @@ -194,7 +194,7 @@ typedef FormData_pg_attribute *Form_pg_attribute; DECLARE_UNIQUE_INDEX(pg_attribute_relid_attnam_index, 2658, on pg_attribute using btree(attrelid oid_ops, attname name_ops)); #define AttributeRelidNameIndexId 2658 -DECLARE_UNIQUE_INDEX(pg_attribute_relid_attnum_index, 2659, on pg_attribute using btree(attrelid oid_ops, attnum int2_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_attribute_relid_attnum_index, 2659, on pg_attribute using btree(attrelid oid_ops, attnum int2_ops)); #define AttributeRelidNumIndexId 2659 #ifdef EXPOSE_TO_CLIENT_CODE diff --git a/src/include/catalog/pg_auth_members.h b/src/include/catalog/pg_auth_members.h index fc5a2dced7b5d..e90c39564088f 100644 --- a/src/include/catalog/pg_auth_members.h +++ b/src/include/catalog/pg_auth_members.h @@ -42,7 +42,7 @@ CATALOG(pg_auth_members,1261,AuthMemRelationId) BKI_SHARED_RELATION BKI_ROWTYPE_ */ typedef FormData_pg_auth_members *Form_pg_auth_members; -DECLARE_UNIQUE_INDEX(pg_auth_members_role_member_index, 2694, on pg_auth_members using btree(roleid oid_ops, member oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_auth_members_role_member_index, 2694, on pg_auth_members using btree(roleid oid_ops, member oid_ops)); #define AuthMemRoleMemIndexId 2694 DECLARE_UNIQUE_INDEX(pg_auth_members_member_role_index, 2695, on pg_auth_members using btree(member oid_ops, roleid oid_ops)); #define AuthMemMemRoleIndexId 2695 diff --git a/src/include/catalog/pg_authid.h b/src/include/catalog/pg_authid.h index 4063072cc915c..1a5c7a73c7c67 100644 --- a/src/include/catalog/pg_authid.h +++ b/src/include/catalog/pg_authid.h @@ -61,7 +61,7 @@ DECLARE_TOAST(pg_authid, 4175, 4176); DECLARE_UNIQUE_INDEX(pg_authid_rolname_index, 2676, on pg_authid using btree(rolname name_ops)); #define AuthIdRolnameIndexId 2676 -DECLARE_UNIQUE_INDEX(pg_authid_oid_index, 2677, on pg_authid using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_authid_oid_index, 2677, on pg_authid using btree(oid oid_ops)); #define AuthIdOidIndexId 2677 #endif /* PG_AUTHID_H */ diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h index 03ad900a49900..2d36628c2011d 100644 --- a/src/include/catalog/pg_cast.h +++ b/src/include/catalog/pg_cast.h @@ -56,7 +56,7 @@ CATALOG(pg_cast,2605,CastRelationId) */ typedef FormData_pg_cast *Form_pg_cast; -DECLARE_UNIQUE_INDEX(pg_cast_oid_index, 2660, on pg_cast using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_cast_oid_index, 2660, on pg_cast using btree(oid oid_ops)); #define CastOidIndexId 2660 DECLARE_UNIQUE_INDEX(pg_cast_source_target_index, 2661, on pg_cast using btree(castsource oid_ops, casttarget oid_ops)); #define CastSourceTargetIndexId 2661 diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h index e8dcd15a55fbd..eca306ca98f5d 100644 --- a/src/include/catalog/pg_class.h +++ b/src/include/catalog/pg_class.h @@ -152,7 +152,7 @@ CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,Relat */ typedef FormData_pg_class *Form_pg_class; -DECLARE_UNIQUE_INDEX(pg_class_oid_index, 2662, on pg_class using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_class_oid_index, 2662, on pg_class using btree(oid oid_ops)); #define ClassOidIndexId 2662 DECLARE_UNIQUE_INDEX(pg_class_relname_nsp_index, 2663, on pg_class using btree(relname name_ops, relnamespace oid_ops)); #define ClassNameNspIndexId 2663 diff --git a/src/include/catalog/pg_collation.h b/src/include/catalog/pg_collation.h index 251c2b9adae86..3c496ea914184 100644 --- a/src/include/catalog/pg_collation.h +++ b/src/include/catalog/pg_collation.h @@ -48,7 +48,7 @@ typedef FormData_pg_collation *Form_pg_collation; DECLARE_UNIQUE_INDEX(pg_collation_name_enc_nsp_index, 3164, on pg_collation using btree(collname name_ops, collencoding int4_ops, collnamespace oid_ops)); #define CollationNameEncNspIndexId 3164 -DECLARE_UNIQUE_INDEX(pg_collation_oid_index, 3085, on pg_collation using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_collation_oid_index, 3085, on pg_collation using btree(oid oid_ops)); #define CollationOidIndexId 3085 #ifdef EXPOSE_TO_CLIENT_CODE diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h index f3c3df390fee9..6449937b352db 100644 --- a/src/include/catalog/pg_constraint.h +++ b/src/include/catalog/pg_constraint.h @@ -161,7 +161,7 @@ DECLARE_UNIQUE_INDEX(pg_constraint_conrelid_contypid_conname_index, 2665, on pg_ #define ConstraintRelidTypidNameIndexId 2665 DECLARE_INDEX(pg_constraint_contypid_index, 2666, on pg_constraint using btree(contypid oid_ops)); #define ConstraintTypidIndexId 2666 -DECLARE_UNIQUE_INDEX(pg_constraint_oid_index, 2667, on pg_constraint using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_constraint_oid_index, 2667, on pg_constraint using btree(oid oid_ops)); #define ConstraintOidIndexId 2667 DECLARE_INDEX(pg_constraint_conparentid_index, 2579, on pg_constraint using btree(conparentid oid_ops)); #define ConstraintParentIndexId 2579 diff --git a/src/include/catalog/pg_conversion.h b/src/include/catalog/pg_conversion.h index 93dcc35840ce6..b02dfe0c3f776 100644 --- a/src/include/catalog/pg_conversion.h +++ b/src/include/catalog/pg_conversion.h @@ -64,7 +64,7 @@ DECLARE_UNIQUE_INDEX(pg_conversion_default_index, 2668, on pg_conversion using b #define ConversionDefaultIndexId 2668 DECLARE_UNIQUE_INDEX(pg_conversion_name_nsp_index, 2669, on pg_conversion using btree(conname name_ops, connamespace oid_ops)); #define ConversionNameNspIndexId 2669 -DECLARE_UNIQUE_INDEX(pg_conversion_oid_index, 2670, on pg_conversion using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_conversion_oid_index, 2670, on pg_conversion using btree(oid oid_ops)); #define ConversionOidIndexId 2670 diff --git a/src/include/catalog/pg_database.h b/src/include/catalog/pg_database.h index 97691127bf539..b7a0b6a381b4c 100644 --- a/src/include/catalog/pg_database.h +++ b/src/include/catalog/pg_database.h @@ -86,7 +86,7 @@ DECLARE_TOAST(pg_database, 4177, 4178); DECLARE_UNIQUE_INDEX(pg_database_datname_index, 2671, on pg_database using btree(datname name_ops)); #define DatabaseNameIndexId 2671 -DECLARE_UNIQUE_INDEX(pg_database_oid_index, 2672, on pg_database using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_database_oid_index, 2672, on pg_database using btree(oid oid_ops)); #define DatabaseOidIndexId 2672 #endif /* PG_DATABASE_H */ diff --git a/src/include/catalog/pg_db_role_setting.h b/src/include/catalog/pg_db_role_setting.h index d3c006d7544d8..f18819d670c45 100644 --- a/src/include/catalog/pg_db_role_setting.h +++ b/src/include/catalog/pg_db_role_setting.h @@ -47,7 +47,7 @@ DECLARE_TOAST(pg_db_role_setting, 2966, 2967); #define PgDbRoleSettingToastTable 2966 #define PgDbRoleSettingToastIndex 2967 -DECLARE_UNIQUE_INDEX(pg_db_role_setting_databaseid_rol_index, 2965, on pg_db_role_setting using btree(setdatabase oid_ops, setrole oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_db_role_setting_databaseid_rol_index, 2965, on pg_db_role_setting using btree(setdatabase oid_ops, setrole oid_ops)); #define DbRoleSettingDatidRolidIndexId 2965 /* diff --git a/src/include/catalog/pg_default_acl.h b/src/include/catalog/pg_default_acl.h index 0f3974c32cbe3..bb7db32cd6c39 100644 --- a/src/include/catalog/pg_default_acl.h +++ b/src/include/catalog/pg_default_acl.h @@ -51,7 +51,7 @@ DECLARE_TOAST(pg_default_acl, 4143, 4144); DECLARE_UNIQUE_INDEX(pg_default_acl_role_nsp_obj_index, 827, on pg_default_acl using btree(defaclrole oid_ops, defaclnamespace oid_ops, defaclobjtype char_ops)); #define DefaultAclRoleNspObjIndexId 827 -DECLARE_UNIQUE_INDEX(pg_default_acl_oid_index, 828, on pg_default_acl using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_default_acl_oid_index, 828, on pg_default_acl using btree(oid oid_ops)); #define DefaultAclOidIndexId 828 #ifdef EXPOSE_TO_CLIENT_CODE diff --git a/src/include/catalog/pg_description.h b/src/include/catalog/pg_description.h index 0002643a76c21..ad9de5e0a0623 100644 --- a/src/include/catalog/pg_description.h +++ b/src/include/catalog/pg_description.h @@ -65,7 +65,7 @@ typedef FormData_pg_description * Form_pg_description; DECLARE_TOAST(pg_description, 2834, 2835); -DECLARE_UNIQUE_INDEX(pg_description_o_c_o_index, 2675, on pg_description using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_description_o_c_o_index, 2675, on pg_description using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops)); #define DescriptionObjIndexId 2675 #endif /* PG_DESCRIPTION_H */ diff --git a/src/include/catalog/pg_enum.h b/src/include/catalog/pg_enum.h index 3ae7a03d4e1d7..5eaf70772c714 100644 --- a/src/include/catalog/pg_enum.h +++ b/src/include/catalog/pg_enum.h @@ -43,7 +43,7 @@ CATALOG(pg_enum,3501,EnumRelationId) */ typedef FormData_pg_enum *Form_pg_enum; -DECLARE_UNIQUE_INDEX(pg_enum_oid_index, 3502, on pg_enum using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_enum_oid_index, 3502, on pg_enum using btree(oid oid_ops)); #define EnumOidIndexId 3502 DECLARE_UNIQUE_INDEX(pg_enum_typid_label_index, 3503, on pg_enum using btree(enumtypid oid_ops, enumlabel name_ops)); #define EnumTypIdLabelIndexId 3503 diff --git a/src/include/catalog/pg_event_trigger.h b/src/include/catalog/pg_event_trigger.h index 4011654969c0b..6f0266ed0fae2 100644 --- a/src/include/catalog/pg_event_trigger.h +++ b/src/include/catalog/pg_event_trigger.h @@ -52,7 +52,7 @@ DECLARE_TOAST(pg_event_trigger, 4145, 4146); DECLARE_UNIQUE_INDEX(pg_event_trigger_evtname_index, 3467, on pg_event_trigger using btree(evtname name_ops)); #define EventTriggerNameIndexId 3467 -DECLARE_UNIQUE_INDEX(pg_event_trigger_oid_index, 3468, on pg_event_trigger using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_event_trigger_oid_index, 3468, on pg_event_trigger using btree(oid oid_ops)); #define EventTriggerOidIndexId 3468 #endif /* PG_EVENT_TRIGGER_H */ diff --git a/src/include/catalog/pg_extension.h b/src/include/catalog/pg_extension.h index f7d640fac6fbb..af119bfea7a8c 100644 --- a/src/include/catalog/pg_extension.h +++ b/src/include/catalog/pg_extension.h @@ -51,7 +51,7 @@ typedef FormData_pg_extension *Form_pg_extension; DECLARE_TOAST(pg_extension, 4147, 4148); -DECLARE_UNIQUE_INDEX(pg_extension_oid_index, 3080, on pg_extension using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_extension_oid_index, 3080, on pg_extension using btree(oid oid_ops)); #define ExtensionOidIndexId 3080 DECLARE_UNIQUE_INDEX(pg_extension_name_index, 3081, on pg_extension using btree(extname name_ops)); #define ExtensionNameIndexId 3081 diff --git a/src/include/catalog/pg_foreign_data_wrapper.h b/src/include/catalog/pg_foreign_data_wrapper.h index ca73dc280cabd..0f523a26b9c4f 100644 --- a/src/include/catalog/pg_foreign_data_wrapper.h +++ b/src/include/catalog/pg_foreign_data_wrapper.h @@ -49,7 +49,7 @@ typedef FormData_pg_foreign_data_wrapper *Form_pg_foreign_data_wrapper; DECLARE_TOAST(pg_foreign_data_wrapper, 4149, 4150); -DECLARE_UNIQUE_INDEX(pg_foreign_data_wrapper_oid_index, 112, on pg_foreign_data_wrapper using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_foreign_data_wrapper_oid_index, 112, on pg_foreign_data_wrapper using btree(oid oid_ops)); #define ForeignDataWrapperOidIndexId 112 DECLARE_UNIQUE_INDEX(pg_foreign_data_wrapper_name_index, 548, on pg_foreign_data_wrapper using btree(fdwname name_ops)); #define ForeignDataWrapperNameIndexId 548 diff --git a/src/include/catalog/pg_foreign_server.h b/src/include/catalog/pg_foreign_server.h index 3a68f444e706b..385b896e970d5 100644 --- a/src/include/catalog/pg_foreign_server.h +++ b/src/include/catalog/pg_foreign_server.h @@ -49,7 +49,7 @@ typedef FormData_pg_foreign_server *Form_pg_foreign_server; DECLARE_TOAST(pg_foreign_server, 4151, 4152); -DECLARE_UNIQUE_INDEX(pg_foreign_server_oid_index, 113, on pg_foreign_server using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_foreign_server_oid_index, 113, on pg_foreign_server using btree(oid oid_ops)); #define ForeignServerOidIndexId 113 DECLARE_UNIQUE_INDEX(pg_foreign_server_name_index, 549, on pg_foreign_server using btree(srvname name_ops)); #define ForeignServerNameIndexId 549 diff --git a/src/include/catalog/pg_foreign_table.h b/src/include/catalog/pg_foreign_table.h index c761852bb938a..24f7f2998eb80 100644 --- a/src/include/catalog/pg_foreign_table.h +++ b/src/include/catalog/pg_foreign_table.h @@ -44,7 +44,7 @@ typedef FormData_pg_foreign_table *Form_pg_foreign_table; DECLARE_TOAST(pg_foreign_table, 4153, 4154); -DECLARE_UNIQUE_INDEX(pg_foreign_table_relid_index, 3119, on pg_foreign_table using btree(ftrelid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_foreign_table_relid_index, 3119, on pg_foreign_table using btree(ftrelid oid_ops)); #define ForeignTableRelidIndexId 3119 #endif /* PG_FOREIGN_TABLE_H */ diff --git a/src/include/catalog/pg_index.h b/src/include/catalog/pg_index.h index b6d7ebec55960..1a7aef18ce85f 100644 --- a/src/include/catalog/pg_index.h +++ b/src/include/catalog/pg_index.h @@ -69,7 +69,7 @@ typedef FormData_pg_index *Form_pg_index; DECLARE_INDEX(pg_index_indrelid_index, 2678, on pg_index using btree(indrelid oid_ops)); #define IndexIndrelidIndexId 2678 -DECLARE_UNIQUE_INDEX(pg_index_indexrelid_index, 2679, on pg_index using btree(indexrelid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_index_indexrelid_index, 2679, on pg_index using btree(indexrelid oid_ops)); #define IndexRelidIndexId 2679 #ifdef EXPOSE_TO_CLIENT_CODE diff --git a/src/include/catalog/pg_inherits.h b/src/include/catalog/pg_inherits.h index a0f2ec4e0bd30..b8147796d855f 100644 --- a/src/include/catalog/pg_inherits.h +++ b/src/include/catalog/pg_inherits.h @@ -43,7 +43,7 @@ CATALOG(pg_inherits,2611,InheritsRelationId) */ typedef FormData_pg_inherits *Form_pg_inherits; -DECLARE_UNIQUE_INDEX(pg_inherits_relid_seqno_index, 2680, on pg_inherits using btree(inhrelid oid_ops, inhseqno int4_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_inherits_relid_seqno_index, 2680, on pg_inherits using btree(inhrelid oid_ops, inhseqno int4_ops)); #define InheritsRelidSeqnoIndexId 2680 DECLARE_INDEX(pg_inherits_parent_index, 2187, on pg_inherits using btree(inhparent oid_ops)); #define InheritsParentIndexId 2187 diff --git a/src/include/catalog/pg_init_privs.h b/src/include/catalog/pg_init_privs.h index da1fa5b279afe..983b1857c0c7d 100644 --- a/src/include/catalog/pg_init_privs.h +++ b/src/include/catalog/pg_init_privs.h @@ -64,7 +64,7 @@ typedef FormData_pg_init_privs * Form_pg_init_privs; DECLARE_TOAST(pg_init_privs, 4155, 4156); -DECLARE_UNIQUE_INDEX(pg_init_privs_o_c_o_index, 3395, on pg_init_privs using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_init_privs_o_c_o_index, 3395, on pg_init_privs using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops)); #define InitPrivsObjIndexId 3395 /* diff --git a/src/include/catalog/pg_language.h b/src/include/catalog/pg_language.h index ffab93eb6a33f..b1dcd0a4f579d 100644 --- a/src/include/catalog/pg_language.h +++ b/src/include/catalog/pg_language.h @@ -68,7 +68,7 @@ DECLARE_TOAST(pg_language, 4157, 4158); DECLARE_UNIQUE_INDEX(pg_language_name_index, 2681, on pg_language using btree(lanname name_ops)); #define LanguageNameIndexId 2681 -DECLARE_UNIQUE_INDEX(pg_language_oid_index, 2682, on pg_language using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_language_oid_index, 2682, on pg_language using btree(oid oid_ops)); #define LanguageOidIndexId 2682 #endif /* PG_LANGUAGE_H */ diff --git a/src/include/catalog/pg_largeobject.h b/src/include/catalog/pg_largeobject.h index 80b1cbae83106..f453319322aa7 100644 --- a/src/include/catalog/pg_largeobject.h +++ b/src/include/catalog/pg_largeobject.h @@ -43,7 +43,7 @@ CATALOG(pg_largeobject,2613,LargeObjectRelationId) */ typedef FormData_pg_largeobject *Form_pg_largeobject; -DECLARE_UNIQUE_INDEX(pg_largeobject_loid_pn_index, 2683, on pg_largeobject using btree(loid oid_ops, pageno int4_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_largeobject_loid_pn_index, 2683, on pg_largeobject using btree(loid oid_ops, pageno int4_ops)); #define LargeObjectLOidPNIndexId 2683 extern Oid LargeObjectCreate(Oid loid); diff --git a/src/include/catalog/pg_largeobject_metadata.h b/src/include/catalog/pg_largeobject_metadata.h index b1504a22fa34b..220988b0ad600 100644 --- a/src/include/catalog/pg_largeobject_metadata.h +++ b/src/include/catalog/pg_largeobject_metadata.h @@ -45,7 +45,7 @@ CATALOG(pg_largeobject_metadata,2995,LargeObjectMetadataRelationId) */ typedef FormData_pg_largeobject_metadata *Form_pg_largeobject_metadata; -DECLARE_UNIQUE_INDEX(pg_largeobject_metadata_oid_index, 2996, on pg_largeobject_metadata using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_largeobject_metadata_oid_index, 2996, on pg_largeobject_metadata using btree(oid oid_ops)); #define LargeObjectMetadataOidIndexId 2996 #endif /* PG_LARGEOBJECT_METADATA_H */ diff --git a/src/include/catalog/pg_namespace.h b/src/include/catalog/pg_namespace.h index 5710c37d78c81..0a68958b1c4c9 100644 --- a/src/include/catalog/pg_namespace.h +++ b/src/include/catalog/pg_namespace.h @@ -55,7 +55,7 @@ DECLARE_TOAST(pg_namespace, 4163, 4164); DECLARE_UNIQUE_INDEX(pg_namespace_nspname_index, 2684, on pg_namespace using btree(nspname name_ops)); #define NamespaceNameIndexId 2684 -DECLARE_UNIQUE_INDEX(pg_namespace_oid_index, 2685, on pg_namespace using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_namespace_oid_index, 2685, on pg_namespace using btree(oid oid_ops)); #define NamespaceOidIndexId 2685 /* diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h index 7836d56c3f35a..d132df1f2f7ee 100644 --- a/src/include/catalog/pg_opclass.h +++ b/src/include/catalog/pg_opclass.h @@ -84,7 +84,7 @@ typedef FormData_pg_opclass *Form_pg_opclass; DECLARE_UNIQUE_INDEX(pg_opclass_am_name_nsp_index, 2686, on pg_opclass using btree(opcmethod oid_ops, opcname name_ops, opcnamespace oid_ops)); #define OpclassAmNameNspIndexId 2686 -DECLARE_UNIQUE_INDEX(pg_opclass_oid_index, 2687, on pg_opclass using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_opclass_oid_index, 2687, on pg_opclass using btree(oid oid_ops)); #define OpclassOidIndexId 2687 #endif /* PG_OPCLASS_H */ diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h index 05a3fe1815756..3ca57e7c1b4b1 100644 --- a/src/include/catalog/pg_operator.h +++ b/src/include/catalog/pg_operator.h @@ -82,7 +82,7 @@ CATALOG(pg_operator,2617,OperatorRelationId) */ typedef FormData_pg_operator *Form_pg_operator; -DECLARE_UNIQUE_INDEX(pg_operator_oid_index, 2688, on pg_operator using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_operator_oid_index, 2688, on pg_operator using btree(oid oid_ops)); #define OperatorOidIndexId 2688 DECLARE_UNIQUE_INDEX(pg_operator_oprname_l_r_n_index, 2689, on pg_operator using btree(oprname name_ops, oprleft oid_ops, oprright oid_ops, oprnamespace oid_ops)); #define OperatorNameNspIndexId 2689 diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h index c00eda0785328..18385a6fd6c09 100644 --- a/src/include/catalog/pg_opfamily.h +++ b/src/include/catalog/pg_opfamily.h @@ -52,7 +52,7 @@ typedef FormData_pg_opfamily *Form_pg_opfamily; DECLARE_UNIQUE_INDEX(pg_opfamily_am_name_nsp_index, 2754, on pg_opfamily using btree(opfmethod oid_ops, opfname name_ops, opfnamespace oid_ops)); #define OpfamilyAmNameNspIndexId 2754 -DECLARE_UNIQUE_INDEX(pg_opfamily_oid_index, 2755, on pg_opfamily using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_opfamily_oid_index, 2755, on pg_opfamily using btree(oid oid_ops)); #define OpfamilyOidIndexId 2755 #ifdef EXPOSE_TO_CLIENT_CODE diff --git a/src/include/catalog/pg_partitioned_table.h b/src/include/catalog/pg_partitioned_table.h index f51d7e16bf991..038730b00536c 100644 --- a/src/include/catalog/pg_partitioned_table.h +++ b/src/include/catalog/pg_partitioned_table.h @@ -66,7 +66,7 @@ typedef FormData_pg_partitioned_table *Form_pg_partitioned_table; DECLARE_TOAST(pg_partitioned_table, 4165, 4166); -DECLARE_UNIQUE_INDEX(pg_partitioned_table_partrelid_index, 3351, on pg_partitioned_table using btree(partrelid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_partitioned_table_partrelid_index, 3351, on pg_partitioned_table using btree(partrelid oid_ops)); #define PartitionedRelidIndexId 3351 #endif /* PG_PARTITIONED_TABLE_H */ diff --git a/src/include/catalog/pg_policy.h b/src/include/catalog/pg_policy.h index a5af6eb352ba9..44197613e06be 100644 --- a/src/include/catalog/pg_policy.h +++ b/src/include/catalog/pg_policy.h @@ -51,7 +51,7 @@ typedef FormData_pg_policy *Form_pg_policy; DECLARE_TOAST(pg_policy, 4167, 4168); -DECLARE_UNIQUE_INDEX(pg_policy_oid_index, 3257, on pg_policy using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_policy_oid_index, 3257, on pg_policy using btree(oid oid_ops)); #define PolicyOidIndexId 3257 DECLARE_UNIQUE_INDEX(pg_policy_polrelid_polname_index, 3258, on pg_policy using btree(polrelid oid_ops, polname name_ops)); #define PolicyPolrelidPolnameIndexId 3258 diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 1c2551c932732..03c8bef42274d 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -134,7 +134,7 @@ typedef FormData_pg_proc *Form_pg_proc; DECLARE_TOAST(pg_proc, 2836, 2837); -DECLARE_UNIQUE_INDEX(pg_proc_oid_index, 2690, on pg_proc using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_proc_oid_index, 2690, on pg_proc using btree(oid oid_ops)); #define ProcedureOidIndexId 2690 DECLARE_UNIQUE_INDEX(pg_proc_proname_args_nsp_index, 2691, on pg_proc using btree(proname name_ops, proargtypes oidvector_ops, pronamespace oid_ops)); #define ProcedureNameArgsNspIndexId 2691 diff --git a/src/include/catalog/pg_publication.h b/src/include/catalog/pg_publication.h index 0dd50fe428fe7..4127611f5a6b5 100644 --- a/src/include/catalog/pg_publication.h +++ b/src/include/catalog/pg_publication.h @@ -63,7 +63,7 @@ CATALOG(pg_publication,6104,PublicationRelationId) */ typedef FormData_pg_publication *Form_pg_publication; -DECLARE_UNIQUE_INDEX(pg_publication_oid_index, 6110, on pg_publication using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_publication_oid_index, 6110, on pg_publication using btree(oid oid_ops)); #define PublicationObjectIndexId 6110 DECLARE_UNIQUE_INDEX(pg_publication_pubname_index, 6111, on pg_publication using btree(pubname name_ops)); #define PublicationNameIndexId 6111 diff --git a/src/include/catalog/pg_publication_rel.h b/src/include/catalog/pg_publication_rel.h index 6e6ec6444d174..c79b7fb4874a5 100644 --- a/src/include/catalog/pg_publication_rel.h +++ b/src/include/catalog/pg_publication_rel.h @@ -40,7 +40,7 @@ CATALOG(pg_publication_rel,6106,PublicationRelRelationId) */ typedef FormData_pg_publication_rel *Form_pg_publication_rel; -DECLARE_UNIQUE_INDEX(pg_publication_rel_oid_index, 6112, on pg_publication_rel using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_publication_rel_oid_index, 6112, on pg_publication_rel using btree(oid oid_ops)); #define PublicationRelObjectIndexId 6112 DECLARE_UNIQUE_INDEX(pg_publication_rel_prrelid_prpubid_index, 6113, on pg_publication_rel using btree(prrelid oid_ops, prpubid oid_ops)); #define PublicationRelPrrelidPrpubidIndexId 6113 diff --git a/src/include/catalog/pg_range.h b/src/include/catalog/pg_range.h index f0c3897184480..2ec6a4b126bb2 100644 --- a/src/include/catalog/pg_range.h +++ b/src/include/catalog/pg_range.h @@ -57,7 +57,7 @@ CATALOG(pg_range,3541,RangeRelationId) */ typedef FormData_pg_range *Form_pg_range; -DECLARE_UNIQUE_INDEX(pg_range_rngtypid_index, 3542, on pg_range using btree(rngtypid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_range_rngtypid_index, 3542, on pg_range using btree(rngtypid oid_ops)); #define RangeTypidIndexId 3542 DECLARE_UNIQUE_INDEX(pg_range_rngmultitypid_index, 2228, on pg_range using btree(rngmultitypid oid_ops)); diff --git a/src/include/catalog/pg_replication_origin.h b/src/include/catalog/pg_replication_origin.h index bd44968f88676..184f2403ceb0f 100644 --- a/src/include/catalog/pg_replication_origin.h +++ b/src/include/catalog/pg_replication_origin.h @@ -58,7 +58,7 @@ DECLARE_TOAST(pg_replication_origin, 4181, 4182); #define PgReplicationOriginToastTable 4181 #define PgReplicationOriginToastIndex 4182 -DECLARE_UNIQUE_INDEX(pg_replication_origin_roiident_index, 6001, on pg_replication_origin using btree(roident oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_replication_origin_roiident_index, 6001, on pg_replication_origin using btree(roident oid_ops)); #define ReplicationOriginIdentIndex 6001 DECLARE_UNIQUE_INDEX(pg_replication_origin_roname_index, 6002, on pg_replication_origin using btree(roname text_ops)); #define ReplicationOriginNameIndex 6002 diff --git a/src/include/catalog/pg_rewrite.h b/src/include/catalog/pg_rewrite.h index 61615cea21026..36f92b1cf1358 100644 --- a/src/include/catalog/pg_rewrite.h +++ b/src/include/catalog/pg_rewrite.h @@ -53,7 +53,7 @@ typedef FormData_pg_rewrite *Form_pg_rewrite; DECLARE_TOAST(pg_rewrite, 2838, 2839); -DECLARE_UNIQUE_INDEX(pg_rewrite_oid_index, 2692, on pg_rewrite using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_rewrite_oid_index, 2692, on pg_rewrite using btree(oid oid_ops)); #define RewriteOidIndexId 2692 DECLARE_UNIQUE_INDEX(pg_rewrite_rel_rulename_index, 2693, on pg_rewrite using btree(ev_class oid_ops, rulename name_ops)); #define RewriteRelRulenameIndexId 2693 diff --git a/src/include/catalog/pg_seclabel.h b/src/include/catalog/pg_seclabel.h index caf67ab760601..b14fd7febe814 100644 --- a/src/include/catalog/pg_seclabel.h +++ b/src/include/catalog/pg_seclabel.h @@ -39,7 +39,7 @@ CATALOG(pg_seclabel,3596,SecLabelRelationId) DECLARE_TOAST(pg_seclabel, 3598, 3599); -DECLARE_UNIQUE_INDEX(pg_seclabel_object_index, 3597, on pg_seclabel using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops, provider text_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_seclabel_object_index, 3597, on pg_seclabel using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops, provider text_ops)); #define SecLabelObjectIndexId 3597 #endif /* PG_SECLABEL_H */ diff --git a/src/include/catalog/pg_sequence.h b/src/include/catalog/pg_sequence.h index 61fe5a1930ce3..addf21abce95b 100644 --- a/src/include/catalog/pg_sequence.h +++ b/src/include/catalog/pg_sequence.h @@ -39,7 +39,7 @@ CATALOG(pg_sequence,2224,SequenceRelationId) */ typedef FormData_pg_sequence *Form_pg_sequence; -DECLARE_UNIQUE_INDEX(pg_sequence_seqrelid_index, 5002, on pg_sequence using btree(seqrelid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_sequence_seqrelid_index, 5002, on pg_sequence using btree(seqrelid oid_ops)); #define SequenceRelidIndexId 5002 #endif /* PG_SEQUENCE_H */ diff --git a/src/include/catalog/pg_shdescription.h b/src/include/catalog/pg_shdescription.h index 5ecb95c00cf25..a37db4fa0b44e 100644 --- a/src/include/catalog/pg_shdescription.h +++ b/src/include/catalog/pg_shdescription.h @@ -59,7 +59,7 @@ DECLARE_TOAST(pg_shdescription, 2846, 2847); #define PgShdescriptionToastTable 2846 #define PgShdescriptionToastIndex 2847 -DECLARE_UNIQUE_INDEX(pg_shdescription_o_c_index, 2397, on pg_shdescription using btree(objoid oid_ops, classoid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_shdescription_o_c_index, 2397, on pg_shdescription using btree(objoid oid_ops, classoid oid_ops)); #define SharedDescriptionObjIndexId 2397 #endif /* PG_SHDESCRIPTION_H */ diff --git a/src/include/catalog/pg_shseclabel.h b/src/include/catalog/pg_shseclabel.h index dd8900316913f..406f5328a7031 100644 --- a/src/include/catalog/pg_shseclabel.h +++ b/src/include/catalog/pg_shseclabel.h @@ -42,7 +42,7 @@ DECLARE_TOAST(pg_shseclabel, 4060, 4061); #define PgShseclabelToastTable 4060 #define PgShseclabelToastIndex 4061 -DECLARE_UNIQUE_INDEX(pg_shseclabel_object_index, 3593, on pg_shseclabel using btree(objoid oid_ops, classoid oid_ops, provider text_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_shseclabel_object_index, 3593, on pg_shseclabel using btree(objoid oid_ops, classoid oid_ops, provider text_ops)); #define SharedSecLabelObjectIndexId 3593 #endif /* PG_SHSECLABEL_H */ diff --git a/src/include/catalog/pg_statistic.h b/src/include/catalog/pg_statistic.h index 3f1534c29a26f..4a66bda879ca3 100644 --- a/src/include/catalog/pg_statistic.h +++ b/src/include/catalog/pg_statistic.h @@ -135,7 +135,7 @@ typedef FormData_pg_statistic *Form_pg_statistic; DECLARE_TOAST(pg_statistic, 2840, 2841); -DECLARE_UNIQUE_INDEX(pg_statistic_relid_att_inh_index, 2696, on pg_statistic using btree(starelid oid_ops, staattnum int2_ops, stainherit bool_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_statistic_relid_att_inh_index, 2696, on pg_statistic using btree(starelid oid_ops, staattnum int2_ops, stainherit bool_ops)); #define StatisticRelidAttnumInhIndexId 2696 #ifdef EXPOSE_TO_CLIENT_CODE diff --git a/src/include/catalog/pg_statistic_ext.h b/src/include/catalog/pg_statistic_ext.h index 99f6cea0a5349..10f52f912cb7f 100644 --- a/src/include/catalog/pg_statistic_ext.h +++ b/src/include/catalog/pg_statistic_ext.h @@ -65,7 +65,7 @@ typedef FormData_pg_statistic_ext *Form_pg_statistic_ext; DECLARE_TOAST(pg_statistic_ext, 3439, 3440); -DECLARE_UNIQUE_INDEX(pg_statistic_ext_oid_index, 3380, on pg_statistic_ext using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_statistic_ext_oid_index, 3380, on pg_statistic_ext using btree(oid oid_ops)); #define StatisticExtOidIndexId 3380 DECLARE_UNIQUE_INDEX(pg_statistic_ext_name_index, 3997, on pg_statistic_ext using btree(stxname name_ops, stxnamespace oid_ops)); #define StatisticExtNameIndexId 3997 diff --git a/src/include/catalog/pg_statistic_ext_data.h b/src/include/catalog/pg_statistic_ext_data.h index e0aa152f7b648..6f7a36c14181a 100644 --- a/src/include/catalog/pg_statistic_ext_data.h +++ b/src/include/catalog/pg_statistic_ext_data.h @@ -51,7 +51,7 @@ typedef FormData_pg_statistic_ext_data * Form_pg_statistic_ext_data; DECLARE_TOAST(pg_statistic_ext_data, 3430, 3431); -DECLARE_UNIQUE_INDEX(pg_statistic_ext_data_stxoid_index, 3433, on pg_statistic_ext_data using btree(stxoid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_statistic_ext_data_stxoid_index, 3433, on pg_statistic_ext_data using btree(stxoid oid_ops)); #define StatisticExtDataStxoidIndexId 3433 #endif /* PG_STATISTIC_EXT_DATA_H */ diff --git a/src/include/catalog/pg_subscription.h b/src/include/catalog/pg_subscription.h index e3618028f7eed..4e44c29149631 100644 --- a/src/include/catalog/pg_subscription.h +++ b/src/include/catalog/pg_subscription.h @@ -74,7 +74,7 @@ DECLARE_TOAST(pg_subscription, 4183, 4184); #define PgSubscriptionToastTable 4183 #define PgSubscriptionToastIndex 4184 -DECLARE_UNIQUE_INDEX(pg_subscription_oid_index, 6114, on pg_subscription using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_subscription_oid_index, 6114, on pg_subscription using btree(oid oid_ops)); #define SubscriptionObjectIndexId 6114 DECLARE_UNIQUE_INDEX(pg_subscription_subname_index, 6115, on pg_subscription using btree(subdbid oid_ops, subname name_ops)); #define SubscriptionNameIndexId 6115 diff --git a/src/include/catalog/pg_subscription_rel.h b/src/include/catalog/pg_subscription_rel.h index 06663b9f16cd1..ab1202cf9bff8 100644 --- a/src/include/catalog/pg_subscription_rel.h +++ b/src/include/catalog/pg_subscription_rel.h @@ -49,7 +49,7 @@ CATALOG(pg_subscription_rel,6102,SubscriptionRelRelationId) typedef FormData_pg_subscription_rel *Form_pg_subscription_rel; -DECLARE_UNIQUE_INDEX(pg_subscription_rel_srrelid_srsubid_index, 6117, on pg_subscription_rel using btree(srrelid oid_ops, srsubid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_subscription_rel_srrelid_srsubid_index, 6117, on pg_subscription_rel using btree(srrelid oid_ops, srsubid oid_ops)); #define SubscriptionRelSrrelidSrsubidIndexId 6117 #ifdef EXPOSE_TO_CLIENT_CODE diff --git a/src/include/catalog/pg_tablespace.h b/src/include/catalog/pg_tablespace.h index ff92e20c5bfe3..6a6c66a61c848 100644 --- a/src/include/catalog/pg_tablespace.h +++ b/src/include/catalog/pg_tablespace.h @@ -49,7 +49,7 @@ DECLARE_TOAST(pg_tablespace, 4185, 4186); #define PgTablespaceToastTable 4185 #define PgTablespaceToastIndex 4186 -DECLARE_UNIQUE_INDEX(pg_tablespace_oid_index, 2697, on pg_tablespace using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_tablespace_oid_index, 2697, on pg_tablespace using btree(oid oid_ops)); #define TablespaceOidIndexId 2697 DECLARE_UNIQUE_INDEX(pg_tablespace_spcname_index, 2698, on pg_tablespace using btree(spcname name_ops)); #define TablespaceNameIndexId 2698 diff --git a/src/include/catalog/pg_transform.h b/src/include/catalog/pg_transform.h index 474baf35473fb..ad25db1841199 100644 --- a/src/include/catalog/pg_transform.h +++ b/src/include/catalog/pg_transform.h @@ -42,7 +42,7 @@ CATALOG(pg_transform,3576,TransformRelationId) */ typedef FormData_pg_transform *Form_pg_transform; -DECLARE_UNIQUE_INDEX(pg_transform_oid_index, 3574, on pg_transform using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_transform_oid_index, 3574, on pg_transform using btree(oid oid_ops)); #define TransformOidIndexId 3574 DECLARE_UNIQUE_INDEX(pg_transform_type_lang_index, 3575, on pg_transform using btree(trftype oid_ops, trflang oid_ops)); #define TransformTypeLangIndexId 3575 diff --git a/src/include/catalog/pg_trigger.h b/src/include/catalog/pg_trigger.h index 9afea78900d9e..55111ed864e9b 100644 --- a/src/include/catalog/pg_trigger.h +++ b/src/include/catalog/pg_trigger.h @@ -78,7 +78,7 @@ DECLARE_INDEX(pg_trigger_tgconstraint_index, 2699, on pg_trigger using btree(tgc #define TriggerConstraintIndexId 2699 DECLARE_UNIQUE_INDEX(pg_trigger_tgrelid_tgname_index, 2701, on pg_trigger using btree(tgrelid oid_ops, tgname name_ops)); #define TriggerRelidNameIndexId 2701 -DECLARE_UNIQUE_INDEX(pg_trigger_oid_index, 2702, on pg_trigger using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_trigger_oid_index, 2702, on pg_trigger using btree(oid oid_ops)); #define TriggerOidIndexId 2702 #ifdef EXPOSE_TO_CLIENT_CODE diff --git a/src/include/catalog/pg_ts_config.h b/src/include/catalog/pg_ts_config.h index aef7da0f76f6f..02ef1a1554404 100644 --- a/src/include/catalog/pg_ts_config.h +++ b/src/include/catalog/pg_ts_config.h @@ -49,7 +49,7 @@ typedef FormData_pg_ts_config *Form_pg_ts_config; DECLARE_UNIQUE_INDEX(pg_ts_config_cfgname_index, 3608, on pg_ts_config using btree(cfgname name_ops, cfgnamespace oid_ops)); #define TSConfigNameNspIndexId 3608 -DECLARE_UNIQUE_INDEX(pg_ts_config_oid_index, 3712, on pg_ts_config using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_ts_config_oid_index, 3712, on pg_ts_config using btree(oid oid_ops)); #define TSConfigOidIndexId 3712 #endif /* PG_TS_CONFIG_H */ diff --git a/src/include/catalog/pg_ts_config_map.h b/src/include/catalog/pg_ts_config_map.h index 95901a94067d0..f39d14fd79579 100644 --- a/src/include/catalog/pg_ts_config_map.h +++ b/src/include/catalog/pg_ts_config_map.h @@ -44,7 +44,7 @@ CATALOG(pg_ts_config_map,3603,TSConfigMapRelationId) typedef FormData_pg_ts_config_map *Form_pg_ts_config_map; -DECLARE_UNIQUE_INDEX(pg_ts_config_map_index, 3609, on pg_ts_config_map using btree(mapcfg oid_ops, maptokentype int4_ops, mapseqno int4_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_ts_config_map_index, 3609, on pg_ts_config_map using btree(mapcfg oid_ops, maptokentype int4_ops, mapseqno int4_ops)); #define TSConfigMapIndexId 3609 #endif /* PG_TS_CONFIG_MAP_H */ diff --git a/src/include/catalog/pg_ts_dict.h b/src/include/catalog/pg_ts_dict.h index 814d0d4407a36..bfe3378ff893c 100644 --- a/src/include/catalog/pg_ts_dict.h +++ b/src/include/catalog/pg_ts_dict.h @@ -55,7 +55,7 @@ DECLARE_TOAST(pg_ts_dict, 4169, 4170); DECLARE_UNIQUE_INDEX(pg_ts_dict_dictname_index, 3604, on pg_ts_dict using btree(dictname name_ops, dictnamespace oid_ops)); #define TSDictionaryNameNspIndexId 3604 -DECLARE_UNIQUE_INDEX(pg_ts_dict_oid_index, 3605, on pg_ts_dict using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_ts_dict_oid_index, 3605, on pg_ts_dict using btree(oid oid_ops)); #define TSDictionaryOidIndexId 3605 #endif /* PG_TS_DICT_H */ diff --git a/src/include/catalog/pg_ts_parser.h b/src/include/catalog/pg_ts_parser.h index 57480ebfaf25a..f9f22716fd470 100644 --- a/src/include/catalog/pg_ts_parser.h +++ b/src/include/catalog/pg_ts_parser.h @@ -56,7 +56,7 @@ typedef FormData_pg_ts_parser *Form_pg_ts_parser; DECLARE_UNIQUE_INDEX(pg_ts_parser_prsname_index, 3606, on pg_ts_parser using btree(prsname name_ops, prsnamespace oid_ops)); #define TSParserNameNspIndexId 3606 -DECLARE_UNIQUE_INDEX(pg_ts_parser_oid_index, 3607, on pg_ts_parser using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_ts_parser_oid_index, 3607, on pg_ts_parser using btree(oid oid_ops)); #define TSParserOidIndexId 3607 #endif /* PG_TS_PARSER_H */ diff --git a/src/include/catalog/pg_ts_template.h b/src/include/catalog/pg_ts_template.h index c1c7fedbe704f..ae91922688989 100644 --- a/src/include/catalog/pg_ts_template.h +++ b/src/include/catalog/pg_ts_template.h @@ -47,7 +47,7 @@ typedef FormData_pg_ts_template *Form_pg_ts_template; DECLARE_UNIQUE_INDEX(pg_ts_template_tmplname_index, 3766, on pg_ts_template using btree(tmplname name_ops, tmplnamespace oid_ops)); #define TSTemplateNameNspIndexId 3766 -DECLARE_UNIQUE_INDEX(pg_ts_template_oid_index, 3767, on pg_ts_template using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_ts_template_oid_index, 3767, on pg_ts_template using btree(oid oid_ops)); #define TSTemplateOidIndexId 3767 #endif /* PG_TS_TEMPLATE_H */ diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index 37345bec00e9e..0d6981bc879d1 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -262,7 +262,7 @@ typedef FormData_pg_type *Form_pg_type; DECLARE_TOAST(pg_type, 4171, 4172); -DECLARE_UNIQUE_INDEX(pg_type_oid_index, 2703, on pg_type using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_type_oid_index, 2703, on pg_type using btree(oid oid_ops)); #define TypeOidIndexId 2703 DECLARE_UNIQUE_INDEX(pg_type_typname_nsp_index, 2704, on pg_type using btree(typname name_ops, typnamespace oid_ops)); #define TypeNameNspIndexId 2704 diff --git a/src/include/catalog/pg_user_mapping.h b/src/include/catalog/pg_user_mapping.h index 3589125015041..cabca048a928b 100644 --- a/src/include/catalog/pg_user_mapping.h +++ b/src/include/catalog/pg_user_mapping.h @@ -47,7 +47,7 @@ typedef FormData_pg_user_mapping *Form_pg_user_mapping; DECLARE_TOAST(pg_user_mapping, 4173, 4174); -DECLARE_UNIQUE_INDEX(pg_user_mapping_oid_index, 174, on pg_user_mapping using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_user_mapping_oid_index, 174, on pg_user_mapping using btree(oid oid_ops)); #define UserMappingOidIndexId 174 DECLARE_UNIQUE_INDEX(pg_user_mapping_user_server_index, 175, on pg_user_mapping using btree(umuser oid_ops, umserver oid_ops)); #define UserMappingUserServerIndexId 175 diff --git a/src/test/modules/unsafe_tests/expected/alter_system_table.out b/src/test/modules/unsafe_tests/expected/alter_system_table.out index ecd1505cdcd4f..4b2f63a95ed9d 100644 --- a/src/test/modules/unsafe_tests/expected/alter_system_table.out +++ b/src/test/modules/unsafe_tests/expected/alter_system_table.out @@ -16,7 +16,7 @@ DETAIL: System catalog modifications are currently disallowed. CREATE TABLE t1x (a int, b anyarray); ERROR: column "b" has pseudo-type anyarray -- index on system catalog -ALTER TABLE pg_namespace ADD UNIQUE USING INDEX pg_namespace_oid_index; +ALTER TABLE pg_namespace ADD CONSTRAINT foo UNIQUE USING INDEX pg_namespace_nspname_index; ERROR: permission denied: "pg_namespace" is a system catalog -- write to system catalog table as superuser -- (allowed even without allow_system_table_mods) @@ -102,7 +102,8 @@ CREATE TABLE t1 (a int, b anyarray); ROLLBACK; -- index on system catalog BEGIN; -ALTER TABLE pg_namespace ADD UNIQUE USING INDEX pg_namespace_oid_index; +ALTER TABLE pg_namespace ADD CONSTRAINT foo UNIQUE USING INDEX pg_namespace_nspname_index; +NOTICE: ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index "pg_namespace_nspname_index" to "foo" ROLLBACK; -- write to system catalog table as superuser BEGIN; @@ -146,7 +147,6 @@ ALTER TABLE pg_description ALTER COLUMN description SET STATISTICS -1; ROLLBACK; -- foreign key referencing catalog BEGIN; -ALTER TABLE pg_description ADD PRIMARY KEY USING INDEX pg_description_o_c_o_index; CREATE TABLE foo (a oid, b oid, c int, FOREIGN KEY (a, b, c) REFERENCES pg_description); ROLLBACK; -- RangeVarCallbackOwnsRelation() diff --git a/src/test/modules/unsafe_tests/sql/alter_system_table.sql b/src/test/modules/unsafe_tests/sql/alter_system_table.sql index 5663570d312d0..6bfc896ef9cf5 100644 --- a/src/test/modules/unsafe_tests/sql/alter_system_table.sql +++ b/src/test/modules/unsafe_tests/sql/alter_system_table.sql @@ -18,7 +18,7 @@ CREATE TABLE pg_catalog.test (a int); CREATE TABLE t1x (a int, b anyarray); -- index on system catalog -ALTER TABLE pg_namespace ADD UNIQUE USING INDEX pg_namespace_oid_index; +ALTER TABLE pg_namespace ADD CONSTRAINT foo UNIQUE USING INDEX pg_namespace_nspname_index; -- write to system catalog table as superuser -- (allowed even without allow_system_table_mods) @@ -104,7 +104,7 @@ ROLLBACK; -- index on system catalog BEGIN; -ALTER TABLE pg_namespace ADD UNIQUE USING INDEX pg_namespace_oid_index; +ALTER TABLE pg_namespace ADD CONSTRAINT foo UNIQUE USING INDEX pg_namespace_nspname_index; ROLLBACK; -- write to system catalog table as superuser @@ -156,7 +156,6 @@ ROLLBACK; -- foreign key referencing catalog BEGIN; -ALTER TABLE pg_description ADD PRIMARY KEY USING INDEX pg_description_o_c_o_index; CREATE TABLE foo (a oid, b oid, c int, FOREIGN KEY (a, b, c) REFERENCES pg_description); ROLLBACK; diff --git a/src/test/regress/expected/misc_sanity.out b/src/test/regress/expected/misc_sanity.out index d40afeef784c9..9ebe28a78da30 100644 --- a/src/test/regress/expected/misc_sanity.out +++ b/src/test/regress/expected/misc_sanity.out @@ -43,6 +43,9 @@ WHERE refclassid = 0 OR refobjid = 0 OR -- whatever OID the test is complaining about must have been added later -- in initdb, where it intentionally isn't pinned. Legitimate exceptions -- to that rule are listed in the comments in setup_depend(). +-- Currently, pg_rewrite is also listed by this check, even though it is +-- covered by setup_depend(). That happens because there are no rules in +-- the pinned data, but initdb creates some intentionally-not-pinned views. do $$ declare relnm text; reloid oid; @@ -73,7 +76,6 @@ loop end if; end loop; end$$; -NOTICE: pg_constraint contains unpinned initdb-created object(s) NOTICE: pg_database contains unpinned initdb-created object(s) NOTICE: pg_extension contains unpinned initdb-created object(s) NOTICE: pg_rewrite contains unpinned initdb-created object(s) @@ -109,3 +111,30 @@ ORDER BY 1, 2; pg_largeobject_metadata | lomacl | aclitem[] (11 rows) +-- system catalogs without primary keys +-- +-- Current exceptions: +-- * pg_depend, pg_shdepend don't have a unique key +SELECT relname +FROM pg_class +WHERE relnamespace = 'pg_catalog'::regnamespace AND relkind = 'r' + AND pg_class.oid NOT IN (SELECT indrelid FROM pg_index WHERE indisprimary) +ORDER BY 1; + relname +------------- + pg_depend + pg_shdepend +(2 rows) + +-- system catalog unique indexes not wrapped in a constraint +-- (There should be none.) +SELECT relname +FROM pg_class c JOIN pg_index i ON c.oid = i.indexrelid +WHERE relnamespace = 'pg_catalog'::regnamespace AND relkind = 'i' + AND i.indisunique + AND c.oid NOT IN (SELECT conindid FROM pg_constraint) +ORDER BY 1; + relname +--------- +(0 rows) + diff --git a/src/test/regress/sql/misc_sanity.sql b/src/test/regress/sql/misc_sanity.sql index 3ce32e4725266..9699f5cc3b3bc 100644 --- a/src/test/regress/sql/misc_sanity.sql +++ b/src/test/regress/sql/misc_sanity.sql @@ -44,6 +44,9 @@ WHERE refclassid = 0 OR refobjid = 0 OR -- whatever OID the test is complaining about must have been added later -- in initdb, where it intentionally isn't pinned. Legitimate exceptions -- to that rule are listed in the comments in setup_depend(). +-- Currently, pg_rewrite is also listed by this check, even though it is +-- covered by setup_depend(). That happens because there are no rules in +-- the pinned data, but initdb creates some intentionally-not-pinned views. do $$ declare relnm text; @@ -94,3 +97,24 @@ WHERE c.oid < 16384 AND relkind = 'r' AND attstorage != 'p' ORDER BY 1, 2; + + +-- system catalogs without primary keys +-- +-- Current exceptions: +-- * pg_depend, pg_shdepend don't have a unique key +SELECT relname +FROM pg_class +WHERE relnamespace = 'pg_catalog'::regnamespace AND relkind = 'r' + AND pg_class.oid NOT IN (SELECT indrelid FROM pg_index WHERE indisprimary) +ORDER BY 1; + + +-- system catalog unique indexes not wrapped in a constraint +-- (There should be none.) +SELECT relname +FROM pg_class c JOIN pg_index i ON c.oid = i.indexrelid +WHERE relnamespace = 'pg_catalog'::regnamespace AND relkind = 'i' + AND i.indisunique + AND c.oid NOT IN (SELECT conindid FROM pg_constraint) +ORDER BY 1; diff --git a/src/tools/msvc/clean.bat b/src/tools/msvc/clean.bat index 672bb2d65031f..4575e3f95f69c 100755 --- a/src/tools/msvc/clean.bat +++ b/src/tools/msvc/clean.bat @@ -71,6 +71,7 @@ if %DIST%==1 if exist src\interfaces\ecpg\preproc\c_kwlist_d.h del /q src\interf if %DIST%==1 if exist src\interfaces\ecpg\preproc\ecpg_kwlist_d.h del /q src\interfaces\ecpg\preproc\ecpg_kwlist_d.h if %DIST%==1 if exist src\interfaces\ecpg\preproc\preproc.y del /q src\interfaces\ecpg\preproc\preproc.y if %DIST%==1 if exist src\backend\catalog\postgres.bki del /q src\backend\catalog\postgres.bki +if %DIST%==1 if exist src\backend\catalog\system_constraints.sql del /q src\backend\catalog\system_constraints.sql if %DIST%==1 if exist src\backend\catalog\schemapg.h del /q src\backend\catalog\schemapg.h if %DIST%==1 if exist src\backend\catalog\pg_*_d.h del /q src\backend\catalog\pg_*_d.h if %DIST%==1 if exist src\backend\catalog\bki-stamp del /q src\backend\catalog\bki-stamp From 0c4f355c6a5fd437f71349f2f3d5d491382572b7 Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Sun, 31 Jan 2021 20:14:29 +0300 Subject: [PATCH 218/240] Fix parsing of complex morphs to tsquery When to_tsquery() or websearch_to_tsquery() meet a complex morph containing multiple words residing adjacent position, these words are connected with OP_AND operator. That leads to surprising results. For instace, both websearch_to_tsquery('"pg_class pg"') and to_tsquery('pg_class <-> pg') produce '( pg & class ) <-> pg' tsquery. This tsquery requires 'pg' and 'class' words to reside on the same position and doesn't match to to_tsvector('pg_class pg'). It appears to be ridiculous behavior, which needs to be fixed. This commit makes to_tsquery() or websearch_to_tsquery() connect words residing adjacent position with OP_PHRASE. Therefore, now those words are normally chained with other OP_PHRASE operator. The examples of above now produces 'pg <-> class <-> pg' tsquery, which matches to to_tsvector('pg_class pg'). Another effect of this commit is that complex morph word positions now need to match the tsvector even if there is no surrounding OP_PHRASE. This behavior change generally looks like an improvement but making this commit not backpatchable. Reported-by: Barry Pederson Bug: #16592 Discussion: https://postgr.es/m/16592-70b110ff9731c07d@postgresql.org Discussion: https://postgr.es/m/CAPpHfdv0EzVhf6CWfB1_TTZqXV_2Sn-jSY3zSd7ePH%3D-%2B1V2DQ%40mail.gmail.com Author: Alexander Korotkov Reviewed-by: Tom Lane, Neil Chen --- src/backend/tsearch/to_tsany.c | 41 ++++++- src/test/regress/expected/tsearch.out | 152 +++++++++++++------------- src/test/regress/sql/tsearch.sql | 36 +++--- 3 files changed, 132 insertions(+), 97 deletions(-) diff --git a/src/backend/tsearch/to_tsany.c b/src/backend/tsearch/to_tsany.c index e4ad661a8baa8..f4ddfc01059ec 100644 --- a/src/backend/tsearch/to_tsany.c +++ b/src/backend/tsearch/to_tsany.c @@ -20,10 +20,20 @@ #include "utils/jsonfuncs.h" +/* + * Opaque data structure, which is passed by parse_tsquery() to pushval_morph(). + */ typedef struct MorphOpaque { Oid cfg_id; - int qoperator; /* query operator */ + + /* + * Single tsquery morph could be parsed into multiple words. When these + * words reside in adjacent positions, they are connected using this + * operator. Usually, that is OP_PHRASE, which requires word positions of + * a complex morph to exactly match the tsvector. + */ + int qoperator; } MorphOpaque; typedef struct TSVectorBuildState @@ -573,7 +583,14 @@ to_tsquery_byid(PG_FUNCTION_ARGS) MorphOpaque data; data.cfg_id = PG_GETARG_OID(0); - data.qoperator = OP_AND; + + /* + * Passing OP_PHRASE as a qoperator makes tsquery require matching of word + * positions of a complex morph exactly match the tsvector. Also, when + * the complex morphs are connected with OP_PHRASE operator, we connect + * all their words into the OP_PHRASE sequence. + */ + data.qoperator = OP_PHRASE; query = parse_tsquery(text_to_cstring(in), pushval_morph, @@ -603,6 +620,12 @@ plainto_tsquery_byid(PG_FUNCTION_ARGS) MorphOpaque data; data.cfg_id = PG_GETARG_OID(0); + + /* + * parse_tsquery() with P_TSQ_PLAIN flag takes the whole input text as a + * single morph. Passing OP_PHRASE as a qoperator makes tsquery require + * matching of all words independently on their positions. + */ data.qoperator = OP_AND; query = parse_tsquery(text_to_cstring(in), @@ -634,6 +657,12 @@ phraseto_tsquery_byid(PG_FUNCTION_ARGS) MorphOpaque data; data.cfg_id = PG_GETARG_OID(0); + + /* + * parse_tsquery() with P_TSQ_PLAIN flag takes the whole input text as a + * single morph. Passing OP_PHRASE as a qoperator makes tsquery require + * matching of word positions. + */ data.qoperator = OP_PHRASE; query = parse_tsquery(text_to_cstring(in), @@ -665,7 +694,13 @@ websearch_to_tsquery_byid(PG_FUNCTION_ARGS) data.cfg_id = PG_GETARG_OID(0); - data.qoperator = OP_AND; + /* + * Passing OP_PHRASE as a qoperator makes tsquery require matching of word + * positions of a complex morph exactly match the tsvector. Also, when + * the complex morphs are given in quotes, we connect all their words into + * the OP_PHRASE sequence. + */ + data.qoperator = OP_PHRASE; query = parse_tsquery(text_to_cstring(in), pushval_morph, diff --git a/src/test/regress/expected/tsearch.out b/src/test/regress/expected/tsearch.out index 0110b4d2e0d8d..4ae62320c9ffe 100644 --- a/src/test/regress/expected/tsearch.out +++ b/src/test/regress/expected/tsearch.out @@ -1997,31 +1997,31 @@ ALTER TABLE test_tsquery ADD COLUMN keyword tsquery; UPDATE test_tsquery SET keyword = to_tsquery('english', txtkeyword); ALTER TABLE test_tsquery ADD COLUMN sample tsquery; UPDATE test_tsquery SET sample = to_tsquery('english', txtsample::text); -SELECT COUNT(*) FROM test_tsquery WHERE keyword < 'new & york'; +SELECT COUNT(*) FROM test_tsquery WHERE keyword < 'new <-> york'; count ------- 2 (1 row) -SELECT COUNT(*) FROM test_tsquery WHERE keyword <= 'new & york'; +SELECT COUNT(*) FROM test_tsquery WHERE keyword <= 'new <-> york'; count ------- 3 (1 row) -SELECT COUNT(*) FROM test_tsquery WHERE keyword = 'new & york'; +SELECT COUNT(*) FROM test_tsquery WHERE keyword = 'new <-> york'; count ------- 1 (1 row) -SELECT COUNT(*) FROM test_tsquery WHERE keyword >= 'new & york'; +SELECT COUNT(*) FROM test_tsquery WHERE keyword >= 'new <-> york'; count ------- 4 (1 row) -SELECT COUNT(*) FROM test_tsquery WHERE keyword > 'new & york'; +SELECT COUNT(*) FROM test_tsquery WHERE keyword > 'new <-> york'; count ------- 3 @@ -2029,31 +2029,31 @@ SELECT COUNT(*) FROM test_tsquery WHERE keyword > 'new & york'; CREATE UNIQUE INDEX bt_tsq ON test_tsquery (keyword); SET enable_seqscan=OFF; -SELECT COUNT(*) FROM test_tsquery WHERE keyword < 'new & york'; +SELECT COUNT(*) FROM test_tsquery WHERE keyword < 'new <-> york'; count ------- 2 (1 row) -SELECT COUNT(*) FROM test_tsquery WHERE keyword <= 'new & york'; +SELECT COUNT(*) FROM test_tsquery WHERE keyword <= 'new <-> york'; count ------- 3 (1 row) -SELECT COUNT(*) FROM test_tsquery WHERE keyword = 'new & york'; +SELECT COUNT(*) FROM test_tsquery WHERE keyword = 'new <-> york'; count ------- 1 (1 row) -SELECT COUNT(*) FROM test_tsquery WHERE keyword >= 'new & york'; +SELECT COUNT(*) FROM test_tsquery WHERE keyword >= 'new <-> york'; count ------- 4 (1 row) -SELECT COUNT(*) FROM test_tsquery WHERE keyword > 'new & york'; +SELECT COUNT(*) FROM test_tsquery WHERE keyword > 'new <-> york'; count ------- 3 @@ -2085,10 +2085,10 @@ SELECT ts_rewrite('moscow & hotel', 'SELECT keyword, sample FROM test_tsquery':: 'hotel' & ( 'moskva' | 'moscow' ) (1 row) -SELECT ts_rewrite('bar & new & qq & foo & york', 'SELECT keyword, sample FROM test_tsquery'::text ); - ts_rewrite ---------------------------------------------------------------------------------- - 'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | 'big' & 'appl' | 'new' & 'york' ) +SELECT ts_rewrite('bar & qq & foo & (new <-> york)', 'SELECT keyword, sample FROM test_tsquery'::text ); + ts_rewrite +------------------------------------------------------------------------------------- + 'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | 'big' <-> 'appl' | 'new' <-> 'york' ) (1 row) SELECT ts_rewrite( 'moscow', 'SELECT keyword, sample FROM test_tsquery'); @@ -2103,10 +2103,10 @@ SELECT ts_rewrite( 'moscow & hotel', 'SELECT keyword, sample FROM test_tsquery') 'hotel' & ( 'moskva' | 'moscow' ) (1 row) -SELECT ts_rewrite( 'bar & new & qq & foo & york', 'SELECT keyword, sample FROM test_tsquery'); - ts_rewrite ---------------------------------------------------------------------------------- - 'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | 'big' & 'appl' | 'new' & 'york' ) +SELECT ts_rewrite( 'bar & qq & foo & (new <-> york)', 'SELECT keyword, sample FROM test_tsquery'); + ts_rewrite +------------------------------------------------------------------------------------- + 'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | 'big' <-> 'appl' | 'new' <-> 'york' ) (1 row) SELECT ts_rewrite('1 & (2 <-> 3)', 'SELECT keyword, sample FROM test_tsquery'::text ); @@ -2149,9 +2149,9 @@ NOTICE: text-search query doesn't contain lexemes: "" (1 row) SELECT keyword FROM test_tsquery WHERE keyword @> 'new'; - keyword ----------------- - 'new' & 'york' + keyword +------------------ + 'new' <-> 'york' (1 row) SELECT keyword FROM test_tsquery WHERE keyword @> 'moscow'; @@ -2183,10 +2183,10 @@ SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_t 'hotel' & ( 'moskva' | 'moscow' ) (1 row) -SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'bar & new & qq & foo & york') AS query; - ts_rewrite ---------------------------------------------------------------------------------- - 'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | 'big' & 'appl' | 'new' & 'york' ) +SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'bar & qq & foo & (new <-> york)') AS query; + ts_rewrite +------------------------------------------------------------------------------------- + 'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | 'big' <-> 'appl' | 'new' <-> 'york' ) (1 row) SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'moscow') AS query; @@ -2201,18 +2201,18 @@ SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_t 'hotel' & ( 'moskva' | 'moscow' ) (1 row) -SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'bar & new & qq & foo & york') AS query; - ts_rewrite ---------------------------------------------------------------------------------- - 'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | 'big' & 'appl' | 'new' & 'york' ) +SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'bar & qq & foo & (new <-> york)') AS query; + ts_rewrite +------------------------------------------------------------------------------------- + 'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | 'big' <-> 'appl' | 'new' <-> 'york' ) (1 row) CREATE INDEX qq ON test_tsquery USING gist (keyword tsquery_ops); SET enable_seqscan=OFF; SELECT keyword FROM test_tsquery WHERE keyword @> 'new'; - keyword ----------------- - 'new' & 'york' + keyword +------------------ + 'new' <-> 'york' (1 row) SELECT keyword FROM test_tsquery WHERE keyword @> 'moscow'; @@ -2244,10 +2244,10 @@ SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_t 'hotel' & ( 'moskva' | 'moscow' ) (1 row) -SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'bar & new & qq & foo & york') AS query; - ts_rewrite ---------------------------------------------------------------------------------- - 'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | 'big' & 'appl' | 'new' & 'york' ) +SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'bar & qq & foo & (new <-> york)') AS query; + ts_rewrite +------------------------------------------------------------------------------------- + 'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | 'big' <-> 'appl' | 'new' <-> 'york' ) (1 row) SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'moscow') AS query; @@ -2262,10 +2262,10 @@ SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_t 'hotel' & ( 'moskva' | 'moscow' ) (1 row) -SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'bar & new & qq & foo & york') AS query; - ts_rewrite ---------------------------------------------------------------------------------- - 'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | 'big' & 'appl' | 'new' & 'york' ) +SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'bar & qq & foo & (new <-> york)') AS query; + ts_rewrite +------------------------------------------------------------------------------------- + 'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | 'big' <-> 'appl' | 'new' <-> 'york' ) (1 row) SELECT ts_rewrite(tsquery_phrase('foo', 'foo'), 'foo', 'bar | baz'); @@ -2456,19 +2456,19 @@ select websearch_to_tsquery('simple', 'fat:A : cat:B'); select websearch_to_tsquery('simple', 'fat*rat'); websearch_to_tsquery ---------------------- - 'fat' & 'rat' + 'fat' <-> 'rat' (1 row) select websearch_to_tsquery('simple', 'fat-rat'); - websearch_to_tsquery ---------------------------- - 'fat-rat' & 'fat' & 'rat' + websearch_to_tsquery +------------------------------- + 'fat-rat' <-> 'fat' <-> 'rat' (1 row) select websearch_to_tsquery('simple', 'fat_rat'); websearch_to_tsquery ---------------------- - 'fat' & 'rat' + 'fat' <-> 'rat' (1 row) -- weights are completely ignored @@ -2665,64 +2665,64 @@ select websearch_to_tsquery('simple', 'abc OR1234'); (1 row) select websearch_to_tsquery('simple', 'abc or-abc'); - websearch_to_tsquery ---------------------------------- - 'abc' & 'or-abc' & 'or' & 'abc' + websearch_to_tsquery +------------------------------------- + 'abc' & 'or-abc' <-> 'or' <-> 'abc' (1 row) select websearch_to_tsquery('simple', 'abc OR_abc'); - websearch_to_tsquery ----------------------- - 'abc' & 'or' & 'abc' + websearch_to_tsquery +------------------------ + 'abc' & 'or' <-> 'abc' (1 row) -- test quotes select websearch_to_tsquery('english', '"pg_class pg'); - websearch_to_tsquery ------------------------ - 'pg' & 'class' & 'pg' + websearch_to_tsquery +------------------------- + 'pg' <-> 'class' & 'pg' (1 row) select websearch_to_tsquery('english', 'pg_class pg"'); - websearch_to_tsquery ------------------------ - 'pg' & 'class' & 'pg' + websearch_to_tsquery +------------------------- + 'pg' <-> 'class' & 'pg' (1 row) select websearch_to_tsquery('english', '"pg_class pg"'); - websearch_to_tsquery ------------------------------ - ( 'pg' & 'class' ) <-> 'pg' + websearch_to_tsquery +--------------------------- + 'pg' <-> 'class' <-> 'pg' (1 row) select websearch_to_tsquery('english', 'abc "pg_class pg"'); - websearch_to_tsquery -------------------------------------- - 'abc' & ( 'pg' & 'class' ) <-> 'pg' + websearch_to_tsquery +----------------------------------- + 'abc' & 'pg' <-> 'class' <-> 'pg' (1 row) select websearch_to_tsquery('english', '"pg_class pg" def'); - websearch_to_tsquery -------------------------------------- - ( 'pg' & 'class' ) <-> 'pg' & 'def' + websearch_to_tsquery +----------------------------------- + 'pg' <-> 'class' <-> 'pg' & 'def' (1 row) select websearch_to_tsquery('english', 'abc "pg pg_class pg" def'); - websearch_to_tsquery ------------------------------------------------------- - 'abc' & 'pg' <-> ( 'pg' & 'class' ) <-> 'pg' & 'def' + websearch_to_tsquery +-------------------------------------------------------- + 'abc' & 'pg' <-> ( 'pg' <-> 'class' ) <-> 'pg' & 'def' (1 row) select websearch_to_tsquery('english', ' or "pg pg_class pg" or '); - websearch_to_tsquery --------------------------------------- - 'pg' <-> ( 'pg' & 'class' ) <-> 'pg' + websearch_to_tsquery +---------------------------------------- + 'pg' <-> ( 'pg' <-> 'class' ) <-> 'pg' (1 row) select websearch_to_tsquery('english', '""pg pg_class pg""'); - websearch_to_tsquery ------------------------------- - 'pg' & 'pg' & 'class' & 'pg' + websearch_to_tsquery +-------------------------------- + 'pg' & 'pg' <-> 'class' & 'pg' (1 row) select websearch_to_tsquery('english', 'abc """"" def'); @@ -2829,7 +2829,7 @@ NOTICE: text-search query contains only stop words or doesn't contain lexemes, select websearch_to_tsquery('''abc''''def'''); websearch_to_tsquery ---------------------- - 'abc' & 'def' + 'abc' <-> 'def' (1 row) select websearch_to_tsquery('\abc'); diff --git a/src/test/regress/sql/tsearch.sql b/src/test/regress/sql/tsearch.sql index 8a27fcd8b0b86..b02ed73f6a8c2 100644 --- a/src/test/regress/sql/tsearch.sql +++ b/src/test/regress/sql/tsearch.sql @@ -554,10 +554,10 @@ to_tsquery('english','Lorem') && phraseto_tsquery('english','ullamcorper urna'), CREATE TABLE test_tsquery (txtkeyword TEXT, txtsample TEXT); \set ECHO none \copy test_tsquery from stdin -'New York' new & york | big & apple | nyc +'New York' new <-> york | big <-> apple | nyc Moscow moskva | moscow 'Sanct Peter' Peterburg | peter | 'Sanct Peterburg' -'foo bar qq' foo & (bar | qq) & city +foo & bar & qq foo & (bar | qq) & city 1 & (2 <-> 3) 2 <-> 4 5 <-> 6 5 <-> 7 \. @@ -569,21 +569,21 @@ ALTER TABLE test_tsquery ADD COLUMN sample tsquery; UPDATE test_tsquery SET sample = to_tsquery('english', txtsample::text); -SELECT COUNT(*) FROM test_tsquery WHERE keyword < 'new & york'; -SELECT COUNT(*) FROM test_tsquery WHERE keyword <= 'new & york'; -SELECT COUNT(*) FROM test_tsquery WHERE keyword = 'new & york'; -SELECT COUNT(*) FROM test_tsquery WHERE keyword >= 'new & york'; -SELECT COUNT(*) FROM test_tsquery WHERE keyword > 'new & york'; +SELECT COUNT(*) FROM test_tsquery WHERE keyword < 'new <-> york'; +SELECT COUNT(*) FROM test_tsquery WHERE keyword <= 'new <-> york'; +SELECT COUNT(*) FROM test_tsquery WHERE keyword = 'new <-> york'; +SELECT COUNT(*) FROM test_tsquery WHERE keyword >= 'new <-> york'; +SELECT COUNT(*) FROM test_tsquery WHERE keyword > 'new <-> york'; CREATE UNIQUE INDEX bt_tsq ON test_tsquery (keyword); SET enable_seqscan=OFF; -SELECT COUNT(*) FROM test_tsquery WHERE keyword < 'new & york'; -SELECT COUNT(*) FROM test_tsquery WHERE keyword <= 'new & york'; -SELECT COUNT(*) FROM test_tsquery WHERE keyword = 'new & york'; -SELECT COUNT(*) FROM test_tsquery WHERE keyword >= 'new & york'; -SELECT COUNT(*) FROM test_tsquery WHERE keyword > 'new & york'; +SELECT COUNT(*) FROM test_tsquery WHERE keyword < 'new <-> york'; +SELECT COUNT(*) FROM test_tsquery WHERE keyword <= 'new <-> york'; +SELECT COUNT(*) FROM test_tsquery WHERE keyword = 'new <-> york'; +SELECT COUNT(*) FROM test_tsquery WHERE keyword >= 'new <-> york'; +SELECT COUNT(*) FROM test_tsquery WHERE keyword > 'new <-> york'; RESET enable_seqscan; @@ -593,11 +593,11 @@ SELECT ts_rewrite(ts_rewrite('new & !york ', 'york', '!jersey'), SELECT ts_rewrite('moscow', 'SELECT keyword, sample FROM test_tsquery'::text ); SELECT ts_rewrite('moscow & hotel', 'SELECT keyword, sample FROM test_tsquery'::text ); -SELECT ts_rewrite('bar & new & qq & foo & york', 'SELECT keyword, sample FROM test_tsquery'::text ); +SELECT ts_rewrite('bar & qq & foo & (new <-> york)', 'SELECT keyword, sample FROM test_tsquery'::text ); SELECT ts_rewrite( 'moscow', 'SELECT keyword, sample FROM test_tsquery'); SELECT ts_rewrite( 'moscow & hotel', 'SELECT keyword, sample FROM test_tsquery'); -SELECT ts_rewrite( 'bar & new & qq & foo & york', 'SELECT keyword, sample FROM test_tsquery'); +SELECT ts_rewrite( 'bar & qq & foo & (new <-> york)', 'SELECT keyword, sample FROM test_tsquery'); SELECT ts_rewrite('1 & (2 <-> 3)', 'SELECT keyword, sample FROM test_tsquery'::text ); SELECT ts_rewrite('1 & (2 <2> 3)', 'SELECT keyword, sample FROM test_tsquery'::text ); @@ -614,10 +614,10 @@ SELECT keyword FROM test_tsquery WHERE keyword <@ 'new'; SELECT keyword FROM test_tsquery WHERE keyword <@ 'moscow'; SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'moscow') AS query; SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'moscow & hotel') AS query; -SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'bar & new & qq & foo & york') AS query; +SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'bar & qq & foo & (new <-> york)') AS query; SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'moscow') AS query; SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'moscow & hotel') AS query; -SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'bar & new & qq & foo & york') AS query; +SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'bar & qq & foo & (new <-> york)') AS query; CREATE INDEX qq ON test_tsquery USING gist (keyword tsquery_ops); SET enable_seqscan=OFF; @@ -628,10 +628,10 @@ SELECT keyword FROM test_tsquery WHERE keyword <@ 'new'; SELECT keyword FROM test_tsquery WHERE keyword <@ 'moscow'; SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'moscow') AS query; SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'moscow & hotel') AS query; -SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'bar & new & qq & foo & york') AS query; +SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'bar & qq & foo & (new <-> york)') AS query; SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'moscow') AS query; SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'moscow & hotel') AS query; -SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'bar & new & qq & foo & york') AS query; +SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'bar & qq & foo & (new <-> york)') AS query; SELECT ts_rewrite(tsquery_phrase('foo', 'foo'), 'foo', 'bar | baz'); SELECT to_tsvector('foo bar') @@ From dc43492e46c7145a476cb8ca6200fc8eefe673ef Mon Sep 17 00:00:00 2001 From: Peter Geoghegan Date: Sun, 31 Jan 2021 10:10:55 -0800 Subject: [PATCH 219/240] Remove unused _bt_delitems_delete() argument. The latestRemovedXid values used by nbtree deletion operations are determined by _bt_delitems_delete()'s caller, so there is no reason to pass a separate heapRel argument. Oversight in commit d168b666823. --- src/backend/access/nbtree/nbtpage.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c index e230f912c28dc..41dc3f8fdff6c 100644 --- a/src/backend/access/nbtree/nbtpage.c +++ b/src/backend/access/nbtree/nbtpage.c @@ -41,8 +41,7 @@ static void _bt_log_reuse_page(Relation rel, BlockNumber blkno, static void _bt_delitems_delete(Relation rel, Buffer buf, TransactionId latestRemovedXid, OffsetNumber *deletable, int ndeletable, - BTVacuumPosting *updatable, int nupdatable, - Relation heapRel); + BTVacuumPosting *updatable, int nupdatable); static char *_bt_delitems_update(BTVacuumPosting *updatable, int nupdatable, OffsetNumber *updatedoffsets, Size *updatedbuflen, bool needswal); @@ -1260,8 +1259,7 @@ _bt_delitems_vacuum(Relation rel, Buffer buf, static void _bt_delitems_delete(Relation rel, Buffer buf, TransactionId latestRemovedXid, OffsetNumber *deletable, int ndeletable, - BTVacuumPosting *updatable, int nupdatable, - Relation heapRel) + BTVacuumPosting *updatable, int nupdatable) { Page page = BufferGetPage(buf); BTPageOpaque opaque; @@ -1650,7 +1648,7 @@ _bt_delitems_delete_check(Relation rel, Buffer buf, Relation heapRel, /* Physically delete tuples (or TIDs) using deletable (or updatable) */ _bt_delitems_delete(rel, buf, latestRemovedXid, deletable, ndeletable, - updatable, nupdatable, heapRel); + updatable, nupdatable); /* be tidy */ for (int i = 0; i < nupdatable; i++) From 676887a3b0b8e3c0348ac3f82ab0d16e9a24bd43 Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Sun, 31 Jan 2021 23:50:40 +0300 Subject: [PATCH 220/240] Implementation of subscripting for jsonb Subscripting for jsonb does not support slices, does not have a limit for the number of subscripts, and an assignment expects a replace value to have jsonb type. There is also one functional difference between assignment via subscripting and assignment via jsonb_set(). When an original jsonb container is NULL, the subscripting replaces it with an empty jsonb and proceeds with an assignment. For the sake of code reuse, we rearrange some parts of jsonb functionality to allow the usage of the same functions for jsonb_set and assign subscripting operation. The original idea belongs to Oleg Bartunov. Catversion is bumped. Discussion: https://postgr.es/m/CA%2Bq6zcV8qvGcDXurwwgUbwACV86Th7G80pnubg42e-p9gsSf%3Dg%40mail.gmail.com Discussion: https://postgr.es/m/CA%2Bq6zcX3mdxGCgdThzuySwH-ApyHHM-G4oB1R0fn0j2hZqqkLQ%40mail.gmail.com Discussion: https://postgr.es/m/CA%2Bq6zcVDuGBv%3DM0FqBYX8DPebS3F_0KQ6OVFobGJPM507_SZ_w%40mail.gmail.com Discussion: https://postgr.es/m/CA%2Bq6zcVovR%2BXY4mfk-7oNk-rF91gH0PebnNfuUjuuDsyHjOcVA%40mail.gmail.com Author: Dmitry Dolgov Reviewed-by: Tom Lane, Arthur Zakirov, Pavel Stehule, Dian M Fay Reviewed-by: Andrew Dunstan, Chapman Flack, Merlin Moncure, Peter Geoghegan Reviewed-by: Alvaro Herrera, Jim Nasby, Josh Berkus, Victor Wagner Reviewed-by: Aleksander Alekseev, Robert Haas, Oleg Bartunov --- doc/src/sgml/json.sgml | 51 ++++ src/backend/utils/adt/Makefile | 1 + src/backend/utils/adt/jsonb_util.c | 72 ++++- src/backend/utils/adt/jsonbsubs.c | 412 ++++++++++++++++++++++++++++ src/backend/utils/adt/jsonfuncs.c | 188 ++++++------- src/include/catalog/catversion.h | 2 +- src/include/catalog/pg_proc.dat | 4 + src/include/catalog/pg_type.dat | 3 +- src/include/utils/jsonb.h | 6 +- src/test/regress/expected/jsonb.out | 272 +++++++++++++++++- src/test/regress/sql/jsonb.sql | 84 +++++- src/tools/pgindent/typedefs.list | 1 + 12 files changed, 988 insertions(+), 108 deletions(-) create mode 100644 src/backend/utils/adt/jsonbsubs.c diff --git a/doc/src/sgml/json.sgml b/doc/src/sgml/json.sgml index 5b9a5557a40fd..3ace5e444b080 100644 --- a/doc/src/sgml/json.sgml +++ b/doc/src/sgml/json.sgml @@ -602,6 +602,57 @@ SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @> '{"tags": ["qu + + <type>jsonb</type> Subscripting + + The jsonb data type supports array-style subscripting expressions + to extract and modify elements. Nested values can be indicated by chaining + subscripting expressions, following the same rules as the path + argument in the jsonb_set function. If a jsonb + value is an array, numeric subscripts start at zero, and negative integers count + backwards from the last element of the array. Slice expressions are not supported. + The result of a subscripting expression is always of the jsonb data type. + + + + An example of subscripting syntax: + + +-- Extract object value by key +SELECT ('{"a": 1}'::jsonb)['a']; + +-- Extract nested object value by key path +SELECT ('{"a": {"b": {"c": 1}}}'::jsonb)['a']['b']['c']; + +-- Extract array element by index +SELECT ('[1, "2", null]'::jsonb)[1]; + +-- Update object value by key. Note the quotes around '1': the assigned +-- value must be of the jsonb type as well +UPDATE table_name SET jsonb_field['key'] = '1'; + +-- Filter records using a WHERE clause with subscripting. Since the result of +-- subscripting is jsonb, the value we compare it against must also be jsonb. +-- The double quotes make "value" also a valid jsonb string. +SELECT * FROM table_name WHERE jsonb_field['key'] = '"value"'; + + + jsonb assignment via subscripting handles a few edge cases + differently from jsonb_set. When a source jsonb + is NULL, assignment via subscripting will proceed as if + it was an empty JSON object: + + +-- Where jsonb_field was NULL, it is now {"a": 1} +UPDATE table_name SET jsonb_field['a'] = '1'; + +-- Where jsonb_field was NULL, it is now [1] +UPDATE table_name SET jsonb_field[0] = '1'; + + + + + Transforms diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile index 82732146d3deb..279ff15ade925 100644 --- a/src/backend/utils/adt/Makefile +++ b/src/backend/utils/adt/Makefile @@ -50,6 +50,7 @@ OBJS = \ jsonb_op.o \ jsonb_util.o \ jsonfuncs.o \ + jsonbsubs.o \ jsonpath.o \ jsonpath_exec.o \ jsonpath_gram.o \ diff --git a/src/backend/utils/adt/jsonb_util.c b/src/backend/utils/adt/jsonb_util.c index 0ce66411ae139..571118779590d 100644 --- a/src/backend/utils/adt/jsonb_util.c +++ b/src/backend/utils/adt/jsonb_util.c @@ -68,18 +68,25 @@ static JsonbValue *pushJsonbValueScalar(JsonbParseState **pstate, JsonbIteratorToken seq, JsonbValue *scalarVal); +void +JsonbToJsonbValue(Jsonb *jsonb, JsonbValue *val) +{ + val->type = jbvBinary; + val->val.binary.data = &jsonb->root; + val->val.binary.len = VARSIZE(jsonb) - VARHDRSZ; +} + /* * Turn an in-memory JsonbValue into a Jsonb for on-disk storage. * - * There isn't a JsonbToJsonbValue(), because generally we find it more - * convenient to directly iterate through the Jsonb representation and only - * really convert nested scalar values. JsonbIteratorNext() does this, so that - * clients of the iteration code don't have to directly deal with the binary - * representation (JsonbDeepContains() is a notable exception, although all - * exceptions are internal to this module). In general, functions that accept - * a JsonbValue argument are concerned with the manipulation of scalar values, - * or simple containers of scalar values, where it would be inconvenient to - * deal with a great amount of other state. + * Generally we find it more convenient to directly iterate through the Jsonb + * representation and only really convert nested scalar values. + * JsonbIteratorNext() does this, so that clients of the iteration code don't + * have to directly deal with the binary representation (JsonbDeepContains() is + * a notable exception, although all exceptions are internal to this module). + * In general, functions that accept a JsonbValue argument are concerned with + * the manipulation of scalar values, or simple containers of scalar values, + * where it would be inconvenient to deal with a great amount of other state. */ Jsonb * JsonbValueToJsonb(JsonbValue *val) @@ -563,6 +570,30 @@ pushJsonbValue(JsonbParseState **pstate, JsonbIteratorToken seq, JsonbValue *res = NULL; JsonbValue v; JsonbIteratorToken tok; + int i; + + if (jbval && (seq == WJB_ELEM || seq == WJB_VALUE) && jbval->type == jbvObject) + { + pushJsonbValue(pstate, WJB_BEGIN_OBJECT, NULL); + for (i = 0; i < jbval->val.object.nPairs; i++) + { + pushJsonbValue(pstate, WJB_KEY, &jbval->val.object.pairs[i].key); + pushJsonbValue(pstate, WJB_VALUE, &jbval->val.object.pairs[i].value); + } + + return pushJsonbValue(pstate, WJB_END_OBJECT, NULL); + } + + if (jbval && (seq == WJB_ELEM || seq == WJB_VALUE) && jbval->type == jbvArray) + { + pushJsonbValue(pstate, WJB_BEGIN_ARRAY, NULL); + for (i = 0; i < jbval->val.array.nElems; i++) + { + pushJsonbValue(pstate, WJB_ELEM, &jbval->val.array.elems[i]); + } + + return pushJsonbValue(pstate, WJB_END_ARRAY, NULL); + } if (!jbval || (seq != WJB_ELEM && seq != WJB_VALUE) || jbval->type != jbvBinary) @@ -573,9 +604,30 @@ pushJsonbValue(JsonbParseState **pstate, JsonbIteratorToken seq, /* unpack the binary and add each piece to the pstate */ it = JsonbIteratorInit(jbval->val.binary.data); + + if ((jbval->val.binary.data->header & JB_FSCALAR) && *pstate) + { + tok = JsonbIteratorNext(&it, &v, true); + Assert(tok == WJB_BEGIN_ARRAY); + Assert(v.type == jbvArray && v.val.array.rawScalar); + + tok = JsonbIteratorNext(&it, &v, true); + Assert(tok == WJB_ELEM); + + res = pushJsonbValueScalar(pstate, seq, &v); + + tok = JsonbIteratorNext(&it, &v, true); + Assert(tok == WJB_END_ARRAY); + Assert(it == NULL); + + return res; + } + while ((tok = JsonbIteratorNext(&it, &v, false)) != WJB_DONE) res = pushJsonbValueScalar(pstate, tok, - tok < WJB_BEGIN_ARRAY ? &v : NULL); + tok < WJB_BEGIN_ARRAY || + (tok == WJB_BEGIN_ARRAY && + v.val.array.rawScalar) ? &v : NULL); return res; } diff --git a/src/backend/utils/adt/jsonbsubs.c b/src/backend/utils/adt/jsonbsubs.c new file mode 100644 index 0000000000000..491e27cc04bd0 --- /dev/null +++ b/src/backend/utils/adt/jsonbsubs.c @@ -0,0 +1,412 @@ +/*------------------------------------------------------------------------- + * + * jsonbsubs.c + * Subscripting support functions for jsonb. + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/utils/adt/jsonbsubs.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "executor/execExpr.h" +#include "nodes/makefuncs.h" +#include "nodes/nodeFuncs.h" +#include "nodes/subscripting.h" +#include "parser/parse_coerce.h" +#include "parser/parse_expr.h" +#include "utils/jsonb.h" +#include "utils/jsonfuncs.h" +#include "utils/builtins.h" +#include "utils/lsyscache.h" + + +/* SubscriptingRefState.workspace for jsonb subscripting execution */ +typedef struct JsonbSubWorkspace +{ + bool expectArray; /* jsonb root is expected to be an array */ + Oid *indexOid; /* OID of coerced subscript expression, could + * be only integer or text */ + Datum *index; /* Subscript values in Datum format */ +} JsonbSubWorkspace; + + +/* + * Finish parse analysis of a SubscriptingRef expression for a jsonb. + * + * Transform the subscript expressions, coerce them to text, + * and determine the result type of the SubscriptingRef node. + */ +static void +jsonb_subscript_transform(SubscriptingRef *sbsref, + List *indirection, + ParseState *pstate, + bool isSlice, + bool isAssignment) +{ + List *upperIndexpr = NIL; + ListCell *idx; + + /* + * Transform and convert the subscript expressions. Jsonb subscripting + * does not support slices, look only and the upper index. + */ + foreach(idx, indirection) + { + A_Indices *ai = lfirst_node(A_Indices, idx); + Node *subExpr; + + if (isSlice) + { + Node *expr = ai->uidx ? ai->uidx : ai->lidx; + + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("jsonb subscript does not support slices"), + parser_errposition(pstate, exprLocation(expr)))); + } + + if (ai->uidx) + { + Oid subExprType = InvalidOid, + targetType = UNKNOWNOID; + + subExpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind); + subExprType = exprType(subExpr); + + if (subExprType != UNKNOWNOID) + { + Oid targets[2] = {INT4OID, TEXTOID}; + + /* + * Jsonb can handle multiple subscript types, but cases when a + * subscript could be coerced to multiple target types must be + * avoided, similar to overloaded functions. It could be + * possibly extend with jsonpath in the future. + */ + for (int i = 0; i < 2; i++) + { + if (can_coerce_type(1, &subExprType, &targets[i], COERCION_IMPLICIT)) + { + /* + * One type has already succeeded, it means there are + * two coercion targets possible, failure. + */ + if (targetType != UNKNOWNOID) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("subscript type is not supported"), + errhint("Jsonb subscript must be coerced " + "only to one type, integer or text."), + parser_errposition(pstate, exprLocation(subExpr)))); + + targetType = targets[i]; + } + } + + /* + * No suitable types were found, failure. + */ + if (targetType == UNKNOWNOID) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("subscript type is not supported"), + errhint("Jsonb subscript must be coerced to either integer or text"), + parser_errposition(pstate, exprLocation(subExpr)))); + } + else + targetType = TEXTOID; + + /* + * We known from can_coerce_type that coercion will succeed, so + * coerce_type could be used. Note the implicit coercion context, + * which is required to handle subscripts of different types, + * similar to overloaded functions. + */ + subExpr = coerce_type(pstate, + subExpr, subExprType, + targetType, -1, + COERCION_IMPLICIT, + COERCE_IMPLICIT_CAST, + -1); + if (subExpr == NULL) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("jsonb subscript must have text type"), + parser_errposition(pstate, exprLocation(subExpr)))); + } + else + { + /* + * Slice with omitted upper bound. Should not happen as we already + * errored out on slice earlier, but handle this just in case. + */ + Assert(isSlice && ai->is_slice); + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("jsonb subscript does not support slices"), + parser_errposition(pstate, exprLocation(ai->uidx)))); + } + + upperIndexpr = lappend(upperIndexpr, subExpr); + } + + /* store the transformed lists into the SubscriptRef node */ + sbsref->refupperindexpr = upperIndexpr; + sbsref->reflowerindexpr = NIL; + + /* Determine the result type of the subscripting operation; always jsonb */ + sbsref->refrestype = JSONBOID; + sbsref->reftypmod = -1; +} + +/* + * During execution, process the subscripts in a SubscriptingRef expression. + * + * The subscript expressions are already evaluated in Datum form in the + * SubscriptingRefState's arrays. Check and convert them as necessary. + * + * If any subscript is NULL, we throw error in assignment cases, or in fetch + * cases set result to NULL and return false (instructing caller to skip the + * rest of the SubscriptingRef sequence). + */ +static bool +jsonb_subscript_check_subscripts(ExprState *state, + ExprEvalStep *op, + ExprContext *econtext) +{ + SubscriptingRefState *sbsrefstate = op->d.sbsref_subscript.state; + JsonbSubWorkspace *workspace = (JsonbSubWorkspace *) sbsrefstate->workspace; + + /* + * In case if the first subscript is an integer, the source jsonb is + * expected to be an array. This information is not used directly, all + * such cases are handled within corresponding jsonb assign functions. But + * if the source jsonb is NULL the expected type will be used to construct + * an empty source. + */ + if (sbsrefstate->numupper > 0 && sbsrefstate->upperprovided[0] && + !sbsrefstate->upperindexnull[0] && workspace->indexOid[0] == INT4OID) + workspace->expectArray = true; + + /* Process upper subscripts */ + for (int i = 0; i < sbsrefstate->numupper; i++) + { + if (sbsrefstate->upperprovided[i]) + { + /* If any index expr yields NULL, result is NULL or error */ + if (sbsrefstate->upperindexnull[i]) + { + if (sbsrefstate->isassignment) + ereport(ERROR, + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("jsonb subscript in assignment must not be null"))); + *op->resnull = true; + return false; + } + + /* + * For jsonb fetch and assign functions we need to provide path in + * text format. Convert if it's not already text. + */ + if (workspace->indexOid[i] == INT4OID) + { + Datum datum = sbsrefstate->upperindex[i]; + char *cs = DatumGetCString(DirectFunctionCall1(int4out, datum)); + + workspace->index[i] = CStringGetTextDatum(cs); + } + else + workspace->index[i] = sbsrefstate->upperindex[i]; + } + } + + return true; +} + +/* + * Evaluate SubscriptingRef fetch for a jsonb element. + * + * Source container is in step's result variable (it's known not NULL, since + * we set fetch_strict to true). + */ +static void +jsonb_subscript_fetch(ExprState *state, + ExprEvalStep *op, + ExprContext *econtext) +{ + SubscriptingRefState *sbsrefstate = op->d.sbsref.state; + JsonbSubWorkspace *workspace = (JsonbSubWorkspace *) sbsrefstate->workspace; + Jsonb *jsonbSource; + + /* Should not get here if source jsonb (or any subscript) is null */ + Assert(!(*op->resnull)); + + jsonbSource = DatumGetJsonbP(*op->resvalue); + *op->resvalue = jsonb_get_element(jsonbSource, + workspace->index, + sbsrefstate->numupper, + op->resnull, + false); +} + +/* + * Evaluate SubscriptingRef assignment for a jsonb element assignment. + * + * Input container (possibly null) is in result area, replacement value is in + * SubscriptingRefState's replacevalue/replacenull. + */ +static void +jsonb_subscript_assign(ExprState *state, + ExprEvalStep *op, + ExprContext *econtext) +{ + SubscriptingRefState *sbsrefstate = op->d.sbsref.state; + JsonbSubWorkspace *workspace = (JsonbSubWorkspace *) sbsrefstate->workspace; + Jsonb *jsonbSource; + JsonbValue replacevalue; + + if (sbsrefstate->replacenull) + replacevalue.type = jbvNull; + else + JsonbToJsonbValue(DatumGetJsonbP(sbsrefstate->replacevalue), + &replacevalue); + + /* + * In case if the input container is null, set up an empty jsonb and + * proceed with the assignment. + */ + if (*op->resnull) + { + JsonbValue *newSource = (JsonbValue *) palloc(sizeof(JsonbValue)); + + /* + * To avoid any surprising results, set up an empty jsonb array in + * case of an array is expected (i.e. the first subscript is integer), + * otherwise jsonb object. + */ + if (workspace->expectArray) + { + newSource->type = jbvArray; + newSource->val.array.nElems = 0; + newSource->val.array.rawScalar = false; + } + else + { + newSource->type = jbvObject; + newSource->val.object.nPairs = 0; + } + + jsonbSource = JsonbValueToJsonb(newSource); + *op->resnull = false; + } + else + jsonbSource = DatumGetJsonbP(*op->resvalue); + + *op->resvalue = jsonb_set_element(jsonbSource, + workspace->index, + sbsrefstate->numupper, + &replacevalue); + /* The result is never NULL, so no need to change *op->resnull */ +} + +/* + * Compute old jsonb element value for a SubscriptingRef assignment + * expression. Will only be called if the new-value subexpression + * contains SubscriptingRef or FieldStore. This is the same as the + * regular fetch case, except that we have to handle a null jsonb, + * and the value should be stored into the SubscriptingRefState's + * prevvalue/prevnull fields. + */ +static void +jsonb_subscript_fetch_old(ExprState *state, + ExprEvalStep *op, + ExprContext *econtext) +{ + SubscriptingRefState *sbsrefstate = op->d.sbsref.state; + + if (*op->resnull) + { + /* whole jsonb is null, so any element is too */ + sbsrefstate->prevvalue = (Datum) 0; + sbsrefstate->prevnull = true; + } + else + { + Jsonb *jsonbSource = DatumGetJsonbP(*op->resvalue); + + sbsrefstate->prevvalue = jsonb_get_element(jsonbSource, + sbsrefstate->upperindex, + sbsrefstate->numupper, + &sbsrefstate->prevnull, + false); + } +} + +/* + * Set up execution state for a jsonb subscript operation. Opposite to the + * arrays subscription, there is no limit for number of subscripts as jsonb + * type itself doesn't have nesting limits. + */ +static void +jsonb_exec_setup(const SubscriptingRef *sbsref, + SubscriptingRefState *sbsrefstate, + SubscriptExecSteps * methods) +{ + JsonbSubWorkspace *workspace; + ListCell *lc; + int nupper = sbsref->refupperindexpr->length; + char *ptr; + + /* Allocate type-specific workspace with space for per-subscript data */ + workspace = palloc0(MAXALIGN(sizeof(JsonbSubWorkspace)) + + nupper * (sizeof(Datum) + sizeof(Oid))); + workspace->expectArray = false; + ptr = ((char *) workspace) + MAXALIGN(sizeof(JsonbSubWorkspace)); + workspace->indexOid = (Oid *) ptr; + ptr += nupper * sizeof(Oid); + workspace->index = (Datum *) ptr; + + sbsrefstate->workspace = workspace; + + /* Collect subscript data types necessary at execution time */ + foreach(lc, sbsref->refupperindexpr) + { + Node *expr = lfirst(lc); + int i = foreach_current_index(lc); + + workspace->indexOid[i] = exprType(expr); + } + + /* + * Pass back pointers to appropriate step execution functions. + */ + methods->sbs_check_subscripts = jsonb_subscript_check_subscripts; + methods->sbs_fetch = jsonb_subscript_fetch; + methods->sbs_assign = jsonb_subscript_assign; + methods->sbs_fetch_old = jsonb_subscript_fetch_old; +} + +/* + * jsonb_subscript_handler + * Subscripting handler for jsonb. + * + */ +Datum +jsonb_subscript_handler(PG_FUNCTION_ARGS) +{ + static const SubscriptRoutines sbsroutines = { + .transform = jsonb_subscript_transform, + .exec_setup = jsonb_exec_setup, + .fetch_strict = true, /* fetch returns NULL for NULL inputs */ + .fetch_leakproof = true, /* fetch returns NULL for bad subscript */ + .store_leakproof = false /* ... but assignment throws error */ + }; + + PG_RETURN_POINTER(&sbsroutines); +} diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c index a794a7df84fb1..076cde09022f3 100644 --- a/src/backend/utils/adt/jsonfuncs.c +++ b/src/backend/utils/adt/jsonfuncs.c @@ -463,16 +463,16 @@ static JsonbValue *IteratorConcat(JsonbIterator **it1, JsonbIterator **it2, JsonbParseState **state); static JsonbValue *setPath(JsonbIterator **it, Datum *path_elems, bool *path_nulls, int path_len, - JsonbParseState **st, int level, Jsonb *newval, + JsonbParseState **st, int level, JsonbValue *newval, int op_type); static void setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls, int path_len, JsonbParseState **st, int level, - Jsonb *newval, uint32 npairs, int op_type); + JsonbValue *newval, uint32 npairs, int op_type); static void setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls, int path_len, JsonbParseState **st, - int level, Jsonb *newval, uint32 nelems, int op_type); -static void addJsonbToParseState(JsonbParseState **jbps, Jsonb *jb); + int level, + JsonbValue *newval, uint32 nelems, int op_type); /* function supporting iterate_json_values */ static void iterate_values_scalar(void *state, char *token, JsonTokenType tokentype); @@ -1448,13 +1448,9 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text) ArrayType *path = PG_GETARG_ARRAYTYPE_P(1); Datum *pathtext; bool *pathnulls; + bool isnull; int npath; - int i; - bool have_object = false, - have_array = false; - JsonbValue *jbvp = NULL; - JsonbValue jbvbuf; - JsonbContainer *container; + Datum res; /* * If the array contains any null elements, return NULL, on the grounds @@ -1469,9 +1465,26 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text) deconstruct_array(path, TEXTOID, -1, false, TYPALIGN_INT, &pathtext, &pathnulls, &npath); - /* Identify whether we have object, array, or scalar at top-level */ - container = &jb->root; + res = jsonb_get_element(jb, pathtext, npath, &isnull, as_text); + + if (isnull) + PG_RETURN_NULL(); + else + PG_RETURN_DATUM(res); +} + +Datum +jsonb_get_element(Jsonb *jb, Datum *path, int npath, bool *isnull, bool as_text) +{ + JsonbContainer *container = &jb->root; + JsonbValue *jbvp = NULL; + int i; + bool have_object = false, + have_array = false; + *isnull = false; + + /* Identify whether we have object, array, or scalar at top-level */ if (JB_ROOT_IS_OBJECT(jb)) have_object = true; else if (JB_ROOT_IS_ARRAY(jb) && !JB_ROOT_IS_SCALAR(jb)) @@ -1496,9 +1509,9 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text) { if (as_text) { - PG_RETURN_TEXT_P(cstring_to_text(JsonbToCString(NULL, - container, - VARSIZE(jb)))); + return PointerGetDatum(cstring_to_text(JsonbToCString(NULL, + container, + VARSIZE(jb)))); } else { @@ -1512,22 +1525,25 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text) if (have_object) { jbvp = getKeyJsonValueFromContainer(container, - VARDATA(pathtext[i]), - VARSIZE(pathtext[i]) - VARHDRSZ, - &jbvbuf); + VARDATA(path[i]), + VARSIZE(path[i]) - VARHDRSZ, + NULL); } else if (have_array) { long lindex; uint32 index; - char *indextext = TextDatumGetCString(pathtext[i]); + char *indextext = TextDatumGetCString(path[i]); char *endptr; errno = 0; lindex = strtol(indextext, &endptr, 10); if (endptr == indextext || *endptr != '\0' || errno != 0 || lindex > INT_MAX || lindex < INT_MIN) - PG_RETURN_NULL(); + { + *isnull = true; + return PointerGetDatum(NULL); + } if (lindex >= 0) { @@ -1545,7 +1561,10 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text) nelements = JsonContainerSize(container); if (-lindex > nelements) - PG_RETURN_NULL(); + { + *isnull = true; + return PointerGetDatum(NULL); + } else index = nelements + lindex; } @@ -1555,11 +1574,15 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text) else { /* scalar, extraction yields a null */ - PG_RETURN_NULL(); + *isnull = true; + return PointerGetDatum(NULL); } if (jbvp == NULL) - PG_RETURN_NULL(); + { + *isnull = true; + return PointerGetDatum(NULL); + } else if (i == npath - 1) break; @@ -1581,9 +1604,12 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text) if (as_text) { if (jbvp->type == jbvNull) - PG_RETURN_NULL(); + { + *isnull = true; + return PointerGetDatum(NULL); + } - PG_RETURN_TEXT_P(JsonbValueAsText(jbvp)); + return PointerGetDatum(JsonbValueAsText(jbvp)); } else { @@ -1594,6 +1620,28 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text) } } +Datum +jsonb_set_element(Jsonb *jb, Datum *path, int path_len, + JsonbValue *newval) +{ + JsonbValue *res; + JsonbParseState *state = NULL; + JsonbIterator *it; + bool *path_nulls = palloc0(path_len * sizeof(bool)); + + if (newval->type == jbvArray && newval->val.array.rawScalar) + *newval = newval->val.array.elems[0]; + + it = JsonbIteratorInit(&jb->root); + + res = setPath(&it, path, path_nulls, path_len, &state, 0, + newval, JB_PATH_CREATE); + + pfree(path_nulls); + + PG_RETURN_JSONB_P(JsonbValueToJsonb(res)); +} + /* * Return the text representation of the given JsonbValue. */ @@ -4151,58 +4199,6 @@ jsonb_strip_nulls(PG_FUNCTION_ARGS) PG_RETURN_POINTER(JsonbValueToJsonb(res)); } -/* - * Add values from the jsonb to the parse state. - * - * If the parse state container is an object, the jsonb is pushed as - * a value, not a key. - * - * This needs to be done using an iterator because pushJsonbValue doesn't - * like getting jbvBinary values, so we can't just push jb as a whole. - */ -static void -addJsonbToParseState(JsonbParseState **jbps, Jsonb *jb) -{ - JsonbIterator *it; - JsonbValue *o = &(*jbps)->contVal; - JsonbValue v; - JsonbIteratorToken type; - - it = JsonbIteratorInit(&jb->root); - - Assert(o->type == jbvArray || o->type == jbvObject); - - if (JB_ROOT_IS_SCALAR(jb)) - { - (void) JsonbIteratorNext(&it, &v, false); /* skip array header */ - Assert(v.type == jbvArray); - (void) JsonbIteratorNext(&it, &v, false); /* fetch scalar value */ - - switch (o->type) - { - case jbvArray: - (void) pushJsonbValue(jbps, WJB_ELEM, &v); - break; - case jbvObject: - (void) pushJsonbValue(jbps, WJB_VALUE, &v); - break; - default: - elog(ERROR, "unexpected parent of nested structure"); - } - } - else - { - while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE) - { - if (type == WJB_KEY || type == WJB_VALUE || type == WJB_ELEM) - (void) pushJsonbValue(jbps, type, &v); - else - (void) pushJsonbValue(jbps, type, NULL); - } - } - -} - /* * SQL function jsonb_pretty (jsonb) * @@ -4474,7 +4470,8 @@ jsonb_set(PG_FUNCTION_ARGS) { Jsonb *in = PG_GETARG_JSONB_P(0); ArrayType *path = PG_GETARG_ARRAYTYPE_P(1); - Jsonb *newval = PG_GETARG_JSONB_P(2); + Jsonb *newjsonb = PG_GETARG_JSONB_P(2); + JsonbValue newval; bool create = PG_GETARG_BOOL(3); JsonbValue *res = NULL; Datum *path_elems; @@ -4483,6 +4480,8 @@ jsonb_set(PG_FUNCTION_ARGS) JsonbIterator *it; JsonbParseState *st = NULL; + JsonbToJsonbValue(newjsonb, &newval); + if (ARR_NDIM(path) > 1) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), @@ -4505,7 +4504,7 @@ jsonb_set(PG_FUNCTION_ARGS) it = JsonbIteratorInit(&in->root); res = setPath(&it, path_elems, path_nulls, path_len, &st, - 0, newval, create ? JB_PATH_CREATE : JB_PATH_REPLACE); + 0, &newval, create ? JB_PATH_CREATE : JB_PATH_REPLACE); Assert(res != NULL); @@ -4632,7 +4631,8 @@ jsonb_insert(PG_FUNCTION_ARGS) { Jsonb *in = PG_GETARG_JSONB_P(0); ArrayType *path = PG_GETARG_ARRAYTYPE_P(1); - Jsonb *newval = PG_GETARG_JSONB_P(2); + Jsonb *newjsonb = PG_GETARG_JSONB_P(2); + JsonbValue newval; bool after = PG_GETARG_BOOL(3); JsonbValue *res = NULL; Datum *path_elems; @@ -4641,6 +4641,8 @@ jsonb_insert(PG_FUNCTION_ARGS) JsonbIterator *it; JsonbParseState *st = NULL; + JsonbToJsonbValue(newjsonb, &newval); + if (ARR_NDIM(path) > 1) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), @@ -4659,7 +4661,7 @@ jsonb_insert(PG_FUNCTION_ARGS) it = JsonbIteratorInit(&in->root); - res = setPath(&it, path_elems, path_nulls, path_len, &st, 0, newval, + res = setPath(&it, path_elems, path_nulls, path_len, &st, 0, &newval, after ? JB_PATH_INSERT_AFTER : JB_PATH_INSERT_BEFORE); Assert(res != NULL); @@ -4790,7 +4792,7 @@ IteratorConcat(JsonbIterator **it1, JsonbIterator **it2, static JsonbValue * setPath(JsonbIterator **it, Datum *path_elems, bool *path_nulls, int path_len, - JsonbParseState **st, int level, Jsonb *newval, int op_type) + JsonbParseState **st, int level, JsonbValue *newval, int op_type) { JsonbValue v; JsonbIteratorToken r; @@ -4843,11 +4845,11 @@ setPath(JsonbIterator **it, Datum *path_elems, static void setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls, int path_len, JsonbParseState **st, int level, - Jsonb *newval, uint32 npairs, int op_type) + JsonbValue *newval, uint32 npairs, int op_type) { - JsonbValue v; int i; - JsonbValue k; + JsonbValue k, + v; bool done = false; if (level >= path_len || path_nulls[level]) @@ -4864,7 +4866,7 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls, newkey.val.string.val = VARDATA_ANY(path_elems[level]); (void) pushJsonbValue(st, WJB_KEY, &newkey); - addJsonbToParseState(st, newval); + (void) pushJsonbValue(st, WJB_VALUE, newval); } for (i = 0; i < npairs; i++) @@ -4895,7 +4897,7 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls, if (!(op_type & JB_PATH_DELETE)) { (void) pushJsonbValue(st, WJB_KEY, &k); - addJsonbToParseState(st, newval); + (void) pushJsonbValue(st, WJB_VALUE, newval); } done = true; } @@ -4918,7 +4920,7 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls, newkey.val.string.val = VARDATA_ANY(path_elems[level]); (void) pushJsonbValue(st, WJB_KEY, &newkey); - addJsonbToParseState(st, newval); + (void) pushJsonbValue(st, WJB_VALUE, newval); } (void) pushJsonbValue(st, r, &k); @@ -4950,7 +4952,7 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls, static void setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls, int path_len, JsonbParseState **st, int level, - Jsonb *newval, uint32 nelems, int op_type) + JsonbValue *newval, uint32 nelems, int op_type) { JsonbValue v; int idx, @@ -4998,7 +5000,7 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls, (op_type & JB_PATH_CREATE_OR_INSERT)) { Assert(newval != NULL); - addJsonbToParseState(st, newval); + (void) pushJsonbValue(st, WJB_ELEM, newval); done = true; } @@ -5014,7 +5016,7 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls, r = JsonbIteratorNext(it, &v, true); /* skip */ if (op_type & (JB_PATH_INSERT_BEFORE | JB_PATH_CREATE)) - addJsonbToParseState(st, newval); + (void) pushJsonbValue(st, WJB_ELEM, newval); /* * We should keep current value only in case of @@ -5025,7 +5027,7 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls, (void) pushJsonbValue(st, r, &v); if (op_type & (JB_PATH_INSERT_AFTER | JB_PATH_REPLACE)) - addJsonbToParseState(st, newval); + (void) pushJsonbValue(st, WJB_ELEM, newval); done = true; } @@ -5059,7 +5061,7 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls, if ((op_type & JB_PATH_CREATE_OR_INSERT) && !done && level == path_len - 1 && i == nelems - 1) { - addJsonbToParseState(st, newval); + (void) pushJsonbValue(st, WJB_ELEM, newval); } } } diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index ee0049dc9718f..133f4ee3094ca 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202101181 +#define CATALOG_VERSION_NO 202101311 #endif diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index b5f52d4e4a3ea..f8174061ef359 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -11300,6 +11300,10 @@ { oid => '9256', descr => 'raw array subscripting support', proname => 'raw_array_subscript_handler', prorettype => 'internal', proargtypes => 'internal', prosrc => 'raw_array_subscript_handler' }, +# type subscripting support +{ oid => '6098', descr => 'jsonb subscripting logic', + proname => 'jsonb_subscript_handler', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'jsonb_subscript_handler' }, # collation management functions { oid => '3445', descr => 'import collations from operating system', diff --git a/src/include/catalog/pg_type.dat b/src/include/catalog/pg_type.dat index 56da2913bdac9..8959c2f53bb00 100644 --- a/src/include/catalog/pg_type.dat +++ b/src/include/catalog/pg_type.dat @@ -444,7 +444,8 @@ { oid => '3802', array_type_oid => '3807', descr => 'Binary JSON', typname => 'jsonb', typlen => '-1', typbyval => 'f', typcategory => 'U', typinput => 'jsonb_in', typoutput => 'jsonb_out', typreceive => 'jsonb_recv', - typsend => 'jsonb_send', typalign => 'i', typstorage => 'x' }, + typsend => 'jsonb_send', typalign => 'i', typstorage => 'x', + typsubscript => 'jsonb_subscript_handler' }, { oid => '4072', array_type_oid => '4073', descr => 'JSON path', typname => 'jsonpath', typlen => '-1', typbyval => 'f', typcategory => 'U', typinput => 'jsonpath_in', typoutput => 'jsonpath_out', diff --git a/src/include/utils/jsonb.h b/src/include/utils/jsonb.h index d9f009d19b498..4e07debf7853a 100644 --- a/src/include/utils/jsonb.h +++ b/src/include/utils/jsonb.h @@ -392,6 +392,7 @@ extern JsonbValue *pushJsonbValue(JsonbParseState **pstate, extern JsonbIterator *JsonbIteratorInit(JsonbContainer *container); extern JsonbIteratorToken JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, bool skipNested); +extern void JsonbToJsonbValue(Jsonb *jsonb, JsonbValue *val); extern Jsonb *JsonbValueToJsonb(JsonbValue *val); extern bool JsonbDeepContains(JsonbIterator **val, JsonbIterator **mContained); @@ -407,5 +408,8 @@ extern char *JsonbToCStringIndent(StringInfo out, JsonbContainer *in, extern bool JsonbExtractScalar(JsonbContainer *jbc, JsonbValue *res); extern const char *JsonbTypeName(JsonbValue *jb); - +extern Datum jsonb_set_element(Jsonb *jb, Datum *path, int path_len, + JsonbValue *newval); +extern Datum jsonb_get_element(Jsonb *jb, Datum *path, int npath, + bool *isnull, bool as_text); #endif /* __JSONB_H__ */ diff --git a/src/test/regress/expected/jsonb.out b/src/test/regress/expected/jsonb.out index 1e6c6ef200aaa..46bf2e23530c0 100644 --- a/src/test/regress/expected/jsonb.out +++ b/src/test/regress/expected/jsonb.out @@ -4599,7 +4599,7 @@ select jsonb_set_lax('{"a":1,"b":2}', '{b}', null, null_value_treatment => 'use_ {"a": 1, "b": null} (1 row) -\pset null +\pset null '' -- jsonb_insert select jsonb_insert('{"a": [0,1,2]}', '{a, 1}', '"new_value"'); jsonb_insert @@ -4729,6 +4729,276 @@ HINT: Try using the function jsonb_set to replace key value. select jsonb_insert('{"a": {"b": "value"}}', '{a, b}', '"new_value"', true); ERROR: cannot replace existing key HINT: Try using the function jsonb_set to replace key value. +-- jsonb subscript +select ('123'::jsonb)['a']; + jsonb +------- + +(1 row) + +select ('123'::jsonb)[0]; + jsonb +------- + +(1 row) + +select ('123'::jsonb)[NULL]; + jsonb +------- + +(1 row) + +select ('{"a": 1}'::jsonb)['a']; + jsonb +------- + 1 +(1 row) + +select ('{"a": 1}'::jsonb)[0]; + jsonb +------- + +(1 row) + +select ('{"a": 1}'::jsonb)['not_exist']; + jsonb +------- + +(1 row) + +select ('{"a": 1}'::jsonb)[NULL]; + jsonb +------- + +(1 row) + +select ('[1, "2", null]'::jsonb)['a']; + jsonb +------- + +(1 row) + +select ('[1, "2", null]'::jsonb)[0]; + jsonb +------- + 1 +(1 row) + +select ('[1, "2", null]'::jsonb)['1']; + jsonb +------- + "2" +(1 row) + +select ('[1, "2", null]'::jsonb)[1.0]; +ERROR: subscript type is not supported +LINE 1: select ('[1, "2", null]'::jsonb)[1.0]; + ^ +HINT: Jsonb subscript must be coerced to either integer or text +select ('[1, "2", null]'::jsonb)[2]; + jsonb +------- + null +(1 row) + +select ('[1, "2", null]'::jsonb)[3]; + jsonb +------- + +(1 row) + +select ('[1, "2", null]'::jsonb)[-2]; + jsonb +------- + "2" +(1 row) + +select ('[1, "2", null]'::jsonb)[1]['a']; + jsonb +------- + +(1 row) + +select ('[1, "2", null]'::jsonb)[1][0]; + jsonb +------- + +(1 row) + +select ('{"a": 1, "b": "c", "d": [1, 2, 3]}'::jsonb)['b']; + jsonb +------- + "c" +(1 row) + +select ('{"a": 1, "b": "c", "d": [1, 2, 3]}'::jsonb)['d']; + jsonb +----------- + [1, 2, 3] +(1 row) + +select ('{"a": 1, "b": "c", "d": [1, 2, 3]}'::jsonb)['d'][1]; + jsonb +------- + 2 +(1 row) + +select ('{"a": 1, "b": "c", "d": [1, 2, 3]}'::jsonb)['d']['a']; + jsonb +------- + +(1 row) + +select ('{"a": {"a1": {"a2": "aaa"}}, "b": "bbb", "c": "ccc"}'::jsonb)['a']['a1']; + jsonb +--------------- + {"a2": "aaa"} +(1 row) + +select ('{"a": {"a1": {"a2": "aaa"}}, "b": "bbb", "c": "ccc"}'::jsonb)['a']['a1']['a2']; + jsonb +------- + "aaa" +(1 row) + +select ('{"a": {"a1": {"a2": "aaa"}}, "b": "bbb", "c": "ccc"}'::jsonb)['a']['a1']['a2']['a3']; + jsonb +------- + +(1 row) + +select ('{"a": ["a1", {"b1": ["aaa", "bbb", "ccc"]}], "b": "bb"}'::jsonb)['a'][1]['b1']; + jsonb +----------------------- + ["aaa", "bbb", "ccc"] +(1 row) + +select ('{"a": ["a1", {"b1": ["aaa", "bbb", "ccc"]}], "b": "bb"}'::jsonb)['a'][1]['b1'][2]; + jsonb +------- + "ccc" +(1 row) + +-- slices are not supported +select ('{"a": 1}'::jsonb)['a':'b']; +ERROR: jsonb subscript does not support slices +LINE 1: select ('{"a": 1}'::jsonb)['a':'b']; + ^ +select ('[1, "2", null]'::jsonb)[1:2]; +ERROR: jsonb subscript does not support slices +LINE 1: select ('[1, "2", null]'::jsonb)[1:2]; + ^ +select ('[1, "2", null]'::jsonb)[:2]; +ERROR: jsonb subscript does not support slices +LINE 1: select ('[1, "2", null]'::jsonb)[:2]; + ^ +select ('[1, "2", null]'::jsonb)[1:]; +ERROR: jsonb subscript does not support slices +LINE 1: select ('[1, "2", null]'::jsonb)[1:]; + ^ +select ('[1, "2", null]'::jsonb)[:]; +ERROR: jsonb subscript does not support slices +create TEMP TABLE test_jsonb_subscript ( + id int, + test_json jsonb +); +insert into test_jsonb_subscript values +(1, '{}'), -- empty jsonb +(2, '{"key": "value"}'); -- jsonb with data +-- update empty jsonb +update test_jsonb_subscript set test_json['a'] = '1' where id = 1; +select * from test_jsonb_subscript; + id | test_json +----+------------------ + 2 | {"key": "value"} + 1 | {"a": 1} +(2 rows) + +-- update jsonb with some data +update test_jsonb_subscript set test_json['a'] = '1' where id = 2; +select * from test_jsonb_subscript; + id | test_json +----+-------------------------- + 1 | {"a": 1} + 2 | {"a": 1, "key": "value"} +(2 rows) + +-- replace jsonb +update test_jsonb_subscript set test_json['a'] = '"test"'; +select * from test_jsonb_subscript; + id | test_json +----+------------------------------- + 1 | {"a": "test"} + 2 | {"a": "test", "key": "value"} +(2 rows) + +-- replace by object +update test_jsonb_subscript set test_json['a'] = '{"b": 1}'::jsonb; +select * from test_jsonb_subscript; + id | test_json +----+--------------------------------- + 1 | {"a": {"b": 1}} + 2 | {"a": {"b": 1}, "key": "value"} +(2 rows) + +-- replace by array +update test_jsonb_subscript set test_json['a'] = '[1, 2, 3]'::jsonb; +select * from test_jsonb_subscript; + id | test_json +----+---------------------------------- + 1 | {"a": [1, 2, 3]} + 2 | {"a": [1, 2, 3], "key": "value"} +(2 rows) + +-- use jsonb subscription in where clause +select * from test_jsonb_subscript where test_json['key'] = '"value"'; + id | test_json +----+---------------------------------- + 2 | {"a": [1, 2, 3], "key": "value"} +(1 row) + +select * from test_jsonb_subscript where test_json['key_doesnt_exists'] = '"value"'; + id | test_json +----+----------- +(0 rows) + +select * from test_jsonb_subscript where test_json['key'] = '"wrong_value"'; + id | test_json +----+----------- +(0 rows) + +-- NULL +update test_jsonb_subscript set test_json[NULL] = '1'; +ERROR: jsonb subscript in assignment must not be null +update test_jsonb_subscript set test_json['another_key'] = NULL; +select * from test_jsonb_subscript; + id | test_json +----+------------------------------------------------------- + 1 | {"a": [1, 2, 3], "another_key": null} + 2 | {"a": [1, 2, 3], "key": "value", "another_key": null} +(2 rows) + +-- NULL as jsonb source +insert into test_jsonb_subscript values (3, NULL); +update test_jsonb_subscript set test_json['a'] = '1' where id = 3; +select * from test_jsonb_subscript; + id | test_json +----+------------------------------------------------------- + 1 | {"a": [1, 2, 3], "another_key": null} + 2 | {"a": [1, 2, 3], "key": "value", "another_key": null} + 3 | {"a": 1} +(3 rows) + +update test_jsonb_subscript set test_json = NULL where id = 3; +update test_jsonb_subscript set test_json[0] = '1'; +select * from test_jsonb_subscript; + id | test_json +----+--------------------------------------------------------------- + 1 | {"0": 1, "a": [1, 2, 3], "another_key": null} + 2 | {"0": 1, "a": [1, 2, 3], "key": "value", "another_key": null} + 3 | [1] +(3 rows) + -- jsonb to tsvector select to_tsvector('{"a": "aaa bbb ddd ccc", "b": ["eee fff ggg"], "c": {"d": "hhh iii"}}'::jsonb); to_tsvector diff --git a/src/test/regress/sql/jsonb.sql b/src/test/regress/sql/jsonb.sql index b6409767f6d73..20aa8fe0e24e9 100644 --- a/src/test/regress/sql/jsonb.sql +++ b/src/test/regress/sql/jsonb.sql @@ -1177,7 +1177,7 @@ select jsonb_set_lax('{"a":1,"b":2}', '{b}', null, null_value_treatment => 'retu select jsonb_set_lax('{"a":1,"b":2}', '{b}', null, null_value_treatment => 'delete_key') as delete_key; select jsonb_set_lax('{"a":1,"b":2}', '{b}', null, null_value_treatment => 'use_json_null') as use_json_null; -\pset null +\pset null '' -- jsonb_insert select jsonb_insert('{"a": [0,1,2]}', '{a, 1}', '"new_value"'); @@ -1208,6 +1208,88 @@ select jsonb_insert('{"a": {"b": "value"}}', '{a, c}', '"new_value"', true); select jsonb_insert('{"a": {"b": "value"}}', '{a, b}', '"new_value"'); select jsonb_insert('{"a": {"b": "value"}}', '{a, b}', '"new_value"', true); +-- jsonb subscript +select ('123'::jsonb)['a']; +select ('123'::jsonb)[0]; +select ('123'::jsonb)[NULL]; +select ('{"a": 1}'::jsonb)['a']; +select ('{"a": 1}'::jsonb)[0]; +select ('{"a": 1}'::jsonb)['not_exist']; +select ('{"a": 1}'::jsonb)[NULL]; +select ('[1, "2", null]'::jsonb)['a']; +select ('[1, "2", null]'::jsonb)[0]; +select ('[1, "2", null]'::jsonb)['1']; +select ('[1, "2", null]'::jsonb)[1.0]; +select ('[1, "2", null]'::jsonb)[2]; +select ('[1, "2", null]'::jsonb)[3]; +select ('[1, "2", null]'::jsonb)[-2]; +select ('[1, "2", null]'::jsonb)[1]['a']; +select ('[1, "2", null]'::jsonb)[1][0]; +select ('{"a": 1, "b": "c", "d": [1, 2, 3]}'::jsonb)['b']; +select ('{"a": 1, "b": "c", "d": [1, 2, 3]}'::jsonb)['d']; +select ('{"a": 1, "b": "c", "d": [1, 2, 3]}'::jsonb)['d'][1]; +select ('{"a": 1, "b": "c", "d": [1, 2, 3]}'::jsonb)['d']['a']; +select ('{"a": {"a1": {"a2": "aaa"}}, "b": "bbb", "c": "ccc"}'::jsonb)['a']['a1']; +select ('{"a": {"a1": {"a2": "aaa"}}, "b": "bbb", "c": "ccc"}'::jsonb)['a']['a1']['a2']; +select ('{"a": {"a1": {"a2": "aaa"}}, "b": "bbb", "c": "ccc"}'::jsonb)['a']['a1']['a2']['a3']; +select ('{"a": ["a1", {"b1": ["aaa", "bbb", "ccc"]}], "b": "bb"}'::jsonb)['a'][1]['b1']; +select ('{"a": ["a1", {"b1": ["aaa", "bbb", "ccc"]}], "b": "bb"}'::jsonb)['a'][1]['b1'][2]; + +-- slices are not supported +select ('{"a": 1}'::jsonb)['a':'b']; +select ('[1, "2", null]'::jsonb)[1:2]; +select ('[1, "2", null]'::jsonb)[:2]; +select ('[1, "2", null]'::jsonb)[1:]; +select ('[1, "2", null]'::jsonb)[:]; + +create TEMP TABLE test_jsonb_subscript ( + id int, + test_json jsonb +); + +insert into test_jsonb_subscript values +(1, '{}'), -- empty jsonb +(2, '{"key": "value"}'); -- jsonb with data + +-- update empty jsonb +update test_jsonb_subscript set test_json['a'] = '1' where id = 1; +select * from test_jsonb_subscript; + +-- update jsonb with some data +update test_jsonb_subscript set test_json['a'] = '1' where id = 2; +select * from test_jsonb_subscript; + +-- replace jsonb +update test_jsonb_subscript set test_json['a'] = '"test"'; +select * from test_jsonb_subscript; + +-- replace by object +update test_jsonb_subscript set test_json['a'] = '{"b": 1}'::jsonb; +select * from test_jsonb_subscript; + +-- replace by array +update test_jsonb_subscript set test_json['a'] = '[1, 2, 3]'::jsonb; +select * from test_jsonb_subscript; + +-- use jsonb subscription in where clause +select * from test_jsonb_subscript where test_json['key'] = '"value"'; +select * from test_jsonb_subscript where test_json['key_doesnt_exists'] = '"value"'; +select * from test_jsonb_subscript where test_json['key'] = '"wrong_value"'; + +-- NULL +update test_jsonb_subscript set test_json[NULL] = '1'; +update test_jsonb_subscript set test_json['another_key'] = NULL; +select * from test_jsonb_subscript; + +-- NULL as jsonb source +insert into test_jsonb_subscript values (3, NULL); +update test_jsonb_subscript set test_json['a'] = '1' where id = 3; +select * from test_jsonb_subscript; + +update test_jsonb_subscript set test_json = NULL where id = 3; +update test_jsonb_subscript set test_json[0] = '1'; +select * from test_jsonb_subscript; + -- jsonb to tsvector select to_tsvector('{"a": "aaa bbb ddd ccc", "b": ["eee fff ggg"], "c": {"d": "hhh iii"}}'::jsonb); diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 721b230bf2924..1d540fe489fe7 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -1198,6 +1198,7 @@ JsonbIterator JsonbIteratorToken JsonbPair JsonbParseState +JsonbSubWorkspace JsonbTypeCategory JsonbValue JunkFilter From 81fcc72e66222357f9bccce3eeda62eb2cb29849 Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Sun, 31 Jan 2021 23:51:01 +0300 Subject: [PATCH 221/240] Filling array gaps during jsonb subscripting This commit introduces two new flags for jsonb assignment: * JB_PATH_FILL_GAPS: Appending array elements on the specified position, gaps are filled with nulls (similar to the JavaScript behavior). This mode also instructs to create the whole path in a jsonb object if some part of the path (more than just the last element) is not present. * JB_PATH_CONSISTENT_POSITION: Assigning keeps array positions consistent by preventing prepending of elements. Both flags are used only in jsonb subscripting assignment. Initially proposed by Nikita Glukhov based on polymorphic subscripting patch, but transformed into an independent change. Discussion: https://postgr.es/m/CA%2Bq6zcV8qvGcDXurwwgUbwACV86Th7G80pnubg42e-p9gsSf%3Dg%40mail.gmail.com Discussion: https://postgr.es/m/CA%2Bq6zcX3mdxGCgdThzuySwH-ApyHHM-G4oB1R0fn0j2hZqqkLQ%40mail.gmail.com Discussion: https://postgr.es/m/CA%2Bq6zcVDuGBv%3DM0FqBYX8DPebS3F_0KQ6OVFobGJPM507_SZ_w%40mail.gmail.com Discussion: https://postgr.es/m/CA%2Bq6zcVovR%2BXY4mfk-7oNk-rF91gH0PebnNfuUjuuDsyHjOcVA%40mail.gmail.com Author: Dmitry Dolgov Reviewed-by: Tom Lane, Arthur Zakirov, Pavel Stehule, Dian M Fay Reviewed-by: Andrew Dunstan, Chapman Flack, Merlin Moncure, Peter Geoghegan Reviewed-by: Alvaro Herrera, Jim Nasby, Josh Berkus, Victor Wagner Reviewed-by: Aleksander Alekseev, Robert Haas, Oleg Bartunov --- doc/src/sgml/json.sgml | 24 +++ src/backend/utils/adt/jsonfuncs.c | 227 ++++++++++++++++++++++++++-- src/test/regress/expected/jsonb.out | 135 +++++++++++++++++ src/test/regress/sql/jsonb.sql | 81 ++++++++++ 4 files changed, 452 insertions(+), 15 deletions(-) diff --git a/doc/src/sgml/json.sgml b/doc/src/sgml/json.sgml index 3ace5e444b080..07bd19f974207 100644 --- a/doc/src/sgml/json.sgml +++ b/doc/src/sgml/json.sgml @@ -648,6 +648,30 @@ UPDATE table_name SET jsonb_field['a'] = '1'; -- Where jsonb_field was NULL, it is now [1] UPDATE table_name SET jsonb_field[0] = '1'; + + + If an index is specified for an array containing too few elements, + NULL elements will be appended until the index is reachable + and the value can be set. + + +-- Where jsonb_field was [], it is now [null, null, 2]; +-- where jsonb_field was [0], it is now [0, null, 2] +UPDATE table_name SET jsonb_field[2] = '2'; + + + A jsonb value will accept assignments to nonexistent subscript + paths as long as the last existing path key is an object or an array. Since + the final subscript is not traversed, it may be an object key. Nested arrays + will be created and NULL-padded according to the path until + the value can be placed appropriately. + + +-- Where jsonb_field was {}, it is now {'a': [{'b': 1}]} +UPDATE table_name SET jsonb_field['a'][0]['b'] = '1'; + +-- Where jsonb_field was [], it is now [{'a': 1}] +UPDATE table_name SET jsonb_field[0]['a'] = '1'; diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c index 076cde09022f3..a0e1266e571a0 100644 --- a/src/backend/utils/adt/jsonfuncs.c +++ b/src/backend/utils/adt/jsonfuncs.c @@ -44,6 +44,8 @@ #define JB_PATH_INSERT_AFTER 0x0010 #define JB_PATH_CREATE_OR_INSERT \ (JB_PATH_INSERT_BEFORE | JB_PATH_INSERT_AFTER | JB_PATH_CREATE) +#define JB_PATH_FILL_GAPS 0x0020 +#define JB_PATH_CONSISTENT_POSITION 0x0040 /* state for json_object_keys */ typedef struct OkeysState @@ -1634,14 +1636,117 @@ jsonb_set_element(Jsonb *jb, Datum *path, int path_len, it = JsonbIteratorInit(&jb->root); - res = setPath(&it, path, path_nulls, path_len, &state, 0, - newval, JB_PATH_CREATE); + res = setPath(&it, path, path_nulls, path_len, &state, 0, newval, + JB_PATH_CREATE | JB_PATH_FILL_GAPS | + JB_PATH_CONSISTENT_POSITION); pfree(path_nulls); PG_RETURN_JSONB_P(JsonbValueToJsonb(res)); } +static void +push_null_elements(JsonbParseState **ps, int num) +{ + JsonbValue null; + + null.type = jbvNull; + + while (num-- > 0) + pushJsonbValue(ps, WJB_ELEM, &null); +} + +/* + * Prepare a new structure containing nested empty objects and arrays + * corresponding to the specified path, and assign a new value at the end of + * this path. E.g. the path [a][0][b] with the new value 1 will produce the + * structure {a: [{b: 1}]}. + * + * Called is responsible to make sure such path does not exist yet. + */ +static void +push_path(JsonbParseState **st, int level, Datum *path_elems, + bool *path_nulls, int path_len, JsonbValue *newval) +{ + /* + * tpath contains expected type of an empty jsonb created at each level + * higher or equal than the current one, either jbvObject or jbvArray. + * Since it contains only information about path slice from level to the + * end, the access index must be normalized by level. + */ + enum jbvType *tpath = palloc0((path_len - level) * sizeof(enum jbvType)); + long lindex; + JsonbValue newkey; + + /* + * Create first part of the chain with beginning tokens. For the current + * level WJB_BEGIN_OBJECT/WJB_BEGIN_ARRAY was already created, so start + * with the next one. + */ + for (int i = level + 1; i < path_len; i++) + { + char *c, + *badp; + + if (path_nulls[i]) + break; + + /* + * Try to convert to an integer to find out the expected type, object + * or array. + */ + c = TextDatumGetCString(path_elems[i]); + errno = 0; + lindex = strtol(c, &badp, 10); + if (errno != 0 || badp == c || *badp != '\0' || lindex > INT_MAX || + lindex < INT_MIN) + { + /* text, an object is expected */ + newkey.type = jbvString; + newkey.val.string.len = VARSIZE_ANY_EXHDR(path_elems[i]); + newkey.val.string.val = VARDATA_ANY(path_elems[i]); + + (void) pushJsonbValue(st, WJB_BEGIN_OBJECT, NULL); + (void) pushJsonbValue(st, WJB_KEY, &newkey); + + tpath[i - level] = jbvObject; + } + else + { + /* integer, an array is expected */ + (void) pushJsonbValue(st, WJB_BEGIN_ARRAY, NULL); + + push_null_elements(st, lindex); + + tpath[i - level] = jbvArray; + } + + } + + /* Insert an actual value for either an object or array */ + if (tpath[(path_len - level) - 1] == jbvArray) + { + (void) pushJsonbValue(st, WJB_ELEM, newval); + } + else + (void) pushJsonbValue(st, WJB_VALUE, newval); + + /* + * Close everything up to the last but one level. The last one will be + * closed outside of this function. + */ + for (int i = path_len - 1; i > level; i--) + { + if (path_nulls[i]) + break; + + if (tpath[i - level] == jbvObject) + (void) pushJsonbValue(st, WJB_END_OBJECT, NULL); + else + (void) pushJsonbValue(st, WJB_END_ARRAY, NULL); + } +} + /* * Return the text representation of the given JsonbValue. */ @@ -4786,6 +4891,21 @@ IteratorConcat(JsonbIterator **it1, JsonbIterator **it2, * Bits JB_PATH_INSERT_BEFORE and JB_PATH_INSERT_AFTER in op_type * behave as JB_PATH_CREATE if new value is inserted in JsonbObject. * + * If JB_PATH_FILL_GAPS bit is set, this will change an assignment logic in + * case if target is an array. The assignment index will not be restricted by + * number of elements in the array, and if there are any empty slots between + * last element of the array and a new one they will be filled with nulls. If + * the index is negative, it still will be considered an an index from the end + * of the array. Of a part of the path is not present and this part is more + * than just one last element, this flag will instruct to create the whole + * chain of corresponding objects and insert the value. + * + * JB_PATH_CONSISTENT_POSITION for an array indicates that the called wants to + * keep values with fixed indices. Indices for existing elements could be + * changed (shifted forward) in case if the array is prepended with a new value + * and a negative index out of the range, so this behavior will be prevented + * and return an error. + * * All path elements before the last must already exist * whatever bits in op_type are set, or nothing is done. */ @@ -4880,6 +5000,8 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls, memcmp(k.val.string.val, VARDATA_ANY(path_elems[level]), k.val.string.len) == 0) { + done = true; + if (level == path_len - 1) { /* @@ -4899,7 +5021,6 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls, (void) pushJsonbValue(st, WJB_KEY, &k); (void) pushJsonbValue(st, WJB_VALUE, newval); } - done = true; } else { @@ -4944,6 +5065,31 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls, } } } + + /*-- + * If we got here there are only few possibilities: + * - no target path was found, and an open object with some keys/values was + * pushed into the state + * - an object is empty, only WJB_BEGIN_OBJECT is pushed + * + * In both cases if instructed to create the path when not present, + * generate the whole chain of empty objects and insert the new value + * there. + */ + if (!done && (op_type & JB_PATH_FILL_GAPS) && (level < path_len - 1)) + { + JsonbValue newkey; + + newkey.type = jbvString; + newkey.val.string.len = VARSIZE_ANY_EXHDR(path_elems[level]); + newkey.val.string.val = VARDATA_ANY(path_elems[level]); + + (void) pushJsonbValue(st, WJB_KEY, &newkey); + (void) push_path(st, level, path_elems, path_nulls, + path_len, newval); + + /* Result is closed with WJB_END_OBJECT outside of this function */ + } } /* @@ -4982,25 +5128,48 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls, if (idx < 0) { if (-idx > nelems) - idx = INT_MIN; + { + /* + * If asked to keep elements position consistent, it's not allowed + * to prepend the array. + */ + if (op_type & JB_PATH_CONSISTENT_POSITION) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("path element at position %d is out of range: %d", + level + 1, idx))); + else + idx = INT_MIN; + } else idx = nelems + idx; } - if (idx > 0 && idx > nelems) - idx = nelems; + /* + * Filling the gaps means there are no limits on the positive index are + * imposed, we can set any element. Otherwise limit the index by nelems. + */ + if (!(op_type & JB_PATH_FILL_GAPS)) + { + if (idx > 0 && idx > nelems) + idx = nelems; + } /* * if we're creating, and idx == INT_MIN, we prepend the new value to the * array also if the array is empty - in which case we don't really care * what the idx value is */ - if ((idx == INT_MIN || nelems == 0) && (level == path_len - 1) && (op_type & JB_PATH_CREATE_OR_INSERT)) { Assert(newval != NULL); + + if (op_type & JB_PATH_FILL_GAPS && nelems == 0 && idx > 0) + push_null_elements(st, idx); + (void) pushJsonbValue(st, WJB_ELEM, newval); + done = true; } @@ -5011,6 +5180,8 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls, if (i == idx && level < path_len) { + done = true; + if (level == path_len - 1) { r = JsonbIteratorNext(it, &v, true); /* skip */ @@ -5028,8 +5199,6 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls, if (op_type & (JB_PATH_INSERT_AFTER | JB_PATH_REPLACE)) (void) pushJsonbValue(st, WJB_ELEM, newval); - - done = true; } else (void) setPath(it, path_elems, path_nulls, path_len, @@ -5057,14 +5226,42 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls, (void) pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL); } } - - if ((op_type & JB_PATH_CREATE_OR_INSERT) && !done && - level == path_len - 1 && i == nelems - 1) - { - (void) pushJsonbValue(st, WJB_ELEM, newval); - } } } + + if ((op_type & JB_PATH_CREATE_OR_INSERT) && !done && level == path_len - 1) + { + /* + * If asked to fill the gaps, idx could be bigger than nelems, so + * prepend the new element with nulls if that's the case. + */ + if (op_type & JB_PATH_FILL_GAPS && idx > nelems) + push_null_elements(st, idx - nelems); + + (void) pushJsonbValue(st, WJB_ELEM, newval); + done = true; + } + + /*-- + * If we got here there are only few possibilities: + * - no target path was found, and an open array with some keys/values was + * pushed into the state + * - an array is empty, only WJB_BEGIN_ARRAY is pushed + * + * In both cases if instructed to create the path when not present, + * generate the whole chain of empty objects and insert the new value + * there. + */ + if (!done && (op_type & JB_PATH_FILL_GAPS) && (level < path_len - 1)) + { + if (idx > 0) + push_null_elements(st, idx - nelems); + + (void) push_path(st, level, path_elems, path_nulls, + path_len, newval); + + /* Result is closed with WJB_END_OBJECT outside of this function */ + } } /* diff --git a/src/test/regress/expected/jsonb.out b/src/test/regress/expected/jsonb.out index 46bf2e23530c0..5b5510c4fdc7e 100644 --- a/src/test/regress/expected/jsonb.out +++ b/src/test/regress/expected/jsonb.out @@ -4999,6 +4999,141 @@ select * from test_jsonb_subscript; 3 | [1] (3 rows) +-- Fill the gaps logic +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '[0]'); +update test_jsonb_subscript set test_json[5] = '1'; +select * from test_jsonb_subscript; + id | test_json +----+-------------------------------- + 1 | [0, null, null, null, null, 1] +(1 row) + +update test_jsonb_subscript set test_json[-4] = '1'; +select * from test_jsonb_subscript; + id | test_json +----+----------------------------- + 1 | [0, null, 1, null, null, 1] +(1 row) + +update test_jsonb_subscript set test_json[-8] = '1'; +ERROR: path element at position 1 is out of range: -8 +select * from test_jsonb_subscript; + id | test_json +----+----------------------------- + 1 | [0, null, 1, null, null, 1] +(1 row) + +-- keep consistent values position +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '[]'); +update test_jsonb_subscript set test_json[5] = '1'; +select * from test_jsonb_subscript; + id | test_json +----+----------------------------------- + 1 | [null, null, null, null, null, 1] +(1 row) + +-- create the whole path +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '{}'); +update test_jsonb_subscript set test_json['a'][0]['b'][0]['c'] = '1'; +select * from test_jsonb_subscript; + id | test_json +----+---------------------------- + 1 | {"a": [{"b": [{"c": 1}]}]} +(1 row) + +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '{}'); +update test_jsonb_subscript set test_json['a'][2]['b'][2]['c'][2] = '1'; +select * from test_jsonb_subscript; + id | test_json +----+------------------------------------------------------------------ + 1 | {"a": [null, null, {"b": [null, null, {"c": [null, null, 1]}]}]} +(1 row) + +-- create the whole path with already existing keys +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '{"b": 1}'); +update test_jsonb_subscript set test_json['a'][0] = '2'; +select * from test_jsonb_subscript; + id | test_json +----+-------------------- + 1 | {"a": [2], "b": 1} +(1 row) + +-- the start jsonb is an object, first subscript is treated as a key +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '{}'); +update test_jsonb_subscript set test_json[0]['a'] = '1'; +select * from test_jsonb_subscript; + id | test_json +----+----------------- + 1 | {"0": {"a": 1}} +(1 row) + +-- the start jsonb is an array +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '[]'); +update test_jsonb_subscript set test_json[0]['a'] = '1'; +update test_jsonb_subscript set test_json[2]['b'] = '2'; +select * from test_jsonb_subscript; + id | test_json +----+---------------------------- + 1 | [{"a": 1}, null, {"b": 2}] +(1 row) + +-- overwriting an existing path +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '{}'); +update test_jsonb_subscript set test_json['a']['b'][1] = '1'; +update test_jsonb_subscript set test_json['a']['b'][10] = '1'; +select * from test_jsonb_subscript; + id | test_json +----+---------------------------------------------------------------------------- + 1 | {"a": {"b": [null, 1, null, null, null, null, null, null, null, null, 1]}} +(1 row) + +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '[]'); +update test_jsonb_subscript set test_json[0][0][0] = '1'; +update test_jsonb_subscript set test_json[0][0][1] = '1'; +select * from test_jsonb_subscript; + id | test_json +----+------------ + 1 | [[[1, 1]]] +(1 row) + +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '{}'); +update test_jsonb_subscript set test_json['a']['b'][10] = '1'; +update test_jsonb_subscript set test_json['a'][10][10] = '1'; +select * from test_jsonb_subscript; + id | test_json +----+------------------------------------------------------------------------------------------------------------------------------------------------------ + 1 | {"a": {"b": [null, null, null, null, null, null, null, null, null, null, 1], "10": [null, null, null, null, null, null, null, null, null, null, 1]}} +(1 row) + +-- an empty sub element +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '{"a": {}}'); +update test_jsonb_subscript set test_json['a']['b']['c'][2] = '1'; +select * from test_jsonb_subscript; + id | test_json +----+-------------------------------------- + 1 | {"a": {"b": {"c": [null, null, 1]}}} +(1 row) + +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '{"a": []}'); +update test_jsonb_subscript set test_json['a'][1]['c'][2] = '1'; +select * from test_jsonb_subscript; + id | test_json +----+--------------------------------------- + 1 | {"a": [null, {"c": [null, null, 1]}]} +(1 row) + -- jsonb to tsvector select to_tsvector('{"a": "aaa bbb ddd ccc", "b": ["eee fff ggg"], "c": {"d": "hhh iii"}}'::jsonb); to_tsvector diff --git a/src/test/regress/sql/jsonb.sql b/src/test/regress/sql/jsonb.sql index 20aa8fe0e24e9..0320db0ea4633 100644 --- a/src/test/regress/sql/jsonb.sql +++ b/src/test/regress/sql/jsonb.sql @@ -1290,6 +1290,87 @@ update test_jsonb_subscript set test_json = NULL where id = 3; update test_jsonb_subscript set test_json[0] = '1'; select * from test_jsonb_subscript; +-- Fill the gaps logic +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '[0]'); + +update test_jsonb_subscript set test_json[5] = '1'; +select * from test_jsonb_subscript; + +update test_jsonb_subscript set test_json[-4] = '1'; +select * from test_jsonb_subscript; + +update test_jsonb_subscript set test_json[-8] = '1'; +select * from test_jsonb_subscript; + +-- keep consistent values position +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '[]'); + +update test_jsonb_subscript set test_json[5] = '1'; +select * from test_jsonb_subscript; + +-- create the whole path +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '{}'); +update test_jsonb_subscript set test_json['a'][0]['b'][0]['c'] = '1'; +select * from test_jsonb_subscript; + +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '{}'); +update test_jsonb_subscript set test_json['a'][2]['b'][2]['c'][2] = '1'; +select * from test_jsonb_subscript; + +-- create the whole path with already existing keys +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '{"b": 1}'); +update test_jsonb_subscript set test_json['a'][0] = '2'; +select * from test_jsonb_subscript; + +-- the start jsonb is an object, first subscript is treated as a key +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '{}'); +update test_jsonb_subscript set test_json[0]['a'] = '1'; +select * from test_jsonb_subscript; + +-- the start jsonb is an array +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '[]'); +update test_jsonb_subscript set test_json[0]['a'] = '1'; +update test_jsonb_subscript set test_json[2]['b'] = '2'; +select * from test_jsonb_subscript; + +-- overwriting an existing path +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '{}'); +update test_jsonb_subscript set test_json['a']['b'][1] = '1'; +update test_jsonb_subscript set test_json['a']['b'][10] = '1'; +select * from test_jsonb_subscript; + +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '[]'); +update test_jsonb_subscript set test_json[0][0][0] = '1'; +update test_jsonb_subscript set test_json[0][0][1] = '1'; +select * from test_jsonb_subscript; + +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '{}'); +update test_jsonb_subscript set test_json['a']['b'][10] = '1'; +update test_jsonb_subscript set test_json['a'][10][10] = '1'; +select * from test_jsonb_subscript; + +-- an empty sub element + +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '{"a": {}}'); +update test_jsonb_subscript set test_json['a']['b']['c'][2] = '1'; +select * from test_jsonb_subscript; + +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '{"a": []}'); +update test_jsonb_subscript set test_json['a'][1]['c'][2] = '1'; +select * from test_jsonb_subscript; + -- jsonb to tsvector select to_tsvector('{"a": "aaa bbb ddd ccc", "b": ["eee fff ggg"], "c": {"d": "hhh iii"}}'::jsonb); From aa6e46daf5304e8d9e66fefc1a5bd77622ec6402 Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Sun, 31 Jan 2021 23:51:06 +0300 Subject: [PATCH 222/240] Throw error when assigning jsonb scalar instead of a composite object During the jsonb subscripting assignment, the provided path might assume an object or an array where the source jsonb has a scalar value. Initial subscripting assignment logic will skip such an update operation with no message shown. This commit makes it throw an error to indicate this type of situation. Discussion: https://postgr.es/m/CA%2Bq6zcV8qvGcDXurwwgUbwACV86Th7G80pnubg42e-p9gsSf%3Dg%40mail.gmail.com Discussion: https://postgr.es/m/CA%2Bq6zcX3mdxGCgdThzuySwH-ApyHHM-G4oB1R0fn0j2hZqqkLQ%40mail.gmail.com Discussion: https://postgr.es/m/CA%2Bq6zcVDuGBv%3DM0FqBYX8DPebS3F_0KQ6OVFobGJPM507_SZ_w%40mail.gmail.com Discussion: https://postgr.es/m/CA%2Bq6zcVovR%2BXY4mfk-7oNk-rF91gH0PebnNfuUjuuDsyHjOcVA%40mail.gmail.com Author: Dmitry Dolgov Reviewed-by: Tom Lane, Arthur Zakirov, Pavel Stehule, Dian M Fay Reviewed-by: Andrew Dunstan, Chapman Flack, Merlin Moncure, Peter Geoghegan Reviewed-by: Alvaro Herrera, Jim Nasby, Josh Berkus, Victor Wagner Reviewed-by: Aleksander Alekseev, Robert Haas, Oleg Bartunov --- doc/src/sgml/json.sgml | 39 +++++++++++++++++++++++------ src/backend/utils/adt/jsonfuncs.c | 29 +++++++++++++++++++++ src/test/regress/expected/jsonb.out | 27 ++++++++++++++++++++ src/test/regress/sql/jsonb.sql | 17 +++++++++++++ 4 files changed, 104 insertions(+), 8 deletions(-) diff --git a/doc/src/sgml/json.sgml b/doc/src/sgml/json.sgml index 07bd19f974207..e16dd6973d2c0 100644 --- a/doc/src/sgml/json.sgml +++ b/doc/src/sgml/json.sgml @@ -614,8 +614,24 @@ SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @> '{"tags": ["qu The result of a subscripting expression is always of the jsonb data type. + + UPDATE statements may use subscripting in the + SET clause to modify jsonb values. Subscript + paths must be traversible for all affected values insofar as they exist. For + instance, the path val['a']['b']['c'] can be traversed all + the way to c if every val, + val['a'], and val['a']['b'] is an + object. If any val['a'] or val['a']['b'] + is not defined, it will be created as an empty object and filled as + necessary. However, if any val itself or one of the + intermediary values is defined as a non-object such as a string, number, or + jsonb null, traversal cannot proceed so + an error is raised and the transaction aborted. + + An example of subscripting syntax: + -- Extract object value by key @@ -631,6 +647,10 @@ SELECT ('[1, "2", null]'::jsonb)[1]; -- value must be of the jsonb type as well UPDATE table_name SET jsonb_field['key'] = '1'; +-- This will raise an error if any record's jsonb_field['a']['b'] is something +-- other than an object. For example, the value {"a": 1} has no 'b' key. +UPDATE table_name SET jsonb_field['a']['b']['c'] = '1'; + -- Filter records using a WHERE clause with subscripting. Since the result of -- subscripting is jsonb, the value we compare it against must also be jsonb. -- The double quotes make "value" also a valid jsonb string. @@ -639,8 +659,9 @@ SELECT * FROM table_name WHERE jsonb_field['key'] = '"value"'; jsonb assignment via subscripting handles a few edge cases differently from jsonb_set. When a source jsonb - is NULL, assignment via subscripting will proceed as if - it was an empty JSON object: + value is NULL, assignment via subscripting will proceed + as if it was an empty JSON value of the type (object or array) implied by the + subscript key: -- Where jsonb_field was NULL, it is now {"a": 1} @@ -661,17 +682,19 @@ UPDATE table_name SET jsonb_field[2] = '2'; A jsonb value will accept assignments to nonexistent subscript - paths as long as the last existing path key is an object or an array. Since - the final subscript is not traversed, it may be an object key. Nested arrays - will be created and NULL-padded according to the path until - the value can be placed appropriately. + paths as long as the last existing element to be traversed is an object or + array, as implied by the corresponding subscript (the element indicated by + the last subscript in the path is not traversed and may be anything). Nested + array and object structures will be created, and in the former case + null-padded, as specified by the subscript path until the + assigned value can be placed. -- Where jsonb_field was {}, it is now {'a': [{'b': 1}]} UPDATE table_name SET jsonb_field['a'][0]['b'] = '1'; --- Where jsonb_field was [], it is now [{'a': 1}] -UPDATE table_name SET jsonb_field[0]['a'] = '1'; +-- Where jsonb_field was [], it is now [null, {'a': 1}] +UPDATE table_name SET jsonb_field[1]['a'] = '1'; diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c index a0e1266e571a0..215a10f16ef6e 100644 --- a/src/backend/utils/adt/jsonfuncs.c +++ b/src/backend/utils/adt/jsonfuncs.c @@ -4931,6 +4931,21 @@ setPath(JsonbIterator **it, Datum *path_elems, switch (r) { case WJB_BEGIN_ARRAY: + + /* + * If instructed complain about attempts to replace whithin a raw + * scalar value. This happens even when current level is equal to + * path_len, because the last path key should also correspond to + * an object or an array, not raw scalar. + */ + if ((op_type & JB_PATH_FILL_GAPS) && (level <= path_len - 1) && + v.val.array.rawScalar) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("cannot replace existing key"), + errdetail("The path assumes key is a composite object, " + "but it is a scalar value."))); + (void) pushJsonbValue(st, r, NULL); setPathArray(it, path_elems, path_nulls, path_len, st, level, newval, v.val.array.nElems, op_type); @@ -4948,6 +4963,20 @@ setPath(JsonbIterator **it, Datum *path_elems, break; case WJB_ELEM: case WJB_VALUE: + + /* + * If instructed complain about attempts to replace whithin a + * scalar value. This happens even when current level is equal to + * path_len, because the last path key should also correspond to + * an object or an array, not an element or value. + */ + if ((op_type & JB_PATH_FILL_GAPS) && (level <= path_len - 1)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("cannot replace existing key"), + errdetail("The path assumes key is a composite object, " + "but it is a scalar value."))); + res = pushJsonbValue(st, r, &v); break; default: diff --git a/src/test/regress/expected/jsonb.out b/src/test/regress/expected/jsonb.out index 5b5510c4fdc7e..cf0ce0e44cce0 100644 --- a/src/test/regress/expected/jsonb.out +++ b/src/test/regress/expected/jsonb.out @@ -5134,6 +5134,33 @@ select * from test_jsonb_subscript; 1 | {"a": [null, {"c": [null, null, 1]}]} (1 row) +-- trying replace assuming a composite object, but it's an element or a value +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '{"a": 1}'); +update test_jsonb_subscript set test_json['a']['b'] = '1'; +ERROR: cannot replace existing key +DETAIL: The path assumes key is a composite object, but it is a scalar value. +update test_jsonb_subscript set test_json['a']['b']['c'] = '1'; +ERROR: cannot replace existing key +DETAIL: The path assumes key is a composite object, but it is a scalar value. +update test_jsonb_subscript set test_json['a'][0] = '1'; +ERROR: cannot replace existing key +DETAIL: The path assumes key is a composite object, but it is a scalar value. +update test_jsonb_subscript set test_json['a'][0]['c'] = '1'; +ERROR: cannot replace existing key +DETAIL: The path assumes key is a composite object, but it is a scalar value. +update test_jsonb_subscript set test_json['a'][0][0] = '1'; +ERROR: cannot replace existing key +DETAIL: The path assumes key is a composite object, but it is a scalar value. +-- trying replace assuming a composite object, but it's a raw scalar +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, 'null'); +update test_jsonb_subscript set test_json[0] = '1'; +ERROR: cannot replace existing key +DETAIL: The path assumes key is a composite object, but it is a scalar value. +update test_jsonb_subscript set test_json[0][0] = '1'; +ERROR: cannot replace existing key +DETAIL: The path assumes key is a composite object, but it is a scalar value. -- jsonb to tsvector select to_tsvector('{"a": "aaa bbb ddd ccc", "b": ["eee fff ggg"], "c": {"d": "hhh iii"}}'::jsonb); to_tsvector diff --git a/src/test/regress/sql/jsonb.sql b/src/test/regress/sql/jsonb.sql index 0320db0ea4633..1a9d21741fa5e 100644 --- a/src/test/regress/sql/jsonb.sql +++ b/src/test/regress/sql/jsonb.sql @@ -1371,6 +1371,23 @@ insert into test_jsonb_subscript values (1, '{"a": []}'); update test_jsonb_subscript set test_json['a'][1]['c'][2] = '1'; select * from test_jsonb_subscript; +-- trying replace assuming a composite object, but it's an element or a value + +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, '{"a": 1}'); +update test_jsonb_subscript set test_json['a']['b'] = '1'; +update test_jsonb_subscript set test_json['a']['b']['c'] = '1'; +update test_jsonb_subscript set test_json['a'][0] = '1'; +update test_jsonb_subscript set test_json['a'][0]['c'] = '1'; +update test_jsonb_subscript set test_json['a'][0][0] = '1'; + +-- trying replace assuming a composite object, but it's a raw scalar + +delete from test_jsonb_subscript; +insert into test_jsonb_subscript values (1, 'null'); +update test_jsonb_subscript set test_json[0] = '1'; +update test_jsonb_subscript set test_json[0][0] = '1'; + -- jsonb to tsvector select to_tsvector('{"a": "aaa bbb ddd ccc", "b": ["eee fff ggg"], "c": {"d": "hhh iii"}}'::jsonb); From 7c5d57caed4d8af705d0cc3131d0d8ed72b7a41d Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 1 Feb 2021 02:03:59 -0500 Subject: [PATCH 223/240] Fix portability issue in new jsonbsubs code. On machines where sizeof(Datum) > sizeof(Oid) (that is, any 64-bit platform), the previous coding would compute a misaligned workspace->index pointer if nupper is odd. Architectures where misaligned access is a hard no-no would then fail. This appears to explain why thorntail is unhappy but other buildfarm members are not. --- src/backend/utils/adt/jsonbsubs.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/backend/utils/adt/jsonbsubs.c b/src/backend/utils/adt/jsonbsubs.c index 491e27cc04bd0..cfb923aaa35cd 100644 --- a/src/backend/utils/adt/jsonbsubs.c +++ b/src/backend/utils/adt/jsonbsubs.c @@ -356,7 +356,7 @@ jsonb_subscript_fetch_old(ExprState *state, static void jsonb_exec_setup(const SubscriptingRef *sbsref, SubscriptingRefState *sbsrefstate, - SubscriptExecSteps * methods) + SubscriptExecSteps *methods) { JsonbSubWorkspace *workspace; ListCell *lc; @@ -368,9 +368,14 @@ jsonb_exec_setup(const SubscriptingRef *sbsref, nupper * (sizeof(Datum) + sizeof(Oid))); workspace->expectArray = false; ptr = ((char *) workspace) + MAXALIGN(sizeof(JsonbSubWorkspace)); - workspace->indexOid = (Oid *) ptr; - ptr += nupper * sizeof(Oid); + + /* + * This coding assumes sizeof(Datum) >= sizeof(Oid), else we might + * misalign the indexOid pointer + */ workspace->index = (Datum *) ptr; + ptr += nupper * sizeof(Datum); + workspace->indexOid = (Oid *) ptr; sbsrefstate->workspace = workspace; From fe61df7f82aa6e0879476146dbe1da9c89b4946b Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Mon, 1 Feb 2021 19:19:44 +0900 Subject: [PATCH 224/240] Introduce --with-ssl={openssl} as a configure option This is a replacement for the existing --with-openssl, extending the logic to make easier the addition of new SSL libraries. The grammar is chosen to be similar to --with-uuid, where multiple values can be chosen, with "openssl" as the only supported value for now. The original switch, --with-openssl, is kept for compatibility. Author: Daniel Gustafsson, Michael Paquier Reviewed-by: Jacob Champion Discussion: https://postgr.es/m/FAB21FC8-0F62-434F-AA78-6BD9336D630A@yesql.se --- configure | 110 +++++++++++------- configure.ac | 31 +++-- contrib/Makefile | 2 +- contrib/pgcrypto/Makefile | 4 +- doc/src/sgml/installation.sgml | 23 +++- doc/src/sgml/pgcrypto.sgml | 2 +- doc/src/sgml/sslinfo.sgml | 2 +- src/Makefile.global.in | 2 +- src/backend/libpq/Makefile | 2 +- src/backend/libpq/hba.c | 2 +- src/common/Makefile | 2 +- src/include/pg_config.h.in | 2 +- src/interfaces/libpq/Makefile | 9 +- src/test/Makefile | 2 +- src/test/modules/Makefile | 2 +- .../modules/ssl_passphrase_callback/Makefile | 2 +- .../ssl_passphrase_callback/t/001_testfunc.pl | 4 +- src/test/ssl/Makefile | 2 +- src/test/ssl/t/001_ssltests.pl | 6 +- src/test/ssl/t/002_scram.pl | 4 +- src/tools/msvc/Solution.pm | 2 +- src/tools/msvc/config_default.pl | 2 +- 22 files changed, 137 insertions(+), 82 deletions(-) diff --git a/configure b/configure index e202697bbfade..ce9ea3699938a 100755 --- a/configure +++ b/configure @@ -653,6 +653,7 @@ LIBOBJS UUID_LIBS LDAP_LIBS_BE LDAP_LIBS_FE +with_ssl PTHREAD_CFLAGS PTHREAD_LIBS PTHREAD_CC @@ -709,7 +710,6 @@ with_uuid with_readline with_systemd with_selinux -with_openssl with_ldap with_krb_srvnam krb_srvtab @@ -854,7 +854,6 @@ with_pam with_bsd_auth with_ldap with_bonjour -with_openssl with_selinux with_systemd with_readline @@ -866,6 +865,8 @@ with_libxslt with_system_tzdata with_zlib with_gnu_ld +with_ssl +with_openssl enable_largefile ' ac_precious_vars='build_alias @@ -1556,7 +1557,6 @@ Optional Packages: --with-bsd-auth build with BSD Authentication support --with-ldap build with LDAP support --with-bonjour build with Bonjour support - --with-openssl build with OpenSSL support --with-selinux build with SELinux support --with-systemd build with systemd support --without-readline do not use GNU Readline nor BSD Libedit for editing @@ -1570,6 +1570,8 @@ Optional Packages: use system time zone data in DIR --without-zlib do not use Zlib --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-ssl=LIB use LIB for SSL/TLS support (openssl) + --with-openssl obsolete spelling of --with-ssl=openssl Some influential environment variables: CC C compiler command @@ -8070,41 +8072,6 @@ fi $as_echo "$with_bonjour" >&6; } -# -# OpenSSL -# -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build with OpenSSL support" >&5 -$as_echo_n "checking whether to build with OpenSSL support... " >&6; } - - - -# Check whether --with-openssl was given. -if test "${with_openssl+set}" = set; then : - withval=$with_openssl; - case $withval in - yes) - -$as_echo "#define USE_OPENSSL 1" >>confdefs.h - - ;; - no) - : - ;; - *) - as_fn_error $? "no argument expected for --with-openssl option" "$LINENO" 5 - ;; - esac - -else - with_openssl=no - -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_openssl" >&5 -$as_echo "$with_openssl" >&6; } - - # # SELinux # @@ -12174,7 +12141,64 @@ fi fi fi +# +# SSL Library +# +# There is currently only one supported SSL/TLS library: OpenSSL. +# + + + +# Check whether --with-ssl was given. +if test "${with_ssl+set}" = set; then : + withval=$with_ssl; + case $withval in + yes) + as_fn_error $? "argument required for --with-ssl option" "$LINENO" 5 + ;; + no) + as_fn_error $? "argument required for --with-ssl option" "$LINENO" 5 + ;; + *) + + ;; + esac + +fi + + +if test x"$with_ssl" = x"" ; then + with_ssl=no +fi + + + +# Check whether --with-openssl was given. +if test "${with_openssl+set}" = set; then : + withval=$with_openssl; + case $withval in + yes) + : + ;; + no) + : + ;; + *) + as_fn_error $? "no argument expected for --with-openssl option" "$LINENO" 5 + ;; + esac + +else + with_openssl=no + +fi + + if test "$with_openssl" = yes ; then + with_ssl=openssl +fi + +if test "$with_ssl" = openssl ; then # Minimum required OpenSSL version is 1.0.1 $as_echo "#define OPENSSL_API_COMPAT 0x10001000L" >>confdefs.h @@ -12435,8 +12459,14 @@ _ACEOF fi done + +$as_echo "#define USE_OPENSSL 1" >>confdefs.h + +elif test "$with_ssl" != no ; then + as_fn_error $? "--with-ssl must specify openssl" "$LINENO" 5 fi + if test "$with_pam" = yes ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pam_start in -lpam" >&5 $as_echo_n "checking for pam_start in -lpam... " >&6; } @@ -13322,7 +13352,7 @@ done fi -if test "$with_openssl" = yes ; then +if test "$with_ssl" = openssl ; then ac_fn_c_check_header_mongrel "$LINENO" "openssl/ssl.h" "ac_cv_header_openssl_ssl_h" "$ac_includes_default" if test "x$ac_cv_header_openssl_ssl_h" = xyes; then : @@ -18098,7 +18128,7 @@ fi # will be used. { $as_echo "$as_me:${as_lineno-$LINENO}: checking which random number source to use" >&5 $as_echo_n "checking which random number source to use... " >&6; } -if test x"$with_openssl" = x"yes" ; then +if test x"$with_ssl" = x"openssl" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: OpenSSL" >&5 $as_echo "OpenSSL" >&6; } elif test x"$PORTNAME" = x"win32" ; then diff --git a/configure.ac b/configure.ac index a5ad072ee4abf..07da84d40172d 100644 --- a/configure.ac +++ b/configure.ac @@ -852,15 +852,6 @@ PGAC_ARG_BOOL(with, bonjour, no, AC_MSG_RESULT([$with_bonjour]) -# -# OpenSSL -# -AC_MSG_CHECKING([whether to build with OpenSSL support]) -PGAC_ARG_BOOL(with, openssl, no, [build with OpenSSL support], - [AC_DEFINE([USE_OPENSSL], 1, [Define to build with OpenSSL support. (--with-openssl)])]) -AC_MSG_RESULT([$with_openssl]) -AC_SUBST(with_openssl) - # # SELinux # @@ -1205,7 +1196,21 @@ if test "$with_gssapi" = yes ; then fi fi +# +# SSL Library +# +# There is currently only one supported SSL/TLS library: OpenSSL. +# +PGAC_ARG_REQ(with, ssl, [LIB], [use LIB for SSL/TLS support (openssl)]) +if test x"$with_ssl" = x"" ; then + with_ssl=no +fi +PGAC_ARG_BOOL(with, openssl, no, [obsolete spelling of --with-ssl=openssl]) if test "$with_openssl" = yes ; then + with_ssl=openssl +fi + +if test "$with_ssl" = openssl ; then dnl Order matters! # Minimum required OpenSSL version is 1.0.1 AC_DEFINE(OPENSSL_API_COMPAT, [0x10001000L], @@ -1229,7 +1234,11 @@ if test "$with_openssl" = yes ; then # thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock() # function was removed. AC_CHECK_FUNCS([CRYPTO_lock]) + AC_DEFINE([USE_OPENSSL], 1, [Define to 1 if you have OpenSSL support.]) +elif test "$with_ssl" != no ; then + AC_MSG_ERROR([--with-ssl must specify openssl]) fi +AC_SUBST(with_ssl) if test "$with_pam" = yes ; then AC_CHECK_LIB(pam, pam_start, [], [AC_MSG_ERROR([library 'pam' is required for PAM])]) @@ -1402,7 +1411,7 @@ if test "$with_gssapi" = yes ; then [AC_CHECK_HEADERS(gssapi.h, [], [AC_MSG_ERROR([gssapi.h header file is required for GSSAPI])])]) fi -if test "$with_openssl" = yes ; then +if test "$with_ssl" = openssl ; then AC_CHECK_HEADER(openssl/ssl.h, [], [AC_MSG_ERROR([header file is required for OpenSSL])]) AC_CHECK_HEADER(openssl/err.h, [], [AC_MSG_ERROR([header file is required for OpenSSL])]) fi @@ -2159,7 +2168,7 @@ fi # first choice, else the native platform sources (Windows API or /dev/urandom) # will be used. AC_MSG_CHECKING([which random number source to use]) -if test x"$with_openssl" = x"yes" ; then +if test x"$with_ssl" = x"openssl" ; then AC_MSG_RESULT([OpenSSL]) elif test x"$PORTNAME" = x"win32" ; then AC_MSG_RESULT([Windows native]) diff --git a/contrib/Makefile b/contrib/Makefile index cdc041c7db731..f27e458482e09 100644 --- a/contrib/Makefile +++ b/contrib/Makefile @@ -51,7 +51,7 @@ SUBDIRS = \ unaccent \ vacuumlo -ifeq ($(with_openssl),yes) +ifeq ($(with_ssl),openssl) SUBDIRS += sslinfo else ALWAYS_SUBDIRS += sslinfo diff --git a/contrib/pgcrypto/Makefile b/contrib/pgcrypto/Makefile index 316a26e58deee..c0b4f1fcf68f2 100644 --- a/contrib/pgcrypto/Makefile +++ b/contrib/pgcrypto/Makefile @@ -10,8 +10,8 @@ OSSL_TESTS = sha2 des 3des cast5 ZLIB_TST = pgp-compression ZLIB_OFF_TST = pgp-zlib-DISABLED -CF_SRCS = $(if $(subst no,,$(with_openssl)), $(OSSL_SRCS), $(INT_SRCS)) -CF_TESTS = $(if $(subst no,,$(with_openssl)), $(OSSL_TESTS), $(INT_TESTS)) +CF_SRCS = $(if $(subst openssl,,$(with_ssl)), $(INT_SRCS), $(OSSL_SRCS)) +CF_TESTS = $(if $(subst openssl,,$(with_ssl)), $(INT_TESTS), $(OSSL_TESTS)) CF_PGP_TESTS = $(if $(subst no,,$(with_zlib)), $(ZLIB_TST), $(ZLIB_OFF_TST)) SRCS = \ diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml index a53389b728e39..66ad4ba93808f 100644 --- a/doc/src/sgml/installation.sgml +++ b/doc/src/sgml/installation.sgml @@ -967,7 +967,7 @@ build-postgresql: - + OpenSSL SSL @@ -976,11 +976,22 @@ build-postgresql: Build with support for SSL (encrypted) - connections. This requires the OpenSSL - package to be installed. configure will check - for the required header files and libraries to make sure that - your OpenSSL installation is sufficient - before proceeding. + connections. The only LIBRARY + supported is . This requires the + OpenSSL package to be installed. + configure will check for the required + header files and libraries to make sure that your + OpenSSL installation is sufficient + before proceeding. + + + + + + + + + Obsolete equivalent of --with-ssl=openssl. diff --git a/doc/src/sgml/pgcrypto.sgml b/doc/src/sgml/pgcrypto.sgml index 3d74e15ec9b79..b6bb23de0f91d 100644 --- a/doc/src/sgml/pgcrypto.sgml +++ b/doc/src/sgml/pgcrypto.sgml @@ -1154,7 +1154,7 @@ gen_random_uuid() returns uuid pgcrypto configures itself according to the findings of the main PostgreSQL configure script. The options that affect it are --with-zlib and - --with-openssl. + --with-ssl=openssl. diff --git a/doc/src/sgml/sslinfo.sgml b/doc/src/sgml/sslinfo.sgml index 3213c039ca671..2a9c45a111bdf 100644 --- a/doc/src/sgml/sslinfo.sgml +++ b/doc/src/sgml/sslinfo.sgml @@ -22,7 +22,7 @@ This extension won't build at all unless the installation was - configured with --with-openssl. + configured with --with-ssl=openssl. diff --git a/src/Makefile.global.in b/src/Makefile.global.in index 9a1688c97cb80..74b3a6acd292f 100644 --- a/src/Makefile.global.in +++ b/src/Makefile.global.in @@ -183,7 +183,7 @@ with_icu = @with_icu@ with_perl = @with_perl@ with_python = @with_python@ with_tcl = @with_tcl@ -with_openssl = @with_openssl@ +with_ssl = @with_ssl@ with_readline = @with_readline@ with_selinux = @with_selinux@ with_systemd = @with_systemd@ diff --git a/src/backend/libpq/Makefile b/src/backend/libpq/Makefile index efc5ef760aa93..8d1d16b0fc54b 100644 --- a/src/backend/libpq/Makefile +++ b/src/backend/libpq/Makefile @@ -28,7 +28,7 @@ OBJS = \ pqmq.o \ pqsignal.o -ifeq ($(with_openssl),yes) +ifeq ($(with_ssl),openssl) OBJS += be-secure-openssl.o endif diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c index 371dccb852fd5..20bf1461cef28 100644 --- a/src/backend/libpq/hba.c +++ b/src/backend/libpq/hba.c @@ -1041,7 +1041,7 @@ parse_hba_line(TokenizedLine *tok_line, int elevel) ereport(elevel, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("hostssl record cannot match because SSL is not supported by this build"), - errhint("Compile with --with-openssl to use SSL connections."), + errhint("Compile with --with-ssl=openssl to use SSL connections."), errcontext("line %d of configuration file \"%s\"", line_num, HbaFileName))); *err_msg = "hostssl record cannot match because SSL is not supported by this build"; diff --git a/src/common/Makefile b/src/common/Makefile index 1a1d0d3406c33..5422579a6a28e 100644 --- a/src/common/Makefile +++ b/src/common/Makefile @@ -80,7 +80,7 @@ OBJS_COMMON = \ wait_error.o \ wchar.o -ifeq ($(with_openssl),yes) +ifeq ($(with_ssl),openssl) OBJS_COMMON += \ protocol_openssl.o \ cryptohash_openssl.o diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index f4d9f3b408d9f..55cab4d2bf361 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -899,7 +899,7 @@ /* Define to select named POSIX semaphores. */ #undef USE_NAMED_POSIX_SEMAPHORES -/* Define to build with OpenSSL support. (--with-openssl) */ +/* Define to build with OpenSSL support. (--with-ssl=openssl) */ #undef USE_OPENSSL /* Define to 1 to build with PAM support. (--with-pam) */ diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile index c4fde3f93dd56..f74677eaf9b45 100644 --- a/src/interfaces/libpq/Makefile +++ b/src/interfaces/libpq/Makefile @@ -45,9 +45,14 @@ OBJS = \ pqexpbuffer.o \ fe-auth.o -ifeq ($(with_openssl),yes) +# File shared across all SSL implementations supported. +ifneq ($(with_ssl),no) +OBJS += \ + fe-secure-common.o +endif + +ifeq ($(with_ssl),openssl) OBJS += \ - fe-secure-common.o \ fe-secure-openssl.o endif diff --git a/src/test/Makefile b/src/test/Makefile index ab1ef9a47532a..f7859c2fd5e79 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -28,7 +28,7 @@ ifneq (,$(filter ldap,$(PG_TEST_EXTRA))) SUBDIRS += ldap endif endif -ifeq ($(with_openssl),yes) +ifeq ($(with_ssl),openssl) ifneq (,$(filter ssl,$(PG_TEST_EXTRA))) SUBDIRS += ssl endif diff --git a/src/test/modules/Makefile b/src/test/modules/Makefile index 59921b46cf3a8..5391f461a25bc 100644 --- a/src/test/modules/Makefile +++ b/src/test/modules/Makefile @@ -28,7 +28,7 @@ SUBDIRS = \ unsafe_tests \ worker_spi -ifeq ($(with_openssl),yes) +ifeq ($(with_ssl),openssl) SUBDIRS += ssl_passphrase_callback else ALWAYS_SUBDIRS += ssl_passphrase_callback diff --git a/src/test/modules/ssl_passphrase_callback/Makefile b/src/test/modules/ssl_passphrase_callback/Makefile index f81265c2963b2..a34d7ea46a3c4 100644 --- a/src/test/modules/ssl_passphrase_callback/Makefile +++ b/src/test/modules/ssl_passphrase_callback/Makefile @@ -1,6 +1,6 @@ # ssl_passphrase_callback Makefile -export with_openssl +export with_ssl MODULE_big = ssl_passphrase_func OBJS = ssl_passphrase_func.o $(WIN32RES) diff --git a/src/test/modules/ssl_passphrase_callback/t/001_testfunc.pl b/src/test/modules/ssl_passphrase_callback/t/001_testfunc.pl index dbc084f870e74..a2bed5336c005 100644 --- a/src/test/modules/ssl_passphrase_callback/t/001_testfunc.pl +++ b/src/test/modules/ssl_passphrase_callback/t/001_testfunc.pl @@ -7,9 +7,9 @@ use Test::More; use PostgresNode; -unless (($ENV{with_openssl} || 'no') eq 'yes') +unless ($ENV{with_ssl} eq 'openssl') { - plan skip_all => 'SSL not supported by this build'; + plan skip_all => 'OpenSSL not supported by this build'; } my $clearpass = "FooBaR1"; diff --git a/src/test/ssl/Makefile b/src/test/ssl/Makefile index 93335b1ea25ac..d545382eea2a4 100644 --- a/src/test/ssl/Makefile +++ b/src/test/ssl/Makefile @@ -13,7 +13,7 @@ subdir = src/test/ssl top_builddir = ../../.. include $(top_builddir)/src/Makefile.global -export with_openssl +export with_ssl CERTIFICATES := server_ca server-cn-and-alt-names \ server-cn-only server-single-alt-name server-multiple-alt-names \ diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl index fd2727b5684be..7928de4e7c2de 100644 --- a/src/test/ssl/t/001_ssltests.pl +++ b/src/test/ssl/t/001_ssltests.pl @@ -11,13 +11,13 @@ use SSLServer; -if ($ENV{with_openssl} eq 'yes') +if ($ENV{with_ssl} ne 'openssl') { - plan tests => 93; + plan skip_all => 'OpenSSL not supported by this build'; } else { - plan skip_all => 'SSL not supported by this build'; + plan tests => 93; } #### Some configuration diff --git a/src/test/ssl/t/002_scram.pl b/src/test/ssl/t/002_scram.pl index a088f71a1aaab..410b9e910d952 100644 --- a/src/test/ssl/t/002_scram.pl +++ b/src/test/ssl/t/002_scram.pl @@ -13,9 +13,9 @@ use SSLServer; -if ($ENV{with_openssl} ne 'yes') +if ($ENV{with_ssl} ne 'openssl') { - plan skip_all => 'SSL not supported by this build'; + plan skip_all => 'OpenSSL not supported by this build'; } # This is the hostname used to connect to the server. diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm index 2f28de0355ae9..1c0c92fcd2c2f 100644 --- a/src/tools/msvc/Solution.pm +++ b/src/tools/msvc/Solution.pm @@ -1156,7 +1156,7 @@ sub GetFakeConfigure $cfg .= ' --with-ldap' if ($self->{options}->{ldap}); $cfg .= ' --without-zlib' unless ($self->{options}->{zlib}); $cfg .= ' --with-extra-version' if ($self->{options}->{extraver}); - $cfg .= ' --with-openssl' if ($self->{options}->{openssl}); + $cfg .= ' --with-ssl=openssl' if ($self->{options}->{openssl}); $cfg .= ' --with-uuid' if ($self->{options}->{uuid}); $cfg .= ' --with-libxml' if ($self->{options}->{xml}); $cfg .= ' --with-libxslt' if ($self->{options}->{xslt}); diff --git a/src/tools/msvc/config_default.pl b/src/tools/msvc/config_default.pl index 2ef2cfc4e995a..5395e211eb208 100644 --- a/src/tools/msvc/config_default.pl +++ b/src/tools/msvc/config_default.pl @@ -16,7 +16,7 @@ tcl => undef, # --with-tcl= perl => undef, # --with-perl= python => undef, # --with-python= - openssl => undef, # --with-openssl= + openssl => undef, # --with-ssl=openssl with uuid => undef, # --with-uuid= xml => undef, # --with-libxml= xslt => undef, # --with-libxslt= From bb513b364b4fe31574574c8d0afbb2255268b321 Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Mon, 1 Feb 2021 14:06:02 +0300 Subject: [PATCH 225/240] Get rid of unnecessary memory allocation in jsonb_subscript_assign() Current code allocates memory for JsonbValue, but it could be placed locally. --- src/backend/utils/adt/jsonbsubs.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/backend/utils/adt/jsonbsubs.c b/src/backend/utils/adt/jsonbsubs.c index cfb923aaa35cd..5868aad0578f0 100644 --- a/src/backend/utils/adt/jsonbsubs.c +++ b/src/backend/utils/adt/jsonbsubs.c @@ -283,7 +283,7 @@ jsonb_subscript_assign(ExprState *state, */ if (*op->resnull) { - JsonbValue *newSource = (JsonbValue *) palloc(sizeof(JsonbValue)); + JsonbValue newSource; /* * To avoid any surprising results, set up an empty jsonb array in @@ -292,17 +292,17 @@ jsonb_subscript_assign(ExprState *state, */ if (workspace->expectArray) { - newSource->type = jbvArray; - newSource->val.array.nElems = 0; - newSource->val.array.rawScalar = false; + newSource.type = jbvArray; + newSource.val.array.nElems = 0; + newSource.val.array.rawScalar = false; } else { - newSource->type = jbvObject; - newSource->val.object.nPairs = 0; + newSource.type = jbvObject; + newSource.val.object.nPairs = 0; } - jsonbSource = JsonbValueToJsonb(newSource); + jsonbSource = JsonbValueToJsonb(&newSource); *op->resnull = false; } else From 3696a600e2292d43c00949ddf0352e4ebb487e5b Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Mon, 1 Feb 2021 13:54:59 +0100 Subject: [PATCH 226/240] SEARCH and CYCLE clauses This adds the SQL standard feature that adds the SEARCH and CYCLE clauses to recursive queries to be able to do produce breadth- or depth-first search orders and detect cycles. These clauses can be rewritten into queries using existing syntax, and that is what this patch does in the rewriter. Reviewed-by: Vik Fearing Reviewed-by: Pavel Stehule Discussion: https://www.postgresql.org/message-id/flat/db80ceee-6f97-9b4a-8ee8-3ba0c58e5be2@2ndquadrant.com --- doc/src/sgml/queries.sgml | 64 ++- doc/src/sgml/ref/select.sgml | 44 ++ src/backend/catalog/dependency.c | 15 + src/backend/nodes/copyfuncs.c | 40 ++ src/backend/nodes/equalfuncs.c | 36 ++ src/backend/nodes/nodeFuncs.c | 42 +- src/backend/nodes/outfuncs.c | 36 ++ src/backend/nodes/readfuncs.c | 44 ++ src/backend/parser/analyze.c | 47 +- src/backend/parser/gram.y | 58 +- src/backend/parser/parse_agg.c | 7 + src/backend/parser/parse_cte.c | 193 +++++++ src/backend/parser/parse_expr.c | 4 + src/backend/parser/parse_func.c | 3 + src/backend/parser/parse_relation.c | 54 +- src/backend/parser/parse_target.c | 17 +- src/backend/rewrite/Makefile | 1 + src/backend/rewrite/rewriteHandler.c | 18 + src/backend/rewrite/rewriteSearchCycle.c | 668 +++++++++++++++++++++++ src/backend/utils/adt/ruleutils.c | 47 ++ src/include/nodes/nodes.h | 2 + src/include/nodes/parsenodes.h | 30 +- src/include/parser/analyze.h | 2 + src/include/parser/kwlist.h | 2 + src/include/parser/parse_node.h | 2 + src/include/rewrite/rewriteSearchCycle.h | 21 + src/test/regress/expected/with.out | 558 +++++++++++++++++++ src/test/regress/sql/with.sql | 279 ++++++++++ 28 files changed, 2301 insertions(+), 33 deletions(-) create mode 100644 src/backend/rewrite/rewriteSearchCycle.c create mode 100644 src/include/rewrite/rewriteSearchCycle.h diff --git a/doc/src/sgml/queries.sgml b/doc/src/sgml/queries.sgml index ca51204875626..4741506eb564a 100644 --- a/doc/src/sgml/queries.sgml +++ b/doc/src/sgml/queries.sgml @@ -2218,6 +2218,39 @@ SELECT * FROM search_tree ORDER BY depth; in any case. + + + There is built-in syntax to compute a depth- or breadth-first sort column. + For example: + + +WITH RECURSIVE search_tree(id, link, data) AS ( + SELECT t.id, t.link, t.data + FROM tree t + UNION ALL + SELECT t.id, t.link, t.data + FROM tree t, search_tree st + WHERE t.id = st.link +) SEARCH DEPTH FIRST BY id SET ordercol +SELECT * FROM search_tree ORDER BY ordercol; + +WITH RECURSIVE search_tree(id, link, data) AS ( + SELECT t.id, t.link, t.data + FROM tree t + UNION ALL + SELECT t.id, t.link, t.data + FROM tree t, search_tree st + WHERE t.id = st.link +) SEARCH BREADTH FIRST BY id SET ordercol +SELECT * FROM search_tree ORDER BY ordercol; + + This syntax is internally expanded to something similar to the above + hand-written forms. The SEARCH clause specifies whether + depth- or breadth first search is wanted, the list of columns to track for + sorting, and a column name that will contain the result data that can be + used for sorting. That column will implicitly be added to the output rows + of the CTE. + @@ -2305,10 +2338,39 @@ SELECT * FROM search_graph; + + There is built-in syntax to simplify cycle detection. The above query can + also be written like this: + +WITH RECURSIVE search_graph(id, link, data, depth) AS ( + SELECT g.id, g.link, g.data, 1 + FROM graph g + UNION ALL + SELECT g.id, g.link, g.data, sg.depth + 1 + FROM graph g, search_graph sg + WHERE g.id = sg.link +) CYCLE id SET is_cycle TO true DEFAULT false USING path +SELECT * FROM search_graph; + + and it will be internally rewritten to the above form. The + CYCLE clause specifies first the list of columns to + track for cycle detection, then a column name that will show whether a + cycle has been detected, then two values to use in that column for the yes + and no cases, and finally the name of another column that will track the + path. The cycle and path columns will implicitly be added to the output + rows of the CTE. + + The cycle path column is computed in the same way as the depth-first - ordering column show in the previous section. + ordering column show in the previous section. A query can have both a + SEARCH and a CYCLE clause, but a + depth-first search specification and a cycle detection specification would + create redundant computations, so it's more efficient to just use the + CYCLE clause and order by the path column. If + breadth-first ordering is wanted, then specifying both + SEARCH and CYCLE can be useful. diff --git a/doc/src/sgml/ref/select.sgml b/doc/src/sgml/ref/select.sgml index c48ff6bc7e8ce..eb8b52495188a 100644 --- a/doc/src/sgml/ref/select.sgml +++ b/doc/src/sgml/ref/select.sgml @@ -73,6 +73,8 @@ SELECT [ ALL | DISTINCT [ ON ( expressionand with_query is: with_query_name [ ( column_name [, ...] ) ] AS [ [ NOT ] MATERIALIZED ] ( select | values | insert | update | delete ) + [ SEARCH { BREADTH | DEPTH } FIRST BY column_name [, ...] SET search_seq_col_name ] + [ CYCLE column_name [, ...] SET cycle_mark_col_name TO cycle_mark_value DEFAULT cycle_mark_default USING cycle_path_col_name ] TABLE [ ONLY ] table_name [ * ] @@ -276,6 +278,48 @@ TABLE [ ONLY ] table_name [ * ] queries that do not use recursion or forward references. + + The optional SEARCH clause computes a search + sequence column that can be used for ordering the results of a + recursive query in either breadth-first or depth-first order. The + supplied column name list specifies the row key that is to be used for + keeping track of visited rows. A column named + search_seq_col_name will be added to the result + column list of the WITH query. This column can be + ordered by in the outer query to achieve the respective ordering. See + for examples. + + + + The optional CYCLE clause is used to detect cycles in + recursive queries. The supplied column name list specifies the row key + that is to be used for keeping track of visited rows. A column named + cycle_mark_col_name will be added to the result + column list of the WITH query. This column will be set + to cycle_mark_value when a cycle has been + detected, else to cycle_mark_default. + Furthermore, processing of the recursive union will stop when a cycle has + been detected. cycle_mark_value and + cycle_mark_default must be constants and they + must be coercible to a common data type, and the data type must have an + inequality operator. (The SQL standard requires that they be character + strings, but PostgreSQL does not require that.) Furthermore, a column + named cycle_path_col_name will be added to the + result column list of the WITH query. This column is + used internally for tracking visited rows. See for examples. + + + + Both the SEARCH and the CYCLE clause + are only valid for recursive WITH queries. The + with_query must be a UNION + (or UNION ALL) of two SELECT (or + equivalent) commands (no nested UNIONs). If both + clauses are used, the column added by the SEARCH clause + appears before the columns added by the CYCLE clause. + + The primary query and the WITH queries are all (notionally) executed at the same time. This implies that the effects of diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 2140151a6afd1..132573362497e 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -2264,6 +2264,21 @@ find_expr_references_walker(Node *node, context->addrs); /* fall through to examine substructure */ } + else if (IsA(node, CTECycleClause)) + { + CTECycleClause *cc = (CTECycleClause *) node; + + if (OidIsValid(cc->cycle_mark_type)) + add_object_address(OCLASS_TYPE, cc->cycle_mark_type, 0, + context->addrs); + if (OidIsValid(cc->cycle_mark_collation)) + add_object_address(OCLASS_COLLATION, cc->cycle_mark_collation, 0, + context->addrs); + if (OidIsValid(cc->cycle_mark_neop)) + add_object_address(OCLASS_OPERATOR, cc->cycle_mark_neop, 0, + context->addrs); + /* fall through to examine substructure */ + } else if (IsA(node, Query)) { /* Recurse into RTE subquery or not-yet-planned sublink subquery */ diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 21e09c667a369..65bbc18ecbadb 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -2589,6 +2589,38 @@ _copyOnConflictClause(const OnConflictClause *from) return newnode; } +static CTESearchClause * +_copyCTESearchClause(const CTESearchClause *from) +{ + CTESearchClause *newnode = makeNode(CTESearchClause); + + COPY_NODE_FIELD(search_col_list); + COPY_SCALAR_FIELD(search_breadth_first); + COPY_STRING_FIELD(search_seq_column); + COPY_LOCATION_FIELD(location); + + return newnode; +} + +static CTECycleClause * +_copyCTECycleClause(const CTECycleClause *from) +{ + CTECycleClause *newnode = makeNode(CTECycleClause); + + COPY_NODE_FIELD(cycle_col_list); + COPY_STRING_FIELD(cycle_mark_column); + COPY_NODE_FIELD(cycle_mark_value); + COPY_NODE_FIELD(cycle_mark_default); + COPY_STRING_FIELD(cycle_path_column); + COPY_LOCATION_FIELD(location); + COPY_SCALAR_FIELD(cycle_mark_type); + COPY_SCALAR_FIELD(cycle_mark_typmod); + COPY_SCALAR_FIELD(cycle_mark_collation); + COPY_SCALAR_FIELD(cycle_mark_neop); + + return newnode; +} + static CommonTableExpr * _copyCommonTableExpr(const CommonTableExpr *from) { @@ -2598,6 +2630,8 @@ _copyCommonTableExpr(const CommonTableExpr *from) COPY_NODE_FIELD(aliascolnames); COPY_SCALAR_FIELD(ctematerialized); COPY_NODE_FIELD(ctequery); + COPY_NODE_FIELD(search_clause); + COPY_NODE_FIELD(cycle_clause); COPY_LOCATION_FIELD(location); COPY_SCALAR_FIELD(cterecursive); COPY_SCALAR_FIELD(cterefcount); @@ -5682,6 +5716,12 @@ copyObjectImpl(const void *from) case T_OnConflictClause: retval = _copyOnConflictClause(from); break; + case T_CTESearchClause: + retval = _copyCTESearchClause(from); + break; + case T_CTECycleClause: + retval = _copyCTECycleClause(from); + break; case T_CommonTableExpr: retval = _copyCommonTableExpr(from); break; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 5a5237c6c3099..c2d73626fcc22 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -2841,6 +2841,34 @@ _equalOnConflictClause(const OnConflictClause *a, const OnConflictClause *b) return true; } +static bool +_equalCTESearchClause(const CTESearchClause *a, const CTESearchClause *b) +{ + COMPARE_NODE_FIELD(search_col_list); + COMPARE_SCALAR_FIELD(search_breadth_first); + COMPARE_STRING_FIELD(search_seq_column); + COMPARE_LOCATION_FIELD(location); + + return true; +} + +static bool +_equalCTECycleClause(const CTECycleClause *a, const CTECycleClause *b) +{ + COMPARE_NODE_FIELD(cycle_col_list); + COMPARE_STRING_FIELD(cycle_mark_column); + COMPARE_NODE_FIELD(cycle_mark_value); + COMPARE_NODE_FIELD(cycle_mark_default); + COMPARE_STRING_FIELD(cycle_path_column); + COMPARE_LOCATION_FIELD(location); + COMPARE_SCALAR_FIELD(cycle_mark_type); + COMPARE_SCALAR_FIELD(cycle_mark_typmod); + COMPARE_SCALAR_FIELD(cycle_mark_collation); + COMPARE_SCALAR_FIELD(cycle_mark_neop); + + return true; +} + static bool _equalCommonTableExpr(const CommonTableExpr *a, const CommonTableExpr *b) { @@ -2848,6 +2876,8 @@ _equalCommonTableExpr(const CommonTableExpr *a, const CommonTableExpr *b) COMPARE_NODE_FIELD(aliascolnames); COMPARE_SCALAR_FIELD(ctematerialized); COMPARE_NODE_FIELD(ctequery); + COMPARE_NODE_FIELD(search_clause); + COMPARE_NODE_FIELD(cycle_clause); COMPARE_LOCATION_FIELD(location); COMPARE_SCALAR_FIELD(cterecursive); COMPARE_SCALAR_FIELD(cterefcount); @@ -3735,6 +3765,12 @@ equal(const void *a, const void *b) case T_OnConflictClause: retval = _equalOnConflictClause(a, b); break; + case T_CTESearchClause: + retval = _equalCTESearchClause(a, b); + break; + case T_CTECycleClause: + retval = _equalCTECycleClause(a, b); + break; case T_CommonTableExpr: retval = _equalCommonTableExpr(a, b); break; diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index 6be19916fced7..49357ac5c2da5 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -1566,6 +1566,12 @@ exprLocation(const Node *expr) case T_OnConflictClause: loc = ((const OnConflictClause *) expr)->location; break; + case T_CTESearchClause: + loc = ((const CTESearchClause *) expr)->location; + break; + case T_CTECycleClause: + loc = ((const CTECycleClause *) expr)->location; + break; case T_CommonTableExpr: loc = ((const CommonTableExpr *) expr)->location; break; @@ -1909,6 +1915,7 @@ expression_tree_walker(Node *node, case T_NextValueExpr: case T_RangeTblRef: case T_SortGroupClause: + case T_CTESearchClause: /* primitive node types with no expression subnodes */ break; case T_WithCheckOption: @@ -2148,6 +2155,16 @@ expression_tree_walker(Node *node, return true; } break; + case T_CTECycleClause: + { + CTECycleClause *cc = (CTECycleClause *) node; + + if (walker(cc->cycle_mark_value, context)) + return true; + if (walker(cc->cycle_mark_default, context)) + return true; + } + break; case T_CommonTableExpr: { CommonTableExpr *cte = (CommonTableExpr *) node; @@ -2156,7 +2173,13 @@ expression_tree_walker(Node *node, * Invoke the walker on the CTE's Query node, so it can * recurse into the sub-query if it wants to. */ - return walker(cte->ctequery, context); + if (walker(cte->ctequery, context)) + return true; + + if (walker(cte->search_clause, context)) + return true; + if (walker(cte->cycle_clause, context)) + return true; } break; case T_List: @@ -2615,6 +2638,7 @@ expression_tree_mutator(Node *node, case T_NextValueExpr: case T_RangeTblRef: case T_SortGroupClause: + case T_CTESearchClause: return (Node *) copyObject(node); case T_WithCheckOption: { @@ -3019,6 +3043,17 @@ expression_tree_mutator(Node *node, return (Node *) newnode; } break; + case T_CTECycleClause: + { + CTECycleClause *cc = (CTECycleClause *) node; + CTECycleClause *newnode; + + FLATCOPY(newnode, cc, CTECycleClause); + MUTATE(newnode->cycle_mark_value, cc->cycle_mark_value, Node *); + MUTATE(newnode->cycle_mark_default, cc->cycle_mark_default, Node *); + return (Node *) newnode; + } + break; case T_CommonTableExpr: { CommonTableExpr *cte = (CommonTableExpr *) node; @@ -3031,6 +3066,10 @@ expression_tree_mutator(Node *node, * recurse into the sub-query if it wants to. */ MUTATE(newnode->ctequery, cte->ctequery, Node *); + + MUTATE(newnode->search_clause, cte->search_clause, CTESearchClause *); + MUTATE(newnode->cycle_clause, cte->cycle_clause, CTECycleClause *); + return (Node *) newnode; } break; @@ -3913,6 +3952,7 @@ raw_expression_tree_walker(Node *node, } break; case T_CommonTableExpr: + /* search_clause and cycle_clause are not interesting here */ return walker(((CommonTableExpr *) node)->ctequery, context); default: elog(ERROR, "unrecognized node type: %d", diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 8392be6d44a33..fda732b4c2dfc 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -3077,6 +3077,34 @@ _outWithClause(StringInfo str, const WithClause *node) WRITE_LOCATION_FIELD(location); } +static void +_outCTESearchClause(StringInfo str, const CTESearchClause *node) +{ + WRITE_NODE_TYPE("CTESEARCHCLAUSE"); + + WRITE_NODE_FIELD(search_col_list); + WRITE_BOOL_FIELD(search_breadth_first); + WRITE_STRING_FIELD(search_seq_column); + WRITE_LOCATION_FIELD(location); +} + +static void +_outCTECycleClause(StringInfo str, const CTECycleClause *node) +{ + WRITE_NODE_TYPE("CTECYCLECLAUSE"); + + WRITE_NODE_FIELD(cycle_col_list); + WRITE_STRING_FIELD(cycle_mark_column); + WRITE_NODE_FIELD(cycle_mark_value); + WRITE_NODE_FIELD(cycle_mark_default); + WRITE_STRING_FIELD(cycle_path_column); + WRITE_LOCATION_FIELD(location); + WRITE_OID_FIELD(cycle_mark_type); + WRITE_INT_FIELD(cycle_mark_typmod); + WRITE_OID_FIELD(cycle_mark_collation); + WRITE_OID_FIELD(cycle_mark_neop); +} + static void _outCommonTableExpr(StringInfo str, const CommonTableExpr *node) { @@ -3086,6 +3114,8 @@ _outCommonTableExpr(StringInfo str, const CommonTableExpr *node) WRITE_NODE_FIELD(aliascolnames); WRITE_ENUM_FIELD(ctematerialized, CTEMaterialize); WRITE_NODE_FIELD(ctequery); + WRITE_NODE_FIELD(search_clause); + WRITE_NODE_FIELD(cycle_clause); WRITE_LOCATION_FIELD(location); WRITE_BOOL_FIELD(cterecursive); WRITE_INT_FIELD(cterefcount); @@ -4262,6 +4292,12 @@ outNode(StringInfo str, const void *obj) case T_WithClause: _outWithClause(str, obj); break; + case T_CTESearchClause: + _outCTESearchClause(str, obj); + break; + case T_CTECycleClause: + _outCTECycleClause(str, obj); + break; case T_CommonTableExpr: _outCommonTableExpr(str, obj); break; diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index d2c8d58070bcd..4388aae71d258 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -409,6 +409,44 @@ _readRowMarkClause(void) READ_DONE(); } +/* + * _readCTESearchClause + */ +static CTESearchClause * +_readCTESearchClause(void) +{ + READ_LOCALS(CTESearchClause); + + READ_NODE_FIELD(search_col_list); + READ_BOOL_FIELD(search_breadth_first); + READ_STRING_FIELD(search_seq_column); + READ_LOCATION_FIELD(location); + + READ_DONE(); +} + +/* + * _readCTECycleClause + */ +static CTECycleClause * +_readCTECycleClause(void) +{ + READ_LOCALS(CTECycleClause); + + READ_NODE_FIELD(cycle_col_list); + READ_STRING_FIELD(cycle_mark_column); + READ_NODE_FIELD(cycle_mark_value); + READ_NODE_FIELD(cycle_mark_default); + READ_STRING_FIELD(cycle_path_column); + READ_LOCATION_FIELD(location); + READ_OID_FIELD(cycle_mark_type); + READ_INT_FIELD(cycle_mark_typmod); + READ_OID_FIELD(cycle_mark_collation); + READ_OID_FIELD(cycle_mark_neop); + + READ_DONE(); +} + /* * _readCommonTableExpr */ @@ -421,6 +459,8 @@ _readCommonTableExpr(void) READ_NODE_FIELD(aliascolnames); READ_ENUM_FIELD(ctematerialized, CTEMaterialize); READ_NODE_FIELD(ctequery); + READ_NODE_FIELD(search_clause); + READ_NODE_FIELD(cycle_clause); READ_LOCATION_FIELD(location); READ_BOOL_FIELD(cterecursive); READ_INT_FIELD(cterefcount); @@ -2653,6 +2693,10 @@ parseNodeString(void) return_value = _readWindowClause(); else if (MATCH("ROWMARKCLAUSE", 13)) return_value = _readRowMarkClause(); + else if (MATCH("CTESEARCHCLAUSE", 15)) + return_value = _readCTESearchClause(); + else if (MATCH("CTECYCLECLAUSE", 14)) + return_value = _readCTECycleClause(); else if (MATCH("COMMONTABLEEXPR", 15)) return_value = _readCommonTableExpr(); else if (MATCH("SETOPERATIONSTMT", 16)) diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 65483892252f3..0f3a70c49a871 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -1809,6 +1809,33 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt) return qry; } +/* + * Make a SortGroupClause node for a SetOperationStmt's groupClauses + */ +SortGroupClause * +makeSortGroupClauseForSetOp(Oid rescoltype) +{ + SortGroupClause *grpcl = makeNode(SortGroupClause); + Oid sortop; + Oid eqop; + bool hashable; + + /* determine the eqop and optional sortop */ + get_sort_group_operators(rescoltype, + false, true, false, + &sortop, &eqop, NULL, + &hashable); + + /* we don't have a tlist yet, so can't assign sortgrouprefs */ + grpcl->tleSortGroupRef = 0; + grpcl->eqop = eqop; + grpcl->sortop = sortop; + grpcl->nulls_first = false; /* OK with or without sortop */ + grpcl->hashable = hashable; + + return grpcl; +} + /* * transformSetOperationTree * Recursively transform leaves and internal nodes of a set-op tree @@ -2109,31 +2136,15 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt, */ if (op->op != SETOP_UNION || !op->all) { - SortGroupClause *grpcl = makeNode(SortGroupClause); - Oid sortop; - Oid eqop; - bool hashable; ParseCallbackState pcbstate; setup_parser_errposition_callback(&pcbstate, pstate, bestlocation); - /* determine the eqop and optional sortop */ - get_sort_group_operators(rescoltype, - false, true, false, - &sortop, &eqop, NULL, - &hashable); + op->groupClauses = lappend(op->groupClauses, + makeSortGroupClauseForSetOp(rescoltype)); cancel_parser_errposition_callback(&pcbstate); - - /* we don't have a tlist yet, so can't assign sortgrouprefs */ - grpcl->tleSortGroupRef = 0; - grpcl->eqop = eqop; - grpcl->sortop = sortop; - grpcl->nulls_first = false; /* OK with or without sortop */ - grpcl->hashable = hashable; - - op->groupClauses = lappend(op->groupClauses, grpcl); } /* diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index b2f447bf9a277..dd72a9fc3c4bd 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -494,6 +494,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type row explicit_row implicit_row type_list array_expr_list %type case_expr case_arg when_clause case_default %type when_clause_list +%type opt_search_clause opt_cycle_clause %type sub_type opt_materialized %type NumericOnly %type NumericOnly_list @@ -625,7 +626,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); ASSERTION ASSIGNMENT ASYMMETRIC AT ATTACH ATTRIBUTE AUTHORIZATION BACKWARD BEFORE BEGIN_P BETWEEN BIGINT BINARY BIT - BOOLEAN_P BOTH BY + BOOLEAN_P BOTH BREADTH BY CACHE CALL CALLED CASCADE CASCADED CASE CAST CATALOG_P CHAIN CHAR_P CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE @@ -637,7 +638,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE DATA_P DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS - DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DEPENDS DESC + DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DEPENDS DEPTH DESC DETACH DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP @@ -11353,8 +11354,6 @@ simple_select: * WITH [ RECURSIVE ] [ (,...) ] * AS (query) [ SEARCH or CYCLE clause ] * - * We don't currently support the SEARCH or CYCLE clause. - * * Recognizing WITH_LA here allows a CTE to be named TIME or ORDINALITY. */ with_clause: @@ -11386,13 +11385,15 @@ cte_list: | cte_list ',' common_table_expr { $$ = lappend($1, $3); } ; -common_table_expr: name opt_name_list AS opt_materialized '(' PreparableStmt ')' +common_table_expr: name opt_name_list AS opt_materialized '(' PreparableStmt ')' opt_search_clause opt_cycle_clause { CommonTableExpr *n = makeNode(CommonTableExpr); n->ctename = $1; n->aliascolnames = $2; n->ctematerialized = $4; n->ctequery = $6; + n->search_clause = castNode(CTESearchClause, $8); + n->cycle_clause = castNode(CTECycleClause, $9); n->location = @1; $$ = (Node *) n; } @@ -11404,6 +11405,49 @@ opt_materialized: | /*EMPTY*/ { $$ = CTEMaterializeDefault; } ; +opt_search_clause: + SEARCH DEPTH FIRST_P BY columnList SET ColId + { + CTESearchClause *n = makeNode(CTESearchClause); + n->search_col_list = $5; + n->search_breadth_first = false; + n->search_seq_column = $7; + n->location = @1; + $$ = (Node *) n; + } + | SEARCH BREADTH FIRST_P BY columnList SET ColId + { + CTESearchClause *n = makeNode(CTESearchClause); + n->search_col_list = $5; + n->search_breadth_first = true; + n->search_seq_column = $7; + n->location = @1; + $$ = (Node *) n; + } + | /*EMPTY*/ + { + $$ = NULL; + } + ; + +opt_cycle_clause: + CYCLE columnList SET ColId TO AexprConst DEFAULT AexprConst USING ColId + { + CTECycleClause *n = makeNode(CTECycleClause); + n->cycle_col_list = $2; + n->cycle_mark_column = $4; + n->cycle_mark_value = $6; + n->cycle_mark_default = $8; + n->cycle_path_column = $10; + n->location = @1; + $$ = (Node *) n; + } + | /*EMPTY*/ + { + $$ = NULL; + } + ; + opt_with_clause: with_clause { $$ = $1; } | /*EMPTY*/ { $$ = NULL; } @@ -15222,6 +15266,7 @@ unreserved_keyword: | BACKWARD | BEFORE | BEGIN_P + | BREADTH | BY | CACHE | CALL @@ -15266,6 +15311,7 @@ unreserved_keyword: | DELIMITER | DELIMITERS | DEPENDS + | DEPTH | DETACH | DICTIONARY | DISABLE_P @@ -15733,6 +15779,7 @@ bare_label_keyword: | BIT | BOOLEAN_P | BOTH + | BREADTH | BY | CACHE | CALL @@ -15797,6 +15844,7 @@ bare_label_keyword: | DELIMITER | DELIMITERS | DEPENDS + | DEPTH | DESC | DETACH | DICTIONARY diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c index 588f005dd93bd..fd08b9eeff099 100644 --- a/src/backend/parser/parse_agg.c +++ b/src/backend/parser/parse_agg.c @@ -545,6 +545,10 @@ check_agglevels_and_constraints(ParseState *pstate, Node *expr) break; + case EXPR_KIND_CYCLE_MARK: + errkind = true; + break; + /* * There is intentionally no default: case here, so that the * compiler will warn if we add a new ParseExprKind without @@ -933,6 +937,9 @@ transformWindowFuncCall(ParseState *pstate, WindowFunc *wfunc, case EXPR_KIND_GENERATED_COLUMN: err = _("window functions are not allowed in column generation expressions"); break; + case EXPR_KIND_CYCLE_MARK: + errkind = true; + break; /* * There is intentionally no default: case here, so that the diff --git a/src/backend/parser/parse_cte.c b/src/backend/parser/parse_cte.c index 4e0029c58c903..f4f7041ead09d 100644 --- a/src/backend/parser/parse_cte.c +++ b/src/backend/parser/parse_cte.c @@ -18,9 +18,13 @@ #include "catalog/pg_type.h" #include "nodes/nodeFuncs.h" #include "parser/analyze.h" +#include "parser/parse_coerce.h" +#include "parser/parse_collate.h" #include "parser/parse_cte.h" +#include "parser/parse_expr.h" #include "utils/builtins.h" #include "utils/lsyscache.h" +#include "utils/typcache.h" /* Enumeration of contexts in which a self-reference is disallowed */ @@ -334,6 +338,195 @@ analyzeCTE(ParseState *pstate, CommonTableExpr *cte) if (lctyp != NULL || lctypmod != NULL || lccoll != NULL) /* shouldn't happen */ elog(ERROR, "wrong number of output columns in WITH"); } + + if (cte->search_clause || cte->cycle_clause) + { + Query *ctequery; + SetOperationStmt *sos; + + if (!cte->cterecursive) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("WITH query is not recursive"), + parser_errposition(pstate, cte->location))); + + /* + * SQL requires a WITH list element (CTE) to be "expandable" in order + * to allow a search or cycle clause. That is a stronger requirement + * than just being recursive. It basically means the query expression + * looks like + * + * non-recursive query UNION [ALL] recursive query + * + * and that the recursive query is not itself a set operation. + * + * As of this writing, most of these criteria are already satisfied by + * all recursive CTEs allowed by PostgreSQL. In the future, if + * further variants recursive CTEs are accepted, there might be + * further checks required here to determine what is "expandable". + */ + + ctequery = castNode(Query, cte->ctequery); + Assert(ctequery->setOperations); + sos = castNode(SetOperationStmt, ctequery->setOperations); + + /* + * This left side check is not required for expandability, but + * rewriteSearchAndCycle() doesn't currently have support for it, so + * we catch it here. + */ + if (!IsA(sos->larg, RangeTblRef)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("with a SEARCH or CYCLE clause, the left side of the UNION must be a SELECT"))); + + if (!IsA(sos->rarg, RangeTblRef)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("with a SEARCH or CYCLE clause, the right side of the UNION must be a SELECT"))); + } + + if (cte->search_clause) + { + ListCell *lc; + List *seen = NIL; + + foreach(lc, cte->search_clause->search_col_list) + { + Value *colname = lfirst(lc); + + if (!list_member(cte->ctecolnames, colname)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("search column \"%s\" not in WITH query column list", + strVal(colname)), + parser_errposition(pstate, cte->search_clause->location))); + + if (list_member(seen, colname)) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_COLUMN), + errmsg("search column \"%s\" specified more than once", + strVal(colname)), + parser_errposition(pstate, cte->search_clause->location))); + seen = lappend(seen, colname); + } + + if (list_member(cte->ctecolnames, makeString(cte->search_clause->search_seq_column))) + ereport(ERROR, + errcode(ERRCODE_SYNTAX_ERROR), + errmsg("search sequence column name \"%s\" already used in WITH query column list", + cte->search_clause->search_seq_column), + parser_errposition(pstate, cte->search_clause->location)); + } + + if (cte->cycle_clause) + { + ListCell *lc; + List *seen = NIL; + TypeCacheEntry *typentry; + Oid op; + + foreach(lc, cte->cycle_clause->cycle_col_list) + { + Value *colname = lfirst(lc); + + if (!list_member(cte->ctecolnames, colname)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("cycle column \"%s\" not in WITH query column list", + strVal(colname)), + parser_errposition(pstate, cte->cycle_clause->location))); + + if (list_member(seen, colname)) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_COLUMN), + errmsg("cycle column \"%s\" specified more than once", + strVal(colname)), + parser_errposition(pstate, cte->cycle_clause->location))); + seen = lappend(seen, colname); + } + + if (list_member(cte->ctecolnames, makeString(cte->cycle_clause->cycle_mark_column))) + ereport(ERROR, + errcode(ERRCODE_SYNTAX_ERROR), + errmsg("cycle mark column name \"%s\" already used in WITH query column list", + cte->cycle_clause->cycle_mark_column), + parser_errposition(pstate, cte->cycle_clause->location)); + + cte->cycle_clause->cycle_mark_value = transformExpr(pstate, cte->cycle_clause->cycle_mark_value, + EXPR_KIND_CYCLE_MARK); + cte->cycle_clause->cycle_mark_default = transformExpr(pstate, cte->cycle_clause->cycle_mark_default, + EXPR_KIND_CYCLE_MARK); + + if (list_member(cte->ctecolnames, makeString(cte->cycle_clause->cycle_path_column))) + ereport(ERROR, + errcode(ERRCODE_SYNTAX_ERROR), + errmsg("cycle path column name \"%s\" already used in WITH query column list", + cte->cycle_clause->cycle_path_column), + parser_errposition(pstate, cte->cycle_clause->location)); + + if (strcmp(cte->cycle_clause->cycle_mark_column, + cte->cycle_clause->cycle_path_column) == 0) + ereport(ERROR, + errcode(ERRCODE_SYNTAX_ERROR), + errmsg("cycle mark column name and cycle path column name are the same"), + parser_errposition(pstate, cte->cycle_clause->location)); + + cte->cycle_clause->cycle_mark_type = select_common_type(pstate, + list_make2(cte->cycle_clause->cycle_mark_value, + cte->cycle_clause->cycle_mark_default), + "CYCLE", NULL); + cte->cycle_clause->cycle_mark_value = coerce_to_common_type(pstate, + cte->cycle_clause->cycle_mark_value, + cte->cycle_clause->cycle_mark_type, + "CYCLE/SET/TO"); + cte->cycle_clause->cycle_mark_default = coerce_to_common_type(pstate, + cte->cycle_clause->cycle_mark_default, + cte->cycle_clause->cycle_mark_type, + "CYCLE/SET/DEFAULT"); + + cte->cycle_clause->cycle_mark_typmod = select_common_typmod(pstate, + list_make2(cte->cycle_clause->cycle_mark_value, + cte->cycle_clause->cycle_mark_default), + cte->cycle_clause->cycle_mark_type); + + cte->cycle_clause->cycle_mark_collation = select_common_collation(pstate, + list_make2(cte->cycle_clause->cycle_mark_value, + cte->cycle_clause->cycle_mark_default), + true); + + typentry = lookup_type_cache(cte->cycle_clause->cycle_mark_type, TYPECACHE_EQ_OPR); + if (!typentry->eq_opr) + ereport(ERROR, + errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("could not identify an equality operator for type %s", + format_type_be(cte->cycle_clause->cycle_mark_type))); + op = get_negator(typentry->eq_opr); + if (!op) + ereport(ERROR, + errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("could not identify an inequality operator for type %s", + format_type_be(cte->cycle_clause->cycle_mark_type))); + + cte->cycle_clause->cycle_mark_neop = op; + } + + if (cte->search_clause && cte->cycle_clause) + { + if (strcmp(cte->search_clause->search_seq_column, + cte->cycle_clause->cycle_mark_column) == 0) + ereport(ERROR, + errcode(ERRCODE_SYNTAX_ERROR), + errmsg("search sequence column name and cycle mark column name are the same"), + parser_errposition(pstate, cte->search_clause->location)); + + if (strcmp(cte->search_clause->search_seq_column, + cte->cycle_clause->cycle_path_column) == 0) + ereport(ERROR, + errcode(ERRCODE_SYNTAX_ERROR), + errmsg("search_sequence column name and cycle path column name are the same"), + parser_errposition(pstate, cte->search_clause->location)); + } } /* diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 379355f9bff0b..6c87783b2c788 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -507,6 +507,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) case EXPR_KIND_CALL_ARGUMENT: case EXPR_KIND_COPY_WHERE: case EXPR_KIND_GENERATED_COLUMN: + case EXPR_KIND_CYCLE_MARK: /* okay */ break; @@ -1723,6 +1724,7 @@ transformSubLink(ParseState *pstate, SubLink *sublink) case EXPR_KIND_RETURNING: case EXPR_KIND_VALUES: case EXPR_KIND_VALUES_SINGLE: + case EXPR_KIND_CYCLE_MARK: /* okay */ break; case EXPR_KIND_CHECK_CONSTRAINT: @@ -3044,6 +3046,8 @@ ParseExprKindName(ParseExprKind exprKind) return "WHERE"; case EXPR_KIND_GENERATED_COLUMN: return "GENERATED AS"; + case EXPR_KIND_CYCLE_MARK: + return "CYCLE"; /* * There is intentionally no default: case here, so that the diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 07d0013e84b19..37cebc7d829cc 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -2527,6 +2527,9 @@ check_srf_call_placement(ParseState *pstate, Node *last_srf, int location) case EXPR_KIND_GENERATED_COLUMN: err = _("set-returning functions are not allowed in column generation expressions"); break; + case EXPR_KIND_CYCLE_MARK: + errkind = true; + break; /* * There is intentionally no default: case here, so that the diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index e490043cf55f0..43db4e9af8bf6 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -2235,6 +2235,8 @@ addRangeTableEntryForCTE(ParseState *pstate, int numaliases; int varattno; ListCell *lc; + int n_dontexpand_columns = 0; + ParseNamespaceItem *psi; Assert(pstate != NULL); @@ -2267,9 +2269,9 @@ addRangeTableEntryForCTE(ParseState *pstate, parser_errposition(pstate, rv->location))); } - rte->coltypes = cte->ctecoltypes; - rte->coltypmods = cte->ctecoltypmods; - rte->colcollations = cte->ctecolcollations; + rte->coltypes = list_copy(cte->ctecoltypes); + rte->coltypmods = list_copy(cte->ctecoltypmods); + rte->colcollations = list_copy(cte->ctecolcollations); rte->alias = alias; if (alias) @@ -2294,6 +2296,34 @@ addRangeTableEntryForCTE(ParseState *pstate, rte->eref = eref; + if (cte->search_clause) + { + rte->eref->colnames = lappend(rte->eref->colnames, makeString(cte->search_clause->search_seq_column)); + if (cte->search_clause->search_breadth_first) + rte->coltypes = lappend_oid(rte->coltypes, RECORDOID); + else + rte->coltypes = lappend_oid(rte->coltypes, RECORDARRAYOID); + rte->coltypmods = lappend_int(rte->coltypmods, -1); + rte->colcollations = lappend_oid(rte->colcollations, InvalidOid); + + n_dontexpand_columns += 1; + } + + if (cte->cycle_clause) + { + rte->eref->colnames = lappend(rte->eref->colnames, makeString(cte->cycle_clause->cycle_mark_column)); + rte->coltypes = lappend_oid(rte->coltypes, cte->cycle_clause->cycle_mark_type); + rte->coltypmods = lappend_int(rte->coltypmods, cte->cycle_clause->cycle_mark_typmod); + rte->colcollations = lappend_oid(rte->colcollations, cte->cycle_clause->cycle_mark_collation); + + rte->eref->colnames = lappend(rte->eref->colnames, makeString(cte->cycle_clause->cycle_path_column)); + rte->coltypes = lappend_oid(rte->coltypes, RECORDARRAYOID); + rte->coltypmods = lappend_int(rte->coltypmods, -1); + rte->colcollations = lappend_oid(rte->colcollations, InvalidOid); + + n_dontexpand_columns += 2; + } + /* * Set flags and access permissions. * @@ -2321,9 +2351,19 @@ addRangeTableEntryForCTE(ParseState *pstate, * Build a ParseNamespaceItem, but don't add it to the pstate's namespace * list --- caller must do that if appropriate. */ - return buildNSItemFromLists(rte, list_length(pstate->p_rtable), + psi = buildNSItemFromLists(rte, list_length(pstate->p_rtable), rte->coltypes, rte->coltypmods, rte->colcollations); + + /* + * The columns added by search and cycle clauses are not included in star + * expansion in queries contained in the CTE. + */ + if (rte->ctelevelsup > 0) + for (int i = 0; i < n_dontexpand_columns; i++) + psi->p_nscolumns[list_length(psi->p_rte->eref->colnames) - 1 - i].p_dontexpand = true; + + return psi; } /* @@ -3008,7 +3048,11 @@ expandNSItemVars(ParseNamespaceItem *nsitem, const char *colname = strVal(colnameval); ParseNamespaceColumn *nscol = nsitem->p_nscolumns + colindex; - if (colname[0]) + if (nscol->p_dontexpand) + { + /* skip */ + } + else if (colname[0]) { Var *var; diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index 7eaa076771a95..51ecc16c42efe 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -399,8 +399,23 @@ markTargetListOrigin(ParseState *pstate, TargetEntry *tle, { CommonTableExpr *cte = GetCTEForRTE(pstate, rte, netlevelsup); TargetEntry *ste; + List *tl = GetCTETargetList(cte); + int extra_cols = 0; + + /* + * RTE for CTE will already have the search and cycle columns + * added, but the subquery won't, so skip looking those up. + */ + if (cte->search_clause) + extra_cols += 1; + if (cte->cycle_clause) + extra_cols += 2; + if (extra_cols && + attnum > list_length(tl) && + attnum <= list_length(tl) + extra_cols) + break; - ste = get_tle_by_resno(GetCTETargetList(cte), attnum); + ste = get_tle_by_resno(tl, attnum); if (ste == NULL || ste->resjunk) elog(ERROR, "CTE %s does not have attribute %d", rte->eref->aliasname, attnum); diff --git a/src/backend/rewrite/Makefile b/src/backend/rewrite/Makefile index b435b3e985c00..4680752e6a7f8 100644 --- a/src/backend/rewrite/Makefile +++ b/src/backend/rewrite/Makefile @@ -17,6 +17,7 @@ OBJS = \ rewriteHandler.o \ rewriteManip.o \ rewriteRemove.o \ + rewriteSearchCycle.o \ rewriteSupport.o \ rowsecurity.o diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index 0c7508a0d8bb6..0672f497c6b35 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -38,6 +38,7 @@ #include "rewrite/rewriteDefine.h" #include "rewrite/rewriteHandler.h" #include "rewrite/rewriteManip.h" +#include "rewrite/rewriteSearchCycle.h" #include "rewrite/rowsecurity.h" #include "utils/builtins.h" #include "utils/lsyscache.h" @@ -2079,6 +2080,23 @@ fireRIRrules(Query *parsetree, List *activeRIRs) int rt_index; ListCell *lc; + /* + * Expand SEARCH and CYCLE clauses in CTEs. + * + * This is just a convenient place to do this, since we are already + * looking at each Query. + */ + foreach(lc, parsetree->cteList) + { + CommonTableExpr *cte = lfirst_node(CommonTableExpr, lc); + + if (cte->search_clause || cte->cycle_clause) + { + cte = rewriteSearchAndCycle(cte); + lfirst(lc) = cte; + } + } + /* * don't try to convert this into a foreach loop, because rtable list can * get changed each time through... diff --git a/src/backend/rewrite/rewriteSearchCycle.c b/src/backend/rewrite/rewriteSearchCycle.c new file mode 100644 index 0000000000000..1a7d66fa6f991 --- /dev/null +++ b/src/backend/rewrite/rewriteSearchCycle.c @@ -0,0 +1,668 @@ +/*------------------------------------------------------------------------- + * + * rewriteSearchCycle.c + * Support for rewriting SEARCH and CYCLE clauses. + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/rewrite/rewriteSearchCycle.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "catalog/pg_operator_d.h" +#include "catalog/pg_type_d.h" +#include "nodes/makefuncs.h" +#include "nodes/pg_list.h" +#include "nodes/parsenodes.h" +#include "nodes/primnodes.h" +#include "parser/analyze.h" +#include "parser/parsetree.h" +#include "rewrite/rewriteManip.h" +#include "rewrite/rewriteSearchCycle.h" +#include "utils/fmgroids.h" + + +/*---------- + * Rewrite a CTE with SEARCH or CYCLE clause + * + * Consider a CTE like + * + * WITH RECURSIVE ctename (col1, col2, col3) AS ( + * query1 + * UNION [ALL] + * SELECT trosl FROM ctename + * ) + * + * With a search clause + * + * SEARCH BREADTH FIRST BY col1, col2 SET sqc + * + * the CTE is rewritten to + * + * WITH RECURSIVE ctename (col1, col2, col3, sqc) AS ( + * SELECT col1, col2, col3, -- original WITH column list + * ROW(0, col1, col2) -- initial row of search columns + * FROM (query1) "*TLOCRN*" (col1, col2, col3) + * UNION [ALL] + * SELECT col1, col2, col3, -- same as above + * ROW(sqc.depth + 1, col1, col2) -- count depth + * FROM (SELECT trosl, ctename.sqc FROM ctename) "*TROCRN*" (col1, col2, col3, sqc) + * ) + * + * (This isn't quite legal SQL: sqc.depth is meant to refer to the first + * column of sqc, which has a row type, but the field names are not defined + * here. Representing this properly in SQL would be more complicated (and the + * SQL standard actually does it in that more complicated way), but the + * internal representation allows us to construct it this way.) + * + * With a search caluse + * + * SEARCH DEPTH FIRST BY col1, col2 SET sqc + * + * the CTE is rewritten to + * + * WITH RECURSIVE ctename (col1, col2, col3, sqc) AS ( + * SELECT col1, col2, col3, -- original WITH column list + * ARRAY[ROW(col1, col2)] -- initial row of search columns + * FROM (query1) "*TLOCRN*" (col1, col2, col3) + * UNION [ALL] + * SELECT col1, col2, col3, -- same as above + * sqc || ARRAY[ROW(col1, col2)] -- record rows seen + * FROM (SELECT trosl, ctename.sqc FROM ctename) "*TROCRN*" (col1, col2, col3, sqc) + * ) + * + * With a cycle clause + * + * CYCLE col1, col2 SET cmc TO 'Y' DEFAULT 'N' USING cpa + * + * (cmc = cycle mark column, cpa = cycle path) the CTE is rewritten to + * + * WITH RECURSIVE ctename (col1, col2, col3, cmc, cpa) AS ( + * SELECT col1, col2, col3, -- original WITH column list + * 'N', -- cycle mark default + * ARRAY[ROW(col1, col2)] -- initial row of cycle columns + * FROM (query1) "*TLOCRN*" (col1, col2, col3) + * UNION [ALL] + * SELECT col1, col2, col3, -- same as above + * CASE WHEN ROW(col1, col2) = ANY (ARRAY[cpa]) THEN 'Y' ELSE 'N' END, -- compute cycle mark column + * cpa || ARRAY[ROW(col1, col2)] -- record rows seen + * FROM (SELECT trosl, ctename.cmc, ctename.cpa FROM ctename) "*TROCRN*" (col1, col2, col3, cmc, cpa) + * WHERE cmc <> 'Y' + * ) + * + * The expression to compute the cycle mark column in the right-hand query is + * written as + * + * CASE WHEN ROW(col1, col2) IN (SELECT p.* FROM TABLE(cpa) p) THEN cmv ELSE cmd END + * + * in the SQL standard, but in PostgreSQL we can use the scalar-array operator + * expression shown above. + * + * Also, in some of the cases where operators are shown above we actually + * directly produce the underlying function call. + * + * If both a search clause and a cycle clause is specified, then the search + * clause column is added before the cycle clause columns. + */ + +/* + * Make a RowExpr from the specified column names, which have to be among the + * output columns of the CTE. + */ +static RowExpr * +make_path_rowexpr(const CommonTableExpr *cte, const List *col_list) +{ + RowExpr *rowexpr; + ListCell *lc; + + rowexpr = makeNode(RowExpr); + rowexpr->row_typeid = RECORDOID; + rowexpr->row_format = COERCE_IMPLICIT_CAST; + rowexpr->location = -1; + + foreach(lc, col_list) + { + char *colname = strVal(lfirst(lc)); + + for (int i = 0; i < list_length(cte->ctecolnames); i++) + { + char *colname2 = strVal(list_nth(cte->ctecolnames, i)); + + if (strcmp(colname, colname2) == 0) + { + Var *var; + + var = makeVar(1, i + 1, + list_nth_oid(cte->ctecoltypes, i), + list_nth_int(cte->ctecoltypmods, i), + list_nth_oid(cte->ctecolcollations, i), + 0); + rowexpr->args = lappend(rowexpr->args, var); + rowexpr->colnames = lappend(rowexpr->colnames, makeString(colname)); + break; + } + } + } + + return rowexpr; +} + +/* + * Wrap a RowExpr in an ArrayExpr, for the initial search depth first or cycle + * row. + */ +static Expr * +make_path_initial_array(RowExpr *rowexpr) +{ + ArrayExpr *arr; + + arr = makeNode(ArrayExpr); + arr->array_typeid = RECORDARRAYOID; + arr->element_typeid = RECORDOID; + arr->location = -1; + arr->elements = list_make1(rowexpr); + + return (Expr *) arr; +} + +/* + * Make an array catenation expression like + * + * cpa || ARRAY[ROW(cols)] + * + * where the varattno of cpa is provided as path_varattno. + */ +static Expr * +make_path_cat_expr(RowExpr *rowexpr, AttrNumber path_varattno) +{ + ArrayExpr *arr; + FuncExpr *fexpr; + + arr = makeNode(ArrayExpr); + arr->array_typeid = RECORDARRAYOID; + arr->element_typeid = RECORDOID; + arr->location = -1; + arr->elements = list_make1(rowexpr); + + fexpr = makeFuncExpr(F_ARRAY_CAT, RECORDARRAYOID, + list_make2(makeVar(1, path_varattno, RECORDARRAYOID, -1, 0, 0), + arr), + InvalidOid, InvalidOid, COERCE_EXPLICIT_CALL); + + return (Expr *) fexpr; +} + +/* + * The real work happens here. + */ +CommonTableExpr * +rewriteSearchAndCycle(CommonTableExpr *cte) +{ + Query *ctequery; + SetOperationStmt *sos; + int rti1, + rti2; + RangeTblEntry *rte1, + *rte2, + *newrte; + Query *newq1, + *newq2; + Query *newsubquery; + RangeTblRef *rtr; + Oid search_seq_type = InvalidOid; + AttrNumber sqc_attno = InvalidAttrNumber; + AttrNumber cmc_attno = InvalidAttrNumber; + AttrNumber cpa_attno = InvalidAttrNumber; + TargetEntry *tle; + RowExpr *cycle_col_rowexpr = NULL; + RowExpr *search_col_rowexpr = NULL; + List *ewcl; + int cte_rtindex = -1; + + Assert(cte->search_clause || cte->cycle_clause); + + cte = copyObject(cte); + + ctequery = castNode(Query, cte->ctequery); + + /* + * The top level of the CTE's query should be a UNION. Find the two + * subqueries. + */ + Assert(ctequery->setOperations); + sos = castNode(SetOperationStmt, ctequery->setOperations); + Assert(sos->op == SETOP_UNION); + + rti1 = castNode(RangeTblRef, sos->larg)->rtindex; + rti2 = castNode(RangeTblRef, sos->rarg)->rtindex; + + rte1 = rt_fetch(rti1, ctequery->rtable); + rte2 = rt_fetch(rti2, ctequery->rtable); + + Assert(rte1->rtekind == RTE_SUBQUERY); + Assert(rte2->rtekind == RTE_SUBQUERY); + + /* + * We'll need this a few times later. + */ + if (cte->search_clause) + { + if (cte->search_clause->search_breadth_first) + search_seq_type = RECORDOID; + else + search_seq_type = RECORDARRAYOID; + } + + /* + * Attribute numbers of the added columns in the CTE's column list + */ + if (cte->search_clause) + sqc_attno = list_length(cte->ctecolnames) + 1; + if (cte->cycle_clause) + { + cmc_attno = list_length(cte->ctecolnames) + 1; + cpa_attno = list_length(cte->ctecolnames) + 2; + if (cte->search_clause) + { + cmc_attno++; + cpa_attno++; + } + } + + /* + * Make new left subquery + */ + newq1 = makeNode(Query); + newq1->commandType = CMD_SELECT; + newq1->canSetTag = true; + + newrte = makeNode(RangeTblEntry); + newrte->rtekind = RTE_SUBQUERY; + newrte->alias = makeAlias("*TLOCRN*", cte->ctecolnames); + newrte->eref = newrte->alias; + newsubquery = copyObject(rte1->subquery); + IncrementVarSublevelsUp((Node *) newsubquery, 1, 1); + newrte->subquery = newsubquery; + newrte->inFromCl = true; + newq1->rtable = list_make1(newrte); + + rtr = makeNode(RangeTblRef); + rtr->rtindex = 1; + newq1->jointree = makeFromExpr(list_make1(rtr), NULL); + + /* + * Make target list + */ + for (int i = 0; i < list_length(cte->ctecolnames); i++) + { + Var *var; + + var = makeVar(1, i + 1, + list_nth_oid(cte->ctecoltypes, i), + list_nth_int(cte->ctecoltypmods, i), + list_nth_oid(cte->ctecolcollations, i), + 0); + tle = makeTargetEntry((Expr *) var, i + 1, strVal(list_nth(cte->ctecolnames, i)), false); + tle->resorigtbl = castNode(TargetEntry, list_nth(rte1->subquery->targetList, i))->resorigtbl; + tle->resorigcol = castNode(TargetEntry, list_nth(rte1->subquery->targetList, i))->resorigcol; + newq1->targetList = lappend(newq1->targetList, tle); + } + + if (cte->search_clause) + { + Expr *texpr; + + search_col_rowexpr = make_path_rowexpr(cte, cte->search_clause->search_col_list); + if (cte->search_clause->search_breadth_first) + { + search_col_rowexpr->args = lcons(makeConst(INT8OID, -1, InvalidOid, sizeof(int64), + Int64GetDatum(0), false, FLOAT8PASSBYVAL), + search_col_rowexpr->args); + search_col_rowexpr->colnames = lcons(makeString("*DEPTH*"), search_col_rowexpr->colnames); + texpr = (Expr *) search_col_rowexpr; + } + else + texpr = make_path_initial_array(search_col_rowexpr); + tle = makeTargetEntry(texpr, + list_length(newq1->targetList) + 1, + cte->search_clause->search_seq_column, + false); + newq1->targetList = lappend(newq1->targetList, tle); + } + if (cte->cycle_clause) + { + tle = makeTargetEntry((Expr *) cte->cycle_clause->cycle_mark_default, + list_length(newq1->targetList) + 1, + cte->cycle_clause->cycle_mark_column, + false); + newq1->targetList = lappend(newq1->targetList, tle); + cycle_col_rowexpr = make_path_rowexpr(cte, cte->cycle_clause->cycle_col_list); + tle = makeTargetEntry(make_path_initial_array(cycle_col_rowexpr), + list_length(newq1->targetList) + 1, + cte->cycle_clause->cycle_path_column, + false); + newq1->targetList = lappend(newq1->targetList, tle); + } + + rte1->subquery = newq1; + + if (cte->search_clause) + { + rte1->eref->colnames = lappend(rte1->eref->colnames, makeString(cte->search_clause->search_seq_column)); + } + if (cte->cycle_clause) + { + rte1->eref->colnames = lappend(rte1->eref->colnames, makeString(cte->cycle_clause->cycle_mark_column)); + rte1->eref->colnames = lappend(rte1->eref->colnames, makeString(cte->cycle_clause->cycle_path_column)); + } + + /* + * Make new right subquery + */ + newq2 = makeNode(Query); + newq2->commandType = CMD_SELECT; + newq2->canSetTag = true; + + newrte = makeNode(RangeTblEntry); + newrte->rtekind = RTE_SUBQUERY; + ewcl = copyObject(cte->ctecolnames); + if (cte->search_clause) + { + ewcl = lappend(ewcl, makeString(cte->search_clause->search_seq_column)); + } + if (cte->cycle_clause) + { + ewcl = lappend(ewcl, makeString(cte->cycle_clause->cycle_mark_column)); + ewcl = lappend(ewcl, makeString(cte->cycle_clause->cycle_path_column)); + } + newrte->alias = makeAlias("*TROCRN*", ewcl); + newrte->eref = newrte->alias; + + /* + * Find the reference to our CTE in the range table + */ + for (int rti = 1; rti <= list_length(rte2->subquery->rtable); rti++) + { + RangeTblEntry *e = rt_fetch(rti, rte2->subquery->rtable); + + if (e->rtekind == RTE_CTE && strcmp(cte->ctename, e->ctename) == 0) + { + cte_rtindex = rti; + break; + } + } + Assert(cte_rtindex > 0); + + newsubquery = copyObject(rte2->subquery); + IncrementVarSublevelsUp((Node *) newsubquery, 1, 1); + + /* + * Add extra columns to target list of subquery of right subquery + */ + if (cte->search_clause) + { + Var *var; + + /* ctename.sqc */ + var = makeVar(cte_rtindex, sqc_attno, + search_seq_type, -1, InvalidOid, 0); + tle = makeTargetEntry((Expr *) var, + list_length(newsubquery->targetList) + 1, + cte->search_clause->search_seq_column, + false); + newsubquery->targetList = lappend(newsubquery->targetList, tle); + } + if (cte->cycle_clause) + { + Var *var; + + /* ctename.cmc */ + var = makeVar(cte_rtindex, cmc_attno, + cte->cycle_clause->cycle_mark_type, + cte->cycle_clause->cycle_mark_typmod, + cte->cycle_clause->cycle_mark_collation, 0); + tle = makeTargetEntry((Expr *) var, + list_length(newsubquery->targetList) + 1, + cte->cycle_clause->cycle_mark_column, + false); + newsubquery->targetList = lappend(newsubquery->targetList, tle); + + /* ctename.cpa */ + var = makeVar(cte_rtindex, cpa_attno, + RECORDARRAYOID, -1, InvalidOid, 0); + tle = makeTargetEntry((Expr *) var, + list_length(newsubquery->targetList) + 1, + cte->cycle_clause->cycle_path_column, + false); + newsubquery->targetList = lappend(newsubquery->targetList, tle); + } + + newrte->subquery = newsubquery; + newrte->inFromCl = true; + newq2->rtable = list_make1(newrte); + + rtr = makeNode(RangeTblRef); + rtr->rtindex = 1; + + if (cte->cycle_clause) + { + Expr *expr; + + /* + * Add cmc <> cmv condition + */ + expr = make_opclause(cte->cycle_clause->cycle_mark_neop, BOOLOID, false, + (Expr *) makeVar(1, cmc_attno, + cte->cycle_clause->cycle_mark_type, + cte->cycle_clause->cycle_mark_typmod, + cte->cycle_clause->cycle_mark_collation, 0), + (Expr *) cte->cycle_clause->cycle_mark_value, + InvalidOid, + cte->cycle_clause->cycle_mark_collation); + + newq2->jointree = makeFromExpr(list_make1(rtr), (Node *) expr); + } + else + newq2->jointree = makeFromExpr(list_make1(rtr), NULL); + + /* + * Make target list + */ + for (int i = 0; i < list_length(cte->ctecolnames); i++) + { + Var *var; + + var = makeVar(1, i + 1, + list_nth_oid(cte->ctecoltypes, i), + list_nth_int(cte->ctecoltypmods, i), + list_nth_oid(cte->ctecolcollations, i), + 0); + tle = makeTargetEntry((Expr *) var, i + 1, strVal(list_nth(cte->ctecolnames, i)), false); + tle->resorigtbl = castNode(TargetEntry, list_nth(rte2->subquery->targetList, i))->resorigtbl; + tle->resorigcol = castNode(TargetEntry, list_nth(rte2->subquery->targetList, i))->resorigcol; + newq2->targetList = lappend(newq2->targetList, tle); + } + + if (cte->search_clause) + { + Expr *texpr; + + if (cte->search_clause->search_breadth_first) + { + FieldSelect *fs; + FuncExpr *fexpr; + + /* + * ROW(sqc.depth + 1, cols) + */ + + search_col_rowexpr = copyObject(search_col_rowexpr); + + fs = makeNode(FieldSelect); + fs->arg = (Expr *) makeVar(1, sqc_attno, RECORDOID, -1, 0, 0); + fs->fieldnum = 1; + fs->resulttype = INT8OID; + fs->resulttypmod = -1; + + fexpr = makeFuncExpr(F_INT8INC, INT8OID, list_make1(fs), InvalidOid, InvalidOid, COERCE_EXPLICIT_CALL); + + lfirst(list_head(search_col_rowexpr->args)) = fexpr; + + texpr = (Expr *) search_col_rowexpr; + } + else + { + /* + * sqc || ARRAY[ROW(cols)] + */ + texpr = make_path_cat_expr(search_col_rowexpr, sqc_attno); + } + tle = makeTargetEntry(texpr, + list_length(newq2->targetList) + 1, + cte->search_clause->search_seq_column, + false); + newq2->targetList = lappend(newq2->targetList, tle); + } + + if (cte->cycle_clause) + { + ScalarArrayOpExpr *saoe; + CaseExpr *caseexpr; + CaseWhen *casewhen; + + /* + * CASE WHEN ROW(cols) = ANY (ARRAY[cpa]) THEN cmv ELSE cmd END + */ + + saoe = makeNode(ScalarArrayOpExpr); + saoe->location = -1; + saoe->opno = RECORD_EQ_OP; + saoe->useOr = true; + saoe->args = list_make2(cycle_col_rowexpr, + makeVar(1, cpa_attno, RECORDARRAYOID, -1, 0, 0)); + + caseexpr = makeNode(CaseExpr); + caseexpr->location = -1; + caseexpr->casetype = cte->cycle_clause->cycle_mark_type; + caseexpr->casecollid = cte->cycle_clause->cycle_mark_collation; + casewhen = makeNode(CaseWhen); + casewhen->location = -1; + casewhen->expr = (Expr *) saoe; + casewhen->result = (Expr *) cte->cycle_clause->cycle_mark_value; + caseexpr->args = list_make1(casewhen); + caseexpr->defresult = (Expr *) cte->cycle_clause->cycle_mark_default; + + tle = makeTargetEntry((Expr *) caseexpr, + list_length(newq2->targetList) + 1, + cte->cycle_clause->cycle_mark_column, + false); + newq2->targetList = lappend(newq2->targetList, tle); + + /* + * cpa || ARRAY[ROW(cols)] + */ + tle = makeTargetEntry(make_path_cat_expr(cycle_col_rowexpr, cpa_attno), + list_length(newq2->targetList) + 1, + cte->cycle_clause->cycle_path_column, + false); + newq2->targetList = lappend(newq2->targetList, tle); + } + + rte2->subquery = newq2; + + if (cte->search_clause) + { + rte2->eref->colnames = lappend(rte2->eref->colnames, makeString(cte->search_clause->search_seq_column)); + } + if (cte->cycle_clause) + { + rte2->eref->colnames = lappend(rte2->eref->colnames, makeString(cte->cycle_clause->cycle_mark_column)); + rte2->eref->colnames = lappend(rte2->eref->colnames, makeString(cte->cycle_clause->cycle_path_column)); + } + + /* + * Add the additional columns to the SetOperationStmt + */ + if (cte->search_clause) + { + sos->colTypes = lappend_oid(sos->colTypes, search_seq_type); + sos->colTypmods = lappend_int(sos->colTypmods, -1); + sos->colCollations = lappend_oid(sos->colCollations, InvalidOid); + if (!sos->all) + sos->groupClauses = lappend(sos->groupClauses, + makeSortGroupClauseForSetOp(search_seq_type)); + } + if (cte->cycle_clause) + { + sos->colTypes = lappend_oid(sos->colTypes, cte->cycle_clause->cycle_mark_type); + sos->colTypmods = lappend_int(sos->colTypmods, cte->cycle_clause->cycle_mark_typmod); + sos->colCollations = lappend_oid(sos->colCollations, cte->cycle_clause->cycle_mark_collation); + if (!sos->all) + sos->groupClauses = lappend(sos->groupClauses, + makeSortGroupClauseForSetOp(cte->cycle_clause->cycle_mark_type)); + + sos->colTypes = lappend_oid(sos->colTypes, RECORDARRAYOID); + sos->colTypmods = lappend_int(sos->colTypmods, -1); + sos->colCollations = lappend_oid(sos->colCollations, InvalidOid); + if (!sos->all) + sos->groupClauses = lappend(sos->groupClauses, + makeSortGroupClauseForSetOp(RECORDARRAYOID)); + } + + /* + * Add the additional columns to the CTE query's target list + */ + if (cte->search_clause) + { + ctequery->targetList = lappend(ctequery->targetList, + makeTargetEntry((Expr *) makeVar(1, sqc_attno, + search_seq_type, -1, InvalidOid, 0), + list_length(ctequery->targetList) + 1, + cte->search_clause->search_seq_column, + false)); + } + if (cte->cycle_clause) + { + ctequery->targetList = lappend(ctequery->targetList, + makeTargetEntry((Expr *) makeVar(1, cmc_attno, + cte->cycle_clause->cycle_mark_type, + cte->cycle_clause->cycle_mark_typmod, + cte->cycle_clause->cycle_mark_collation, 0), + list_length(ctequery->targetList) + 1, + cte->cycle_clause->cycle_mark_column, + false)); + ctequery->targetList = lappend(ctequery->targetList, + makeTargetEntry((Expr *) makeVar(1, cpa_attno, + RECORDARRAYOID, -1, InvalidOid, 0), + list_length(ctequery->targetList) + 1, + cte->cycle_clause->cycle_path_column, + false)); + } + + /* + * Add the additional columns to the CTE's output columns + */ + cte->ctecolnames = ewcl; + if (cte->search_clause) + { + cte->ctecoltypes = lappend_oid(cte->ctecoltypes, search_seq_type); + cte->ctecoltypmods = lappend_int(cte->ctecoltypmods, -1); + cte->ctecolcollations = lappend_oid(cte->ctecolcollations, InvalidOid); + } + if (cte->cycle_clause) + { + cte->ctecoltypes = lappend_oid(cte->ctecoltypes, cte->cycle_clause->cycle_mark_type); + cte->ctecoltypmods = lappend_int(cte->ctecoltypmods, cte->cycle_clause->cycle_mark_typmod); + cte->ctecolcollations = lappend_oid(cte->ctecolcollations, cte->cycle_clause->cycle_mark_collation); + + cte->ctecoltypes = lappend_oid(cte->ctecoltypes, RECORDARRAYOID); + cte->ctecoltypmods = lappend_int(cte->ctecoltypmods, -1); + cte->ctecolcollations = lappend_oid(cte->ctecolcollations, InvalidOid); + } + + return cte; +} diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 1a844bc4613f9..4a9244f4f665a 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -5168,6 +5168,53 @@ get_with_clause(Query *query, deparse_context *context) if (PRETTY_INDENT(context)) appendContextKeyword(context, "", 0, 0, 0); appendStringInfoChar(buf, ')'); + + if (cte->search_clause) + { + bool first = true; + ListCell *lc; + + appendStringInfo(buf, " SEARCH %s FIRST BY ", + cte->search_clause->search_breadth_first ? "BREADTH" : "DEPTH"); + + foreach(lc, cte->search_clause->search_col_list) + { + if (first) + first = false; + else + appendStringInfoString(buf, ", "); + appendStringInfoString(buf, + quote_identifier(strVal(lfirst(lc)))); + } + + appendStringInfo(buf, " SET %s", quote_identifier(cte->search_clause->search_seq_column)); + } + + if (cte->cycle_clause) + { + bool first = true; + ListCell *lc; + + appendStringInfoString(buf, " CYCLE "); + + foreach(lc, cte->cycle_clause->cycle_col_list) + { + if (first) + first = false; + else + appendStringInfoString(buf, ", "); + appendStringInfoString(buf, + quote_identifier(strVal(lfirst(lc)))); + } + + appendStringInfo(buf, " SET %s", quote_identifier(cte->cycle_clause->cycle_mark_column)); + appendStringInfoString(buf, " TO "); + get_rule_expr(cte->cycle_clause->cycle_mark_value, context, false); + appendStringInfoString(buf, " DEFAULT "); + get_rule_expr(cte->cycle_clause->cycle_mark_default, context, false); + appendStringInfo(buf, " USING %s", quote_identifier(cte->cycle_clause->cycle_path_column)); + } + sep = ", "; } diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index caed683ba92a8..40ae489c235c2 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -471,6 +471,8 @@ typedef enum NodeTag T_WithClause, T_InferClause, T_OnConflictClause, + T_CTESearchClause, + T_CTECycleClause, T_CommonTableExpr, T_RoleSpec, T_TriggerTransition, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 068c6ec440135..236832a2ca779 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1439,9 +1439,8 @@ typedef struct OnConflictClause /* * CommonTableExpr - * representation of WITH list element - * - * We don't currently support the SEARCH or CYCLE clause. */ + typedef enum CTEMaterialize { CTEMaterializeDefault, /* no option specified */ @@ -1449,6 +1448,31 @@ typedef enum CTEMaterialize CTEMaterializeNever /* NOT MATERIALIZED */ } CTEMaterialize; +typedef struct CTESearchClause +{ + NodeTag type; + List *search_col_list; + bool search_breadth_first; + char *search_seq_column; + int location; +} CTESearchClause; + +typedef struct CTECycleClause +{ + NodeTag type; + List *cycle_col_list; + char *cycle_mark_column; + Node *cycle_mark_value; + Node *cycle_mark_default; + char *cycle_path_column; + int location; + /* These fields are set during parse analysis: */ + Oid cycle_mark_type; /* common type of _value and _default */ + int cycle_mark_typmod; + Oid cycle_mark_collation; + Oid cycle_mark_neop; /* <> operator for type */ +} CTECycleClause; + typedef struct CommonTableExpr { NodeTag type; @@ -1457,6 +1481,8 @@ typedef struct CommonTableExpr CTEMaterialize ctematerialized; /* is this an optimization fence? */ /* SelectStmt/InsertStmt/etc before parse analysis, Query afterwards: */ Node *ctequery; /* the CTE's subquery */ + CTESearchClause *search_clause; + CTECycleClause *cycle_clause; int location; /* token location, or -1 if unknown */ /* These fields are set during parse analysis: */ bool cterecursive; /* is this CTE actually recursive? */ diff --git a/src/include/parser/analyze.h b/src/include/parser/analyze.h index fede4be820aa9..4a3c9686f9080 100644 --- a/src/include/parser/analyze.h +++ b/src/include/parser/analyze.h @@ -46,4 +46,6 @@ extern void applyLockingClause(Query *qry, Index rtindex, extern List *BuildOnConflictExcludedTargetlist(Relation targetrel, Index exclRelIndex); +extern SortGroupClause *makeSortGroupClauseForSetOp(Oid rescoltype); + #endif /* ANALYZE_H */ diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index 8c554e1f690d4..28083aaac9d7f 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -60,6 +60,7 @@ PG_KEYWORD("binary", BINARY, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("bit", BIT, COL_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("boolean", BOOLEAN_P, COL_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("both", BOTH, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("breadth", BREADTH, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("by", BY, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("cache", CACHE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("call", CALL, UNRESERVED_KEYWORD, BARE_LABEL) @@ -128,6 +129,7 @@ PG_KEYWORD("delete", DELETE_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("delimiter", DELIMITER, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("delimiters", DELIMITERS, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("depends", DEPENDS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("depth", DEPTH, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("desc", DESC, RESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("detach", DETACH, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD, BARE_LABEL) diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h index dfc214b06fb38..176b9f37c1f8f 100644 --- a/src/include/parser/parse_node.h +++ b/src/include/parser/parse_node.h @@ -78,6 +78,7 @@ typedef enum ParseExprKind EXPR_KIND_CALL_ARGUMENT, /* procedure argument in CALL */ EXPR_KIND_COPY_WHERE, /* WHERE condition in COPY FROM */ EXPR_KIND_GENERATED_COLUMN, /* generation expression for a column */ + EXPR_KIND_CYCLE_MARK, /* cycle mark value */ } ParseExprKind; @@ -294,6 +295,7 @@ struct ParseNamespaceColumn Oid p_varcollid; /* OID of collation, or InvalidOid */ Index p_varnosyn; /* rangetable index of syntactic referent */ AttrNumber p_varattnosyn; /* attribute number of syntactic referent */ + bool p_dontexpand; /* not included in star expansion */ }; /* Support for parser_errposition_callback function */ diff --git a/src/include/rewrite/rewriteSearchCycle.h b/src/include/rewrite/rewriteSearchCycle.h new file mode 100644 index 0000000000000..257fb7cdab744 --- /dev/null +++ b/src/include/rewrite/rewriteSearchCycle.h @@ -0,0 +1,21 @@ +/*------------------------------------------------------------------------- + * + * rewriteSearchCycle.h + * Support for rewriting SEARCH and CYCLE clauses. + * + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/rewrite/rewriteSearchCycle.h + * + *------------------------------------------------------------------------- + */ +#ifndef REWRITESEARCHCYCLE_H +#define REWRITESEARCHCYCLE_H + +#include "nodes/parsenodes.h" + +extern CommonTableExpr *rewriteSearchAndCycle(CommonTableExpr *cte); + +#endif /* REWRITESEARCHCYCLE_H */ diff --git a/src/test/regress/expected/with.out b/src/test/regress/expected/with.out index 9429e9fd28f08..c519a61c4fe79 100644 --- a/src/test/regress/expected/with.out +++ b/src/test/regress/expected/with.out @@ -577,6 +577,190 @@ SELECT t1.id, t2.path, t2 FROM t AS t1 JOIN t AS t2 ON 16 | {3,7,11,16} | (16,"{3,7,11,16}") (16 rows) +-- SEARCH clause +create temp table graph0( f int, t int, label text ); +insert into graph0 values + (1, 2, 'arc 1 -> 2'), + (1, 3, 'arc 1 -> 3'), + (2, 3, 'arc 2 -> 3'), + (1, 4, 'arc 1 -> 4'), + (4, 5, 'arc 4 -> 5'); +with recursive search_graph(f, t, label) as ( + select * from graph0 g + union all + select g.* + from graph0 g, search_graph sg + where g.f = sg.t +) search depth first by f, t set seq +select * from search_graph order by seq; + f | t | label | seq +---+---+------------+------------------- + 1 | 2 | arc 1 -> 2 | {"(1,2)"} + 2 | 3 | arc 2 -> 3 | {"(1,2)","(2,3)"} + 1 | 3 | arc 1 -> 3 | {"(1,3)"} + 1 | 4 | arc 1 -> 4 | {"(1,4)"} + 4 | 5 | arc 4 -> 5 | {"(1,4)","(4,5)"} + 2 | 3 | arc 2 -> 3 | {"(2,3)"} + 4 | 5 | arc 4 -> 5 | {"(4,5)"} +(7 rows) + +with recursive search_graph(f, t, label) as ( + select * from graph0 g + union distinct + select g.* + from graph0 g, search_graph sg + where g.f = sg.t +) search depth first by f, t set seq +select * from search_graph order by seq; + f | t | label | seq +---+---+------------+------------------- + 1 | 2 | arc 1 -> 2 | {"(1,2)"} + 2 | 3 | arc 2 -> 3 | {"(1,2)","(2,3)"} + 1 | 3 | arc 1 -> 3 | {"(1,3)"} + 1 | 4 | arc 1 -> 4 | {"(1,4)"} + 4 | 5 | arc 4 -> 5 | {"(1,4)","(4,5)"} + 2 | 3 | arc 2 -> 3 | {"(2,3)"} + 4 | 5 | arc 4 -> 5 | {"(4,5)"} +(7 rows) + +with recursive search_graph(f, t, label) as ( + select * from graph0 g + union all + select g.* + from graph0 g, search_graph sg + where g.f = sg.t +) search breadth first by f, t set seq +select * from search_graph order by seq; + f | t | label | seq +---+---+------------+--------- + 1 | 2 | arc 1 -> 2 | (0,1,2) + 1 | 3 | arc 1 -> 3 | (0,1,3) + 1 | 4 | arc 1 -> 4 | (0,1,4) + 2 | 3 | arc 2 -> 3 | (0,2,3) + 4 | 5 | arc 4 -> 5 | (0,4,5) + 2 | 3 | arc 2 -> 3 | (1,2,3) + 4 | 5 | arc 4 -> 5 | (1,4,5) +(7 rows) + +with recursive search_graph(f, t, label) as ( + select * from graph0 g + union distinct + select g.* + from graph0 g, search_graph sg + where g.f = sg.t +) search breadth first by f, t set seq +select * from search_graph order by seq; + f | t | label | seq +---+---+------------+--------- + 1 | 2 | arc 1 -> 2 | (0,1,2) + 1 | 3 | arc 1 -> 3 | (0,1,3) + 1 | 4 | arc 1 -> 4 | (0,1,4) + 2 | 3 | arc 2 -> 3 | (0,2,3) + 4 | 5 | arc 4 -> 5 | (0,4,5) + 2 | 3 | arc 2 -> 3 | (1,2,3) + 4 | 5 | arc 4 -> 5 | (1,4,5) +(7 rows) + +-- various syntax errors +with recursive search_graph(f, t, label) as ( + select * from graph0 g + union all + select g.* + from graph0 g, search_graph sg + where g.f = sg.t +) search depth first by foo, tar set seq +select * from search_graph; +ERROR: search column "foo" not in WITH query column list +LINE 7: ) search depth first by foo, tar set seq + ^ +with recursive search_graph(f, t, label) as ( + select * from graph0 g + union all + select g.* + from graph0 g, search_graph sg + where g.f = sg.t +) search depth first by f, t set label +select * from search_graph; +ERROR: search sequence column name "label" already used in WITH query column list +LINE 7: ) search depth first by f, t set label + ^ +with recursive search_graph(f, t, label) as ( + select * from graph0 g + union all + select g.* + from graph0 g, search_graph sg + where g.f = sg.t +) search depth first by f, t, f set seq +select * from search_graph; +ERROR: search column "f" specified more than once +LINE 7: ) search depth first by f, t, f set seq + ^ +with recursive search_graph(f, t, label) as ( + select * from graph0 g + union all + select * from graph0 g + union all + select g.* + from graph0 g, search_graph sg + where g.f = sg.t +) search depth first by f, t set seq +select * from search_graph order by seq; +ERROR: with a SEARCH or CYCLE clause, the left side of the UNION must be a SELECT +with recursive search_graph(f, t, label) as ( + select * from graph0 g + union all + (select * from graph0 g + union all + select g.* + from graph0 g, search_graph sg + where g.f = sg.t) +) search depth first by f, t set seq +select * from search_graph order by seq; +ERROR: with a SEARCH or CYCLE clause, the right side of the UNION must be a SELECT +-- test ruleutils and view expansion +create temp view v_search as +with recursive search_graph(f, t, label) as ( + select * from graph0 g + union all + select g.* + from graph0 g, search_graph sg + where g.f = sg.t +) search depth first by f, t set seq +select f, t, label from search_graph; +select pg_get_viewdef('v_search'); + pg_get_viewdef +------------------------------------------------ + WITH RECURSIVE search_graph(f, t, label) AS (+ + SELECT g.f, + + g.t, + + g.label + + FROM graph0 g + + UNION ALL + + SELECT g.f, + + g.t, + + g.label + + FROM graph0 g, + + search_graph sg + + WHERE (g.f = sg.t) + + ) SEARCH DEPTH FIRST BY f, t SET seq + + SELECT search_graph.f, + + search_graph.t, + + search_graph.label + + FROM search_graph; +(1 row) + +select * from v_search; + f | t | label +---+---+------------ + 1 | 2 | arc 1 -> 2 + 1 | 3 | arc 1 -> 3 + 2 | 3 | arc 2 -> 3 + 1 | 4 | arc 1 -> 4 + 4 | 5 | arc 4 -> 5 + 2 | 3 | arc 2 -> 3 + 4 | 5 | arc 4 -> 5 +(7 rows) + -- -- test cycle detection -- @@ -701,6 +885,380 @@ select * from search_graph order by path; 5 | 1 | arc 5 -> 1 | t | {"(5,1)","(1,4)","(4,5)","(5,1)"} (25 rows) +-- CYCLE clause +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) cycle f, t set is_cycle to true default false using path +select * from search_graph; + f | t | label | is_cycle | path +---+---+------------+----------+------------------------------------------- + 1 | 2 | arc 1 -> 2 | f | {"(1,2)"} + 1 | 3 | arc 1 -> 3 | f | {"(1,3)"} + 2 | 3 | arc 2 -> 3 | f | {"(2,3)"} + 1 | 4 | arc 1 -> 4 | f | {"(1,4)"} + 4 | 5 | arc 4 -> 5 | f | {"(4,5)"} + 5 | 1 | arc 5 -> 1 | f | {"(5,1)"} + 1 | 2 | arc 1 -> 2 | f | {"(5,1)","(1,2)"} + 1 | 3 | arc 1 -> 3 | f | {"(5,1)","(1,3)"} + 1 | 4 | arc 1 -> 4 | f | {"(5,1)","(1,4)"} + 2 | 3 | arc 2 -> 3 | f | {"(1,2)","(2,3)"} + 4 | 5 | arc 4 -> 5 | f | {"(1,4)","(4,5)"} + 5 | 1 | arc 5 -> 1 | f | {"(4,5)","(5,1)"} + 1 | 2 | arc 1 -> 2 | f | {"(4,5)","(5,1)","(1,2)"} + 1 | 3 | arc 1 -> 3 | f | {"(4,5)","(5,1)","(1,3)"} + 1 | 4 | arc 1 -> 4 | f | {"(4,5)","(5,1)","(1,4)"} + 2 | 3 | arc 2 -> 3 | f | {"(5,1)","(1,2)","(2,3)"} + 4 | 5 | arc 4 -> 5 | f | {"(5,1)","(1,4)","(4,5)"} + 5 | 1 | arc 5 -> 1 | f | {"(1,4)","(4,5)","(5,1)"} + 1 | 2 | arc 1 -> 2 | f | {"(1,4)","(4,5)","(5,1)","(1,2)"} + 1 | 3 | arc 1 -> 3 | f | {"(1,4)","(4,5)","(5,1)","(1,3)"} + 1 | 4 | arc 1 -> 4 | t | {"(1,4)","(4,5)","(5,1)","(1,4)"} + 2 | 3 | arc 2 -> 3 | f | {"(4,5)","(5,1)","(1,2)","(2,3)"} + 4 | 5 | arc 4 -> 5 | t | {"(4,5)","(5,1)","(1,4)","(4,5)"} + 5 | 1 | arc 5 -> 1 | t | {"(5,1)","(1,4)","(4,5)","(5,1)"} + 2 | 3 | arc 2 -> 3 | f | {"(1,4)","(4,5)","(5,1)","(1,2)","(2,3)"} +(25 rows) + +with recursive search_graph(f, t, label) as ( + select * from graph g + union distinct + select g.* + from graph g, search_graph sg + where g.f = sg.t +) cycle f, t set is_cycle to 'Y' default 'N' using path +select * from search_graph; + f | t | label | is_cycle | path +---+---+------------+----------+------------------------------------------- + 1 | 2 | arc 1 -> 2 | N | {"(1,2)"} + 1 | 3 | arc 1 -> 3 | N | {"(1,3)"} + 2 | 3 | arc 2 -> 3 | N | {"(2,3)"} + 1 | 4 | arc 1 -> 4 | N | {"(1,4)"} + 4 | 5 | arc 4 -> 5 | N | {"(4,5)"} + 5 | 1 | arc 5 -> 1 | N | {"(5,1)"} + 1 | 2 | arc 1 -> 2 | N | {"(5,1)","(1,2)"} + 1 | 3 | arc 1 -> 3 | N | {"(5,1)","(1,3)"} + 1 | 4 | arc 1 -> 4 | N | {"(5,1)","(1,4)"} + 2 | 3 | arc 2 -> 3 | N | {"(1,2)","(2,3)"} + 4 | 5 | arc 4 -> 5 | N | {"(1,4)","(4,5)"} + 5 | 1 | arc 5 -> 1 | N | {"(4,5)","(5,1)"} + 1 | 2 | arc 1 -> 2 | N | {"(4,5)","(5,1)","(1,2)"} + 1 | 3 | arc 1 -> 3 | N | {"(4,5)","(5,1)","(1,3)"} + 1 | 4 | arc 1 -> 4 | N | {"(4,5)","(5,1)","(1,4)"} + 2 | 3 | arc 2 -> 3 | N | {"(5,1)","(1,2)","(2,3)"} + 4 | 5 | arc 4 -> 5 | N | {"(5,1)","(1,4)","(4,5)"} + 5 | 1 | arc 5 -> 1 | N | {"(1,4)","(4,5)","(5,1)"} + 1 | 2 | arc 1 -> 2 | N | {"(1,4)","(4,5)","(5,1)","(1,2)"} + 1 | 3 | arc 1 -> 3 | N | {"(1,4)","(4,5)","(5,1)","(1,3)"} + 1 | 4 | arc 1 -> 4 | Y | {"(1,4)","(4,5)","(5,1)","(1,4)"} + 2 | 3 | arc 2 -> 3 | N | {"(4,5)","(5,1)","(1,2)","(2,3)"} + 4 | 5 | arc 4 -> 5 | Y | {"(4,5)","(5,1)","(1,4)","(4,5)"} + 5 | 1 | arc 5 -> 1 | Y | {"(5,1)","(1,4)","(4,5)","(5,1)"} + 2 | 3 | arc 2 -> 3 | N | {"(1,4)","(4,5)","(5,1)","(1,2)","(2,3)"} +(25 rows) + +-- multiple CTEs +with recursive +graph(f, t, label) as ( + values (1, 2, 'arc 1 -> 2'), + (1, 3, 'arc 1 -> 3'), + (2, 3, 'arc 2 -> 3'), + (1, 4, 'arc 1 -> 4'), + (4, 5, 'arc 4 -> 5'), + (5, 1, 'arc 5 -> 1') +), +search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) cycle f, t set is_cycle to true default false using path +select f, t, label from search_graph; + f | t | label +---+---+------------ + 1 | 2 | arc 1 -> 2 + 1 | 3 | arc 1 -> 3 + 2 | 3 | arc 2 -> 3 + 1 | 4 | arc 1 -> 4 + 4 | 5 | arc 4 -> 5 + 5 | 1 | arc 5 -> 1 + 2 | 3 | arc 2 -> 3 + 4 | 5 | arc 4 -> 5 + 5 | 1 | arc 5 -> 1 + 1 | 4 | arc 1 -> 4 + 1 | 3 | arc 1 -> 3 + 1 | 2 | arc 1 -> 2 + 5 | 1 | arc 5 -> 1 + 1 | 4 | arc 1 -> 4 + 1 | 3 | arc 1 -> 3 + 1 | 2 | arc 1 -> 2 + 4 | 5 | arc 4 -> 5 + 2 | 3 | arc 2 -> 3 + 1 | 4 | arc 1 -> 4 + 1 | 3 | arc 1 -> 3 + 1 | 2 | arc 1 -> 2 + 4 | 5 | arc 4 -> 5 + 2 | 3 | arc 2 -> 3 + 5 | 1 | arc 5 -> 1 + 2 | 3 | arc 2 -> 3 +(25 rows) + +-- star expansion +with recursive a as ( + select 1 as b + union all + select * from a +) cycle b set c to true default false using p +select * from a; + b | c | p +---+---+----------- + 1 | f | {(1)} + 1 | t | {(1),(1)} +(2 rows) + +-- search+cycle +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) search depth first by f, t set seq + cycle f, t set is_cycle to true default false using path +select * from search_graph; + f | t | label | seq | is_cycle | path +---+---+------------+-------------------------------------------+----------+------------------------------------------- + 1 | 2 | arc 1 -> 2 | {"(1,2)"} | f | {"(1,2)"} + 1 | 3 | arc 1 -> 3 | {"(1,3)"} | f | {"(1,3)"} + 2 | 3 | arc 2 -> 3 | {"(2,3)"} | f | {"(2,3)"} + 1 | 4 | arc 1 -> 4 | {"(1,4)"} | f | {"(1,4)"} + 4 | 5 | arc 4 -> 5 | {"(4,5)"} | f | {"(4,5)"} + 5 | 1 | arc 5 -> 1 | {"(5,1)"} | f | {"(5,1)"} + 1 | 2 | arc 1 -> 2 | {"(5,1)","(1,2)"} | f | {"(5,1)","(1,2)"} + 1 | 3 | arc 1 -> 3 | {"(5,1)","(1,3)"} | f | {"(5,1)","(1,3)"} + 1 | 4 | arc 1 -> 4 | {"(5,1)","(1,4)"} | f | {"(5,1)","(1,4)"} + 2 | 3 | arc 2 -> 3 | {"(1,2)","(2,3)"} | f | {"(1,2)","(2,3)"} + 4 | 5 | arc 4 -> 5 | {"(1,4)","(4,5)"} | f | {"(1,4)","(4,5)"} + 5 | 1 | arc 5 -> 1 | {"(4,5)","(5,1)"} | f | {"(4,5)","(5,1)"} + 1 | 2 | arc 1 -> 2 | {"(4,5)","(5,1)","(1,2)"} | f | {"(4,5)","(5,1)","(1,2)"} + 1 | 3 | arc 1 -> 3 | {"(4,5)","(5,1)","(1,3)"} | f | {"(4,5)","(5,1)","(1,3)"} + 1 | 4 | arc 1 -> 4 | {"(4,5)","(5,1)","(1,4)"} | f | {"(4,5)","(5,1)","(1,4)"} + 2 | 3 | arc 2 -> 3 | {"(5,1)","(1,2)","(2,3)"} | f | {"(5,1)","(1,2)","(2,3)"} + 4 | 5 | arc 4 -> 5 | {"(5,1)","(1,4)","(4,5)"} | f | {"(5,1)","(1,4)","(4,5)"} + 5 | 1 | arc 5 -> 1 | {"(1,4)","(4,5)","(5,1)"} | f | {"(1,4)","(4,5)","(5,1)"} + 1 | 2 | arc 1 -> 2 | {"(1,4)","(4,5)","(5,1)","(1,2)"} | f | {"(1,4)","(4,5)","(5,1)","(1,2)"} + 1 | 3 | arc 1 -> 3 | {"(1,4)","(4,5)","(5,1)","(1,3)"} | f | {"(1,4)","(4,5)","(5,1)","(1,3)"} + 1 | 4 | arc 1 -> 4 | {"(1,4)","(4,5)","(5,1)","(1,4)"} | t | {"(1,4)","(4,5)","(5,1)","(1,4)"} + 2 | 3 | arc 2 -> 3 | {"(4,5)","(5,1)","(1,2)","(2,3)"} | f | {"(4,5)","(5,1)","(1,2)","(2,3)"} + 4 | 5 | arc 4 -> 5 | {"(4,5)","(5,1)","(1,4)","(4,5)"} | t | {"(4,5)","(5,1)","(1,4)","(4,5)"} + 5 | 1 | arc 5 -> 1 | {"(5,1)","(1,4)","(4,5)","(5,1)"} | t | {"(5,1)","(1,4)","(4,5)","(5,1)"} + 2 | 3 | arc 2 -> 3 | {"(1,4)","(4,5)","(5,1)","(1,2)","(2,3)"} | f | {"(1,4)","(4,5)","(5,1)","(1,2)","(2,3)"} +(25 rows) + +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) search breadth first by f, t set seq + cycle f, t set is_cycle to true default false using path +select * from search_graph; + f | t | label | seq | is_cycle | path +---+---+------------+---------+----------+------------------------------------------- + 1 | 2 | arc 1 -> 2 | (0,1,2) | f | {"(1,2)"} + 1 | 3 | arc 1 -> 3 | (0,1,3) | f | {"(1,3)"} + 2 | 3 | arc 2 -> 3 | (0,2,3) | f | {"(2,3)"} + 1 | 4 | arc 1 -> 4 | (0,1,4) | f | {"(1,4)"} + 4 | 5 | arc 4 -> 5 | (0,4,5) | f | {"(4,5)"} + 5 | 1 | arc 5 -> 1 | (0,5,1) | f | {"(5,1)"} + 1 | 2 | arc 1 -> 2 | (1,1,2) | f | {"(5,1)","(1,2)"} + 1 | 3 | arc 1 -> 3 | (1,1,3) | f | {"(5,1)","(1,3)"} + 1 | 4 | arc 1 -> 4 | (1,1,4) | f | {"(5,1)","(1,4)"} + 2 | 3 | arc 2 -> 3 | (1,2,3) | f | {"(1,2)","(2,3)"} + 4 | 5 | arc 4 -> 5 | (1,4,5) | f | {"(1,4)","(4,5)"} + 5 | 1 | arc 5 -> 1 | (1,5,1) | f | {"(4,5)","(5,1)"} + 1 | 2 | arc 1 -> 2 | (2,1,2) | f | {"(4,5)","(5,1)","(1,2)"} + 1 | 3 | arc 1 -> 3 | (2,1,3) | f | {"(4,5)","(5,1)","(1,3)"} + 1 | 4 | arc 1 -> 4 | (2,1,4) | f | {"(4,5)","(5,1)","(1,4)"} + 2 | 3 | arc 2 -> 3 | (2,2,3) | f | {"(5,1)","(1,2)","(2,3)"} + 4 | 5 | arc 4 -> 5 | (2,4,5) | f | {"(5,1)","(1,4)","(4,5)"} + 5 | 1 | arc 5 -> 1 | (2,5,1) | f | {"(1,4)","(4,5)","(5,1)"} + 1 | 2 | arc 1 -> 2 | (3,1,2) | f | {"(1,4)","(4,5)","(5,1)","(1,2)"} + 1 | 3 | arc 1 -> 3 | (3,1,3) | f | {"(1,4)","(4,5)","(5,1)","(1,3)"} + 1 | 4 | arc 1 -> 4 | (3,1,4) | t | {"(1,4)","(4,5)","(5,1)","(1,4)"} + 2 | 3 | arc 2 -> 3 | (3,2,3) | f | {"(4,5)","(5,1)","(1,2)","(2,3)"} + 4 | 5 | arc 4 -> 5 | (3,4,5) | t | {"(4,5)","(5,1)","(1,4)","(4,5)"} + 5 | 1 | arc 5 -> 1 | (3,5,1) | t | {"(5,1)","(1,4)","(4,5)","(5,1)"} + 2 | 3 | arc 2 -> 3 | (4,2,3) | f | {"(1,4)","(4,5)","(5,1)","(1,2)","(2,3)"} +(25 rows) + +-- various syntax errors +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) cycle foo, tar set is_cycle to true default false using path +select * from search_graph; +ERROR: cycle column "foo" not in WITH query column list +LINE 7: ) cycle foo, tar set is_cycle to true default false using pa... + ^ +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) cycle f, t set is_cycle to true default 55 using path +select * from search_graph; +ERROR: CYCLE types boolean and integer cannot be matched +LINE 7: ) cycle f, t set is_cycle to true default 55 using path + ^ +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) cycle f, t set is_cycle to point '(1,1)' default point '(0,0)' using path +select * from search_graph; +ERROR: could not identify an equality operator for type point +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) cycle f, t set label to true default false using path +select * from search_graph; +ERROR: cycle mark column name "label" already used in WITH query column list +LINE 7: ) cycle f, t set label to true default false using path + ^ +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) cycle f, t set is_cycle to true default false using label +select * from search_graph; +ERROR: cycle path column name "label" already used in WITH query column list +LINE 7: ) cycle f, t set is_cycle to true default false using label + ^ +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) cycle f, t set foo to true default false using foo +select * from search_graph; +ERROR: cycle mark column name and cycle path column name are the same +LINE 7: ) cycle f, t set foo to true default false using foo + ^ +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) cycle f, t, f set is_cycle to true default false using path +select * from search_graph; +ERROR: cycle column "f" specified more than once +LINE 7: ) cycle f, t, f set is_cycle to true default false using pat... + ^ +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) search depth first by f, t set foo + cycle f, t set foo to true default false using path +select * from search_graph; +ERROR: search sequence column name and cycle mark column name are the same +LINE 7: ) search depth first by f, t set foo + ^ +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) search depth first by f, t set foo + cycle f, t set is_cycle to true default false using foo +select * from search_graph; +ERROR: search_sequence column name and cycle path column name are the same +LINE 7: ) search depth first by f, t set foo + ^ +-- test ruleutils and view expansion +create temp view v_cycle as +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) cycle f, t set is_cycle to true default false using path +select f, t, label from search_graph; +select pg_get_viewdef('v_cycle'); + pg_get_viewdef +-------------------------------------------------------------------- + WITH RECURSIVE search_graph(f, t, label) AS ( + + SELECT g.f, + + g.t, + + g.label + + FROM graph g + + UNION ALL + + SELECT g.f, + + g.t, + + g.label + + FROM graph g, + + search_graph sg + + WHERE (g.f = sg.t) + + ) CYCLE f, t SET is_cycle TO true DEFAULT false USING path+ + SELECT search_graph.f, + + search_graph.t, + + search_graph.label + + FROM search_graph; +(1 row) + +select * from v_cycle; + f | t | label +---+---+------------ + 1 | 2 | arc 1 -> 2 + 1 | 3 | arc 1 -> 3 + 2 | 3 | arc 2 -> 3 + 1 | 4 | arc 1 -> 4 + 4 | 5 | arc 4 -> 5 + 5 | 1 | arc 5 -> 1 + 1 | 2 | arc 1 -> 2 + 1 | 3 | arc 1 -> 3 + 1 | 4 | arc 1 -> 4 + 2 | 3 | arc 2 -> 3 + 4 | 5 | arc 4 -> 5 + 5 | 1 | arc 5 -> 1 + 1 | 2 | arc 1 -> 2 + 1 | 3 | arc 1 -> 3 + 1 | 4 | arc 1 -> 4 + 2 | 3 | arc 2 -> 3 + 4 | 5 | arc 4 -> 5 + 5 | 1 | arc 5 -> 1 + 1 | 2 | arc 1 -> 2 + 1 | 3 | arc 1 -> 3 + 1 | 4 | arc 1 -> 4 + 2 | 3 | arc 2 -> 3 + 4 | 5 | arc 4 -> 5 + 5 | 1 | arc 5 -> 1 + 2 | 3 | arc 2 -> 3 +(25 rows) + -- -- test multiple WITH queries -- diff --git a/src/test/regress/sql/with.sql b/src/test/regress/sql/with.sql index ad976de531132..f4ba0d8e39942 100644 --- a/src/test/regress/sql/with.sql +++ b/src/test/regress/sql/with.sql @@ -303,6 +303,118 @@ UNION ALL SELECT t1.id, t2.path, t2 FROM t AS t1 JOIN t AS t2 ON (t1.id=t2.id); +-- SEARCH clause + +create temp table graph0( f int, t int, label text ); + +insert into graph0 values + (1, 2, 'arc 1 -> 2'), + (1, 3, 'arc 1 -> 3'), + (2, 3, 'arc 2 -> 3'), + (1, 4, 'arc 1 -> 4'), + (4, 5, 'arc 4 -> 5'); + +with recursive search_graph(f, t, label) as ( + select * from graph0 g + union all + select g.* + from graph0 g, search_graph sg + where g.f = sg.t +) search depth first by f, t set seq +select * from search_graph order by seq; + +with recursive search_graph(f, t, label) as ( + select * from graph0 g + union distinct + select g.* + from graph0 g, search_graph sg + where g.f = sg.t +) search depth first by f, t set seq +select * from search_graph order by seq; + +with recursive search_graph(f, t, label) as ( + select * from graph0 g + union all + select g.* + from graph0 g, search_graph sg + where g.f = sg.t +) search breadth first by f, t set seq +select * from search_graph order by seq; + +with recursive search_graph(f, t, label) as ( + select * from graph0 g + union distinct + select g.* + from graph0 g, search_graph sg + where g.f = sg.t +) search breadth first by f, t set seq +select * from search_graph order by seq; + +-- various syntax errors +with recursive search_graph(f, t, label) as ( + select * from graph0 g + union all + select g.* + from graph0 g, search_graph sg + where g.f = sg.t +) search depth first by foo, tar set seq +select * from search_graph; + +with recursive search_graph(f, t, label) as ( + select * from graph0 g + union all + select g.* + from graph0 g, search_graph sg + where g.f = sg.t +) search depth first by f, t set label +select * from search_graph; + +with recursive search_graph(f, t, label) as ( + select * from graph0 g + union all + select g.* + from graph0 g, search_graph sg + where g.f = sg.t +) search depth first by f, t, f set seq +select * from search_graph; + +with recursive search_graph(f, t, label) as ( + select * from graph0 g + union all + select * from graph0 g + union all + select g.* + from graph0 g, search_graph sg + where g.f = sg.t +) search depth first by f, t set seq +select * from search_graph order by seq; + +with recursive search_graph(f, t, label) as ( + select * from graph0 g + union all + (select * from graph0 g + union all + select g.* + from graph0 g, search_graph sg + where g.f = sg.t) +) search depth first by f, t set seq +select * from search_graph order by seq; + +-- test ruleutils and view expansion +create temp view v_search as +with recursive search_graph(f, t, label) as ( + select * from graph0 g + union all + select g.* + from graph0 g, search_graph sg + where g.f = sg.t +) search depth first by f, t set seq +select f, t, label from search_graph; + +select pg_get_viewdef('v_search'); + +select * from v_search; + -- -- test cycle detection -- @@ -345,6 +457,173 @@ with recursive search_graph(f, t, label, is_cycle, path) as ( ) select * from search_graph order by path; +-- CYCLE clause + +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) cycle f, t set is_cycle to true default false using path +select * from search_graph; + +with recursive search_graph(f, t, label) as ( + select * from graph g + union distinct + select g.* + from graph g, search_graph sg + where g.f = sg.t +) cycle f, t set is_cycle to 'Y' default 'N' using path +select * from search_graph; + +-- multiple CTEs +with recursive +graph(f, t, label) as ( + values (1, 2, 'arc 1 -> 2'), + (1, 3, 'arc 1 -> 3'), + (2, 3, 'arc 2 -> 3'), + (1, 4, 'arc 1 -> 4'), + (4, 5, 'arc 4 -> 5'), + (5, 1, 'arc 5 -> 1') +), +search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) cycle f, t set is_cycle to true default false using path +select f, t, label from search_graph; + +-- star expansion +with recursive a as ( + select 1 as b + union all + select * from a +) cycle b set c to true default false using p +select * from a; + +-- search+cycle +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) search depth first by f, t set seq + cycle f, t set is_cycle to true default false using path +select * from search_graph; + +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) search breadth first by f, t set seq + cycle f, t set is_cycle to true default false using path +select * from search_graph; + +-- various syntax errors +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) cycle foo, tar set is_cycle to true default false using path +select * from search_graph; + +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) cycle f, t set is_cycle to true default 55 using path +select * from search_graph; + +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) cycle f, t set is_cycle to point '(1,1)' default point '(0,0)' using path +select * from search_graph; + +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) cycle f, t set label to true default false using path +select * from search_graph; + +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) cycle f, t set is_cycle to true default false using label +select * from search_graph; + +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) cycle f, t set foo to true default false using foo +select * from search_graph; + +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) cycle f, t, f set is_cycle to true default false using path +select * from search_graph; + +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) search depth first by f, t set foo + cycle f, t set foo to true default false using path +select * from search_graph; + +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) search depth first by f, t set foo + cycle f, t set is_cycle to true default false using foo +select * from search_graph; + +-- test ruleutils and view expansion +create temp view v_cycle as +with recursive search_graph(f, t, label) as ( + select * from graph g + union all + select g.* + from graph g, search_graph sg + where g.f = sg.t +) cycle f, t set is_cycle to true default false using path +select f, t, label from search_graph; + +select pg_get_viewdef('v_cycle'); + +select * from v_cycle; + -- -- test multiple WITH queries -- From fb2d645dd53ff571572d830e830fc8c368063802 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 1 Feb 2021 14:05:51 -0500 Subject: [PATCH 227/240] Revise make_partition_pruneinfo to not use its partitioned_rels input. It turns out that the calculation of [Merge]AppendPath.partitioned_rels in allpaths.c is faulty and sometimes omits relevant non-leaf partitions, allowing an assertion added by commit a929e17e5a8 to trigger. Rather than fix that, it seems better to get rid of those fields altogether. We don't really need the info until create_plan time, and calculating it once for the selected plan should be cheaper than calculating it for each append path we consider. As a first step, teach make_partition_pruneinfo to collect the relevant partitioned tables for itself. It's not hard to do so by traversing from child tables up to parents using the AppendRelInfo links. While here, make some minor stylistic improvements; mainly, don't use the "Relids" alias for bitmapsets that are not identities of any relation considered by the planner. Try to document the logic better, too. No backpatch, as there does not seem to be a live problem before a929e17e5a8. Also no new regression test; the code where the bug was will be gone at the end of this patch series, so it seems a bit pointless to memorialize the issue. Tom Lane and David Rowley, per reports from Andreas Seltenreich and Jaime Casanova. Discussion: https://postgr.es/m/87sg8tqhsl.fsf@aurora.ydns.eu Discussion: https://postgr.es/m/CAJKUy5gCXDSmFs2c=R+VGgn7FiYcLCsEFEuDNNLGfoha=pBE_g@mail.gmail.com --- src/backend/partitioning/partprune.c | 199 ++++++++++++++++++++------- 1 file changed, 149 insertions(+), 50 deletions(-) diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c index 42c7c5f55412f..6df52bc6b7bdd 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -138,10 +138,12 @@ typedef struct PruneStepResult } PruneStepResult; +static List *add_part_relids(List *allpartrelids, Bitmapset *partrelids); static List *make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, + List *prunequal, + Bitmapset *partrelids, int *relid_subplan_map, - Relids partrelids, List *prunequal, Bitmapset **matchedsubplans); static void gen_partprune_steps(RelOptInfo *rel, List *clauses, PartClauseTarget target, @@ -213,67 +215,105 @@ static void partkey_datum_from_expr(PartitionPruneContext *context, * * 'parentrel' is the RelOptInfo for an appendrel, and 'subpaths' is the list * of scan paths for its child rels. - * - * 'partitioned_rels' is a List containing Lists of relids of partitioned - * tables (a/k/a non-leaf partitions) that are parents of some of the child - * rels. Here we attempt to populate the PartitionPruneInfo by adding a - * 'prune_infos' item for each sublist in the 'partitioned_rels' list. - * However, some of the sets of partitioned relations may not require any - * run-time pruning. In these cases we'll simply not include a 'prune_infos' - * item for that set and instead we'll add all the subplans which belong to - * that set into the PartitionPruneInfo's 'other_subplans' field. Callers - * will likely never want to prune subplans which are mentioned in this field. - * - * 'prunequal' is a list of potential pruning quals. + * 'prunequal' is a list of potential pruning quals (i.e., restriction + * clauses that are applicable to the appendrel). */ PartitionPruneInfo * make_partition_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, - List *subpaths, List *partitioned_rels, + List *subpaths, List *unused_partitioned_rels, List *prunequal) { PartitionPruneInfo *pruneinfo; Bitmapset *allmatchedsubplans = NULL; + List *allpartrelids; + List *prunerelinfos; int *relid_subplan_map; ListCell *lc; - List *prunerelinfos; int i; /* - * Construct a temporary array to map from planner relids to subplan - * indexes. For convenience, we use 1-based indexes here, so that zero - * can represent an un-filled array entry. + * Scan the subpaths to see which ones are scans of partition child + * relations, and identify their parent partitioned rels. (Note: we must + * restrict the parent partitioned rels to be parentrel or children of + * parentrel, otherwise we couldn't translate prunequal to match.) + * + * Also construct a temporary array to map from partition-child-relation + * relid to the index in 'subpaths' of the scan plan for that partition. + * (Use of "subplan" rather than "subpath" is a bit of a misnomer, but + * we'll let it stand.) For convenience, we use 1-based indexes here, so + * that zero can represent an un-filled array entry. */ + allpartrelids = NIL; relid_subplan_map = palloc0(sizeof(int) * root->simple_rel_array_size); - /* - * relid_subplan_map maps relid of a leaf partition to the index in - * 'subpaths' of the scan plan for that partition. - */ i = 1; foreach(lc, subpaths) { Path *path = (Path *) lfirst(lc); RelOptInfo *pathrel = path->parent; - Assert(IS_SIMPLE_REL(pathrel)); - Assert(pathrel->relid < root->simple_rel_array_size); - /* No duplicates please */ - Assert(relid_subplan_map[pathrel->relid] == 0); + /* We don't consider partitioned joins here */ + if (pathrel->reloptkind == RELOPT_OTHER_MEMBER_REL) + { + RelOptInfo *prel = pathrel; + Bitmapset *partrelids = NULL; - relid_subplan_map[pathrel->relid] = i++; + /* + * Traverse up to the pathrel's topmost partitioned parent, + * collecting parent relids as we go; but stop if we reach + * parentrel. (Normally, a pathrel's topmost partitioned parent + * is either parentrel or a UNION ALL appendrel child of + * parentrel. But when handling partitionwise joins of + * multi-level partitioning trees, we can see an append path whose + * parentrel is an intermediate partitioned table.) + */ + do + { + AppendRelInfo *appinfo; + + Assert(prel->relid < root->simple_rel_array_size); + appinfo = root->append_rel_array[prel->relid]; + prel = find_base_rel(root, appinfo->parent_relid); + if (!IS_PARTITIONED_REL(prel)) + break; /* reached a non-partitioned parent */ + /* accept this level as an interesting parent */ + partrelids = bms_add_member(partrelids, prel->relid); + if (prel == parentrel) + break; /* don't traverse above parentrel */ + } while (prel->reloptkind == RELOPT_OTHER_MEMBER_REL); + + if (partrelids) + { + /* + * Found some relevant parent partitions, which may or may not + * overlap with partition trees we already found. Add new + * information to the allpartrelids list. + */ + allpartrelids = add_part_relids(allpartrelids, partrelids); + /* Also record the subplan in relid_subplan_map[] */ + /* No duplicates please */ + Assert(relid_subplan_map[pathrel->relid] == 0); + relid_subplan_map[pathrel->relid] = i; + } + } + i++; } - /* We now build a PartitionedRelPruneInfo for each partitioned rel. */ + /* + * We now build a PartitionedRelPruneInfo for each topmost partitioned rel + * (omitting any that turn out not to have useful pruning quals). + */ prunerelinfos = NIL; - foreach(lc, partitioned_rels) + foreach(lc, allpartrelids) { - Relids partrelids = (Relids) lfirst(lc); + Bitmapset *partrelids = (Bitmapset *) lfirst(lc); List *pinfolist; Bitmapset *matchedsubplans = NULL; pinfolist = make_partitionedrel_pruneinfo(root, parentrel, + prunequal, + partrelids, relid_subplan_map, - partrelids, prunequal, &matchedsubplans); /* When pruning is possible, record the matched subplans */ @@ -299,7 +339,7 @@ make_partition_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, pruneinfo->prune_infos = prunerelinfos; /* - * Some subplans may not belong to any of the listed partitioned rels. + * Some subplans may not belong to any of the identified partitioned rels. * This can happen for UNION ALL queries which include a non-partitioned * table, or when some of the hierarchies aren't run-time prunable. Build * a bitmapset of the indexes of all such subplans, so that the executor @@ -321,28 +361,86 @@ make_partition_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, return pruneinfo; } +/* + * add_part_relids + * Add new info to a list of Bitmapsets of partitioned relids. + * + * Within 'allpartrelids', there is one Bitmapset for each topmost parent + * partitioned rel. Each Bitmapset contains the RT indexes of the topmost + * parent as well as its relevant non-leaf child partitions. Since (by + * construction of the rangetable list) parent partitions must have lower + * RT indexes than their children, we can distinguish the topmost parent + * as being the lowest set bit in the Bitmapset. + * + * 'partrelids' contains the RT indexes of a parent partitioned rel, and + * possibly some non-leaf children, that are newly identified as parents of + * some subpath rel passed to make_partition_pruneinfo(). These are added + * to an appropriate member of 'allpartrelids'. + * + * Note that the list contains only RT indexes of partitioned tables that + * are parents of some scan-level relation appearing in the 'subpaths' that + * make_partition_pruneinfo() is dealing with. Also, "topmost" parents are + * not allowed to be higher than the 'parentrel' associated with the append + * path. In this way, we avoid expending cycles on partitioned rels that + * can't contribute useful pruning information for the problem at hand. + * (It is possible for 'parentrel' to be a child partitioned table, and it + * is also possible for scan-level relations to be child partitioned tables + * rather than leaf partitions. Hence we must construct this relation set + * with reference to the particular append path we're dealing with, rather + * than looking at the full partitioning structure represented in the + * RelOptInfos.) + */ +static List * +add_part_relids(List *allpartrelids, Bitmapset *partrelids) +{ + Index targetpart; + ListCell *lc; + + /* We can easily get the lowest set bit this way: */ + targetpart = bms_next_member(partrelids, -1); + Assert(targetpart > 0); + + /* Look for a matching topmost parent */ + foreach(lc, allpartrelids) + { + Bitmapset *currpartrelids = (Bitmapset *) lfirst(lc); + Index currtarget = bms_next_member(currpartrelids, -1); + + if (targetpart == currtarget) + { + /* Found a match, so add any new RT indexes to this hierarchy */ + currpartrelids = bms_add_members(currpartrelids, partrelids); + lfirst(lc) = currpartrelids; + return allpartrelids; + } + } + /* No match, so add the new partition hierarchy to the list */ + return lappend(allpartrelids, partrelids); +} + /* * make_partitionedrel_pruneinfo - * Build a List of PartitionedRelPruneInfos, one for each partitioned - * rel. These can be used in the executor to allow additional partition - * pruning to take place. - * - * Here we generate partition pruning steps for 'prunequal' and also build a - * data structure which allows mapping of partition indexes into 'subpaths' - * indexes. - * - * If no non-Const expressions are being compared to the partition key in any - * of the 'partitioned_rels', then we return NIL to indicate no run-time - * pruning should be performed. Run-time pruning would be useless since the - * pruning done during planning will have pruned everything that can be. - * - * On non-NIL return, 'matchedsubplans' is set to the subplan indexes which - * were matched to this partition hierarchy. + * Build a List of PartitionedRelPruneInfos, one for each interesting + * partitioned rel in a partitioning hierarchy. These can be used in the + * executor to allow additional partition pruning to take place. + * + * parentrel: rel associated with the appendpath being considered + * prunequal: potential pruning quals, represented for parentrel + * partrelids: Set of RT indexes identifying relevant partitioned tables + * within a single partitioning hierarchy + * relid_subplan_map[]: maps child relation relids to subplan indexes + * matchedsubplans: on success, receives the set of subplan indexes which + * were matched to this partition hierarchy + * + * If we cannot find any useful run-time pruning steps, return NIL. + * However, on success, each rel identified in partrelids will have + * an element in the result list, even if some of them are useless. */ static List * make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, + List *prunequal, + Bitmapset *partrelids, int *relid_subplan_map, - Relids partrelids, List *prunequal, Bitmapset **matchedsubplans) { RelOptInfo *targetpart = NULL; @@ -2421,11 +2519,12 @@ get_steps_using_prefix_recurse(GeneratePruningStepsContext *context, */ Assert(list_length(step_exprs) == cur_keyno || !bms_is_empty(step_nullkeys)); + /* * Note also that for hash partitioning, each partition key should * have either equality clauses or an IS NULL clause, so if a - * partition key doesn't have an expression, it would be specified - * in step_nullkeys. + * partition key doesn't have an expression, it would be specified in + * step_nullkeys. */ Assert(context->rel->part_scheme->strategy != PARTITION_STRATEGY_HASH || From 5076f88bc985a7728eea337cbabae0e034b064b1 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 1 Feb 2021 14:34:59 -0500 Subject: [PATCH 228/240] Remove incidental dependencies on partitioned_rels lists. It turns out that the calculation of [Merge]AppendPath.partitioned_rels in allpaths.c is faulty and sometimes omits relevant non-leaf partitions, allowing an assertion added by commit a929e17e5a8 to trigger. Rather than fix that, it seems better to get rid of those fields altogether. We don't really need the info until create_plan time, and calculating it once for the selected plan should be cheaper than calculating it for each append path we consider. This patch undoes a couple of very minor uses of the partitioned_rels values. createplan.c was testing for nil-ness to optimize away the preparatory work for make_partition_pruneinfo(). That is worth doing if the check is nigh free, but it's not worth going to any great lengths to avoid. create_append_path() was testing for nil-ness as part of deciding how to set up ParamPathInfo for an AppendPath. I replaced that with a check for the appendrel's parent rel being partitioned. That's not quite the same thing but should cover most cases. If we note any interesting loss of optimizations, we can dumb this down to just always use the more expensive method when the parent is a baserel. Discussion: https://postgr.es/m/87sg8tqhsl.fsf@aurora.ydns.eu Discussion: https://postgr.es/m/CAJKUy5gCXDSmFs2c=R+VGgn7FiYcLCsEFEuDNNLGfoha=pBE_g@mail.gmail.com --- src/backend/optimizer/plan/createplan.c | 6 ++---- src/backend/optimizer/util/pathnode.c | 15 +++++++-------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 25d4750ca66af..181387480a140 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -1227,8 +1227,7 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags) * pruning during execution. Gather information needed by the executor to * do partition pruning. */ - if (enable_partition_pruning && - best_path->partitioned_rels != NIL) + if (enable_partition_pruning) { List *prunequal; @@ -1393,8 +1392,7 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path, * pruning during execution. Gather information needed by the executor to * do partition pruning. */ - if (enable_partition_pruning && - best_path->partitioned_rels != NIL) + if (enable_partition_pruning) { List *prunequal; diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index d465b9e213731..7aea30b306dc4 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -1230,15 +1230,14 @@ create_append_path(PlannerInfo *root, /* * When generating an Append path for a partitioned table, there may be - * parameters that are useful so we can eliminate certain partitions - * during execution. Here we'll go all the way and fully populate the - * parameter info data as we do for normal base relations. However, we - * need only bother doing this for RELOPT_BASEREL rels, as - * RELOPT_OTHER_MEMBER_REL's Append paths are merged into the base rel's - * Append subpaths. It would do no harm to do this, we just avoid it to - * save wasting effort. + * parameterized quals that are useful for run-time pruning. Hence, + * compute path.param_info the same way as for any other baserel, so that + * such quals will be available for make_partition_pruneinfo(). (This + * would not work right for a non-baserel, ie a scan on a non-leaf child + * partition, and it's not necessary anyway in that case. Must skip it if + * we don't have "root", too.) */ - if (partitioned_rels != NIL && root && rel->reloptkind == RELOPT_BASEREL) + if (root && rel->reloptkind == RELOPT_BASEREL && IS_PARTITIONED_REL(rel)) pathnode->path.param_info = get_baserel_parampathinfo(root, rel, required_outer); From f003a7522bfa11177dc52c65eb97273a1057dfba Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 1 Feb 2021 14:43:54 -0500 Subject: [PATCH 229/240] Remove [Merge]AppendPath.partitioned_rels. It turns out that the calculation of [Merge]AppendPath.partitioned_rels in allpaths.c is faulty and sometimes omits relevant non-leaf partitions, allowing an assertion added by commit a929e17e5a8 to trigger. Rather than fix that, it seems better to get rid of those fields altogether. We don't really need the info until create_plan time, and calculating it once for the selected plan should be cheaper than calculating it for each append path we consider. The preceding two commits did away with all use of the partitioned_rels values; this commit just mechanically removes the fields and the code that calculated them. Discussion: https://postgr.es/m/87sg8tqhsl.fsf@aurora.ydns.eu Discussion: https://postgr.es/m/CAJKUy5gCXDSmFs2c=R+VGgn7FiYcLCsEFEuDNNLGfoha=pBE_g@mail.gmail.com --- src/backend/nodes/outfuncs.c | 2 - src/backend/optimizer/path/allpaths.c | 181 +++--------------------- src/backend/optimizer/path/joinrels.c | 2 +- src/backend/optimizer/plan/createplan.c | 2 - src/backend/optimizer/plan/planner.c | 3 +- src/backend/optimizer/prep/prepunion.c | 6 +- src/backend/optimizer/util/pathnode.c | 8 +- src/backend/partitioning/partprune.c | 2 +- src/include/nodes/pathnodes.h | 6 - src/include/optimizer/pathnode.h | 5 +- src/include/partitioning/partprune.h | 1 - 11 files changed, 31 insertions(+), 187 deletions(-) diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index fda732b4c2dfc..f5dcedf6e89ec 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -1871,7 +1871,6 @@ _outAppendPath(StringInfo str, const AppendPath *node) _outPathInfo(str, (const Path *) node); - WRITE_NODE_FIELD(partitioned_rels); WRITE_NODE_FIELD(subpaths); WRITE_INT_FIELD(first_partial_path); WRITE_FLOAT_FIELD(limit_tuples, "%.0f"); @@ -1884,7 +1883,6 @@ _outMergeAppendPath(StringInfo str, const MergeAppendPath *node) _outPathInfo(str, (const Path *) node); - WRITE_NODE_FIELD(partitioned_rels); WRITE_NODE_FIELD(subpaths); WRITE_FLOAT_FIELD(limit_tuples, "%.0f"); } diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 026a4b08481c9..cd3fdd259cdcc 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -99,18 +99,13 @@ static void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, Index rti, RangeTblEntry *rte); static void generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel, List *live_childrels, - List *all_child_pathkeys, - List *partitioned_rels); + List *all_child_pathkeys); static Path *get_cheapest_parameterized_child_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer); -static List *accumulate_partitioned_rels(List *partitioned_rels, - List *sub_partitioned_rels, - bool flatten_partitioned_rels); static void accumulate_append_subpath(Path *path, - List **subpaths, List **special_subpaths, - List **partitioned_rels, - bool flatten_partitioned_rels); + List **subpaths, + List **special_subpaths); static Path *get_singleton_append_subpath(Path *path); static void set_dummy_rel_pathlist(RelOptInfo *rel); static void set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel, @@ -1299,38 +1294,11 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, List *all_child_pathkeys = NIL; List *all_child_outers = NIL; ListCell *l; - List *partitioned_rels = NIL; - List *partial_partitioned_rels = NIL; - List *pa_partitioned_rels = NIL; double partial_rows = -1; - bool flatten_partitioned_rels; /* If appropriate, consider parallel append */ pa_subpaths_valid = enable_parallel_append && rel->consider_parallel; - /* What we do with the partitioned_rels list is different for UNION ALL */ - flatten_partitioned_rels = (rel->rtekind != RTE_SUBQUERY); - - /* - * For partitioned tables, we accumulate a list of Relids of each - * partitioned table which has at least one of its subpartitions directly - * present as a subpath in this Append. This is used later for run-time - * partition pruning. We must maintain separate lists for each Append - * Path that we create as some paths that we create here can't flatten - * sub-Appends and sub-MergeAppends into the top-level Append. We needn't - * bother doing this for join rels as no run-time pruning is done on - * those. - */ - if (rel->reloptkind != RELOPT_JOINREL && rel->part_scheme != NULL) - { - partitioned_rels = list_make1(bms_make_singleton(rel->relid)); - partial_partitioned_rels = list_make1(bms_make_singleton(rel->relid)); - - /* skip this one if we're not going to make a Parallel Append path */ - if (pa_subpaths_valid) - pa_partitioned_rels = list_make1(bms_make_singleton(rel->relid)); - } - /* * For every non-dummy child, remember the cheapest path. Also, identify * all pathkeys (orderings) and parameterizations (required_outer sets) @@ -1353,8 +1321,7 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, if (childrel->pathlist != NIL && childrel->cheapest_total_path->param_info == NULL) accumulate_append_subpath(childrel->cheapest_total_path, - &subpaths, NULL, &partitioned_rels, - flatten_partitioned_rels); + &subpaths, NULL); else subpaths_valid = false; @@ -1363,9 +1330,7 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, { cheapest_partial_path = linitial(childrel->partial_pathlist); accumulate_append_subpath(cheapest_partial_path, - &partial_subpaths, NULL, - &partial_partitioned_rels, - flatten_partitioned_rels); + &partial_subpaths, NULL); } else partial_subpaths_valid = false; @@ -1394,10 +1359,7 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, Assert(cheapest_partial_path != NULL); accumulate_append_subpath(cheapest_partial_path, &pa_partial_subpaths, - &pa_nonpartial_subpaths, - &pa_partitioned_rels, - flatten_partitioned_rels); - + &pa_nonpartial_subpaths); } else { @@ -1416,9 +1378,7 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, */ accumulate_append_subpath(nppath, &pa_nonpartial_subpaths, - NULL, - &pa_partitioned_rels, - flatten_partitioned_rels); + NULL); } } @@ -1495,7 +1455,7 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, if (subpaths_valid) add_path(rel, (Path *) create_append_path(root, rel, subpaths, NIL, NIL, NULL, 0, false, - partitioned_rels, -1)); + -1)); /* * Consider an append of unordered, unparameterized partial paths. Make @@ -1538,7 +1498,7 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, appendpath = create_append_path(root, rel, NIL, partial_subpaths, NIL, NULL, parallel_workers, enable_parallel_append, - partial_partitioned_rels, -1); + -1); /* * Make sure any subsequent partial paths use the same row count @@ -1587,7 +1547,7 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, appendpath = create_append_path(root, rel, pa_nonpartial_subpaths, pa_partial_subpaths, NIL, NULL, parallel_workers, true, - pa_partitioned_rels, partial_rows); + partial_rows); add_partial_path(rel, (Path *) appendpath); } @@ -1597,8 +1557,7 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, */ if (subpaths_valid) generate_orderedappend_paths(root, rel, live_childrels, - all_child_pathkeys, - partitioned_rels); + all_child_pathkeys); /* * Build Append paths for each parameterization seen among the child rels. @@ -1617,10 +1576,6 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, { Relids required_outer = (Relids) lfirst(l); ListCell *lcr; - List *part_rels = NIL; - - if (rel->reloptkind != RELOPT_JOINREL && rel->part_scheme != NULL) - part_rels = list_make1(bms_make_singleton(rel->relid)); /* Select the child paths for an Append with this parameterization */ subpaths = NIL; @@ -1646,15 +1601,14 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, subpaths_valid = false; break; } - accumulate_append_subpath(subpath, &subpaths, NULL, &part_rels, - flatten_partitioned_rels); + accumulate_append_subpath(subpath, &subpaths, NULL); } if (subpaths_valid) add_path(rel, (Path *) create_append_path(root, rel, subpaths, NIL, NIL, required_outer, 0, false, - part_rels, -1)); + -1)); } /* @@ -1681,7 +1635,7 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, appendpath = create_append_path(root, rel, NIL, list_make1(path), NIL, NULL, path->parallel_workers, true, - partitioned_rels, partial_rows); + partial_rows); add_partial_path(rel, (Path *) appendpath); } } @@ -1717,26 +1671,13 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, static void generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel, List *live_childrels, - List *all_child_pathkeys, - List *partitioned_rels) + List *all_child_pathkeys) { ListCell *lcp; List *partition_pathkeys = NIL; List *partition_pathkeys_desc = NIL; bool partition_pathkeys_partial = true; bool partition_pathkeys_desc_partial = true; - List *startup_partitioned_rels = NIL; - List *total_partitioned_rels = NIL; - bool flatten_partitioned_rels; - - /* Set up the method for building the partitioned rels lists */ - flatten_partitioned_rels = (rel->rtekind != RTE_SUBQUERY); - - if (rel->reloptkind != RELOPT_JOINREL && rel->part_scheme != NULL) - { - startup_partitioned_rels = list_make1(bms_make_singleton(rel->relid)); - total_partitioned_rels = list_make1(bms_make_singleton(rel->relid)); - } /* * Some partitioned table setups may allow us to use an Append node @@ -1878,13 +1819,9 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel, * child paths for the MergeAppend. */ accumulate_append_subpath(cheapest_startup, - &startup_subpaths, NULL, - &startup_partitioned_rels, - flatten_partitioned_rels); + &startup_subpaths, NULL); accumulate_append_subpath(cheapest_total, - &total_subpaths, NULL, - &total_partitioned_rels, - flatten_partitioned_rels); + &total_subpaths, NULL); } } @@ -1900,7 +1837,6 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel, NULL, 0, false, - startup_partitioned_rels, -1)); if (startup_neq_total) add_path(rel, (Path *) create_append_path(root, @@ -1911,7 +1847,6 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel, NULL, 0, false, - total_partitioned_rels, -1)); } else @@ -1921,15 +1856,13 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel, rel, startup_subpaths, pathkeys, - NULL, - startup_partitioned_rels)); + NULL)); if (startup_neq_total) add_path(rel, (Path *) create_merge_append_path(root, rel, total_subpaths, pathkeys, - NULL, - total_partitioned_rels)); + NULL)); } } } @@ -2008,54 +1941,6 @@ get_cheapest_parameterized_child_path(PlannerInfo *root, RelOptInfo *rel, return cheapest; } -/* - * accumulate_partitioned_rels - * Record 'sub_partitioned_rels' in the 'partitioned_rels' list, - * flattening as appropriate. - */ -static List * -accumulate_partitioned_rels(List *partitioned_rels, - List *sub_partitioned_rels, - bool flatten) -{ - if (flatten) - { - /* - * We're only called with flatten == true when the partitioned_rels - * list has at most 1 element. So we can just add the members from - * sub list's first element onto the first element of - * partitioned_rels. Only later in planning when doing UNION ALL - * Append processing will we see flatten == false. partitioned_rels - * may end up with more than 1 element then, but we never expect to be - * called with flatten == true again after that, so we needn't bother - * doing anything here for anything but the initial element. - */ - if (partitioned_rels != NIL && sub_partitioned_rels != NIL) - { - Relids partrels = (Relids) linitial(partitioned_rels); - Relids subpartrels = (Relids) linitial(sub_partitioned_rels); - - /* Ensure the above comment holds true */ - Assert(list_length(partitioned_rels) == 1); - Assert(list_length(sub_partitioned_rels) == 1); - - linitial(partitioned_rels) = bms_add_members(partrels, subpartrels); - } - } - else - { - /* - * Handle UNION ALL to partitioned tables. This always occurs after - * we've done the accumulation for sub-partitioned tables, so there's - * no need to consider how adding multiple elements to the top level - * list affects the flatten == true case above. - */ - partitioned_rels = list_concat(partitioned_rels, sub_partitioned_rels); - } - - return partitioned_rels; -} - /* * accumulate_append_subpath * Add a subpath to the list being built for an Append or MergeAppend. @@ -2076,24 +1961,9 @@ accumulate_partitioned_rels(List *partitioned_rels, * children to subpaths and the rest to special_subpaths. If the latter is * NULL, we don't flatten the path at all (unless it contains only partial * paths). - * - * When pulling up sub-Appends and sub-Merge Appends, we also gather the - * path's list of partitioned tables and store in 'partitioned_rels'. The - * exact behavior here depends on the value of 'flatten_partitioned_rels'. - * - * When 'flatten_partitioned_rels' is true, 'partitioned_rels' will contain at - * most one element which is a Relids of the partitioned relations which there - * are subpaths for. In this case, we just add the RT indexes for the - * partitioned tables for the subpath we're pulling up to the single entry in - * 'partitioned_rels'. When 'flatten_partitioned_rels' is false we - * concatenate the path's partitioned rel list onto the top-level list. This - * done for UNION ALLs which could have a partitioned table in each union - * branch. */ static void -accumulate_append_subpath(Path *path, List **subpaths, List **special_subpaths, - List **partitioned_rels, - bool flatten_partitioned_rels) +accumulate_append_subpath(Path *path, List **subpaths, List **special_subpaths) { if (IsA(path, AppendPath)) { @@ -2102,9 +1972,6 @@ accumulate_append_subpath(Path *path, List **subpaths, List **special_subpaths, if (!apath->path.parallel_aware || apath->first_partial_path == 0) { *subpaths = list_concat(*subpaths, apath->subpaths); - *partitioned_rels = accumulate_partitioned_rels(*partitioned_rels, - apath->partitioned_rels, - flatten_partitioned_rels); return; } else if (special_subpaths != NULL) @@ -2120,9 +1987,6 @@ accumulate_append_subpath(Path *path, List **subpaths, List **special_subpaths, apath->first_partial_path); *special_subpaths = list_concat(*special_subpaths, new_special_subpaths); - *partitioned_rels = accumulate_partitioned_rels(*partitioned_rels, - apath->partitioned_rels, - flatten_partitioned_rels); return; } } @@ -2131,9 +1995,6 @@ accumulate_append_subpath(Path *path, List **subpaths, List **special_subpaths, MergeAppendPath *mpath = (MergeAppendPath *) path; *subpaths = list_concat(*subpaths, mpath->subpaths); - *partitioned_rels = accumulate_partitioned_rels(*partitioned_rels, - mpath->partitioned_rels, - flatten_partitioned_rels); return; } @@ -2195,7 +2056,7 @@ set_dummy_rel_pathlist(RelOptInfo *rel) /* Set up the dummy path */ add_path(rel, (Path *) create_append_path(NULL, rel, NIL, NIL, NIL, rel->lateral_relids, - 0, false, NIL, -1)); + 0, false, -1)); /* * We set the cheapest-path fields immediately, just in case they were diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c index e19d2e82289eb..0dbe2ac7265ff 100644 --- a/src/backend/optimizer/path/joinrels.c +++ b/src/backend/optimizer/path/joinrels.c @@ -1279,7 +1279,7 @@ mark_dummy_rel(RelOptInfo *rel) /* Set up the dummy path */ add_path(rel, (Path *) create_append_path(NULL, rel, NIL, NIL, NIL, rel->lateral_relids, - 0, false, NIL, -1)); + 0, false, -1)); /* Set or update cheapest_total_path and related fields */ set_cheapest(rel); diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 181387480a140..6c8305c977e64 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -1248,7 +1248,6 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags) partpruneinfo = make_partition_pruneinfo(root, rel, best_path->subpaths, - best_path->partitioned_rels, prunequal); } @@ -1412,7 +1411,6 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path, if (prunequal != NIL) partpruneinfo = make_partition_pruneinfo(root, rel, best_path->subpaths, - best_path->partitioned_rels, prunequal); } diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 4e6497ff32877..adf68d8790689 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -1726,7 +1726,7 @@ inheritance_planner(PlannerInfo *root) /* Make a dummy path, cf set_dummy_rel_pathlist() */ dummy_path = (Path *) create_append_path(NULL, final_rel, NIL, NIL, NIL, NULL, 0, false, - NIL, -1); + -1); /* These lists must be nonempty to make a valid ModifyTable node */ subpaths = list_make1(dummy_path); @@ -4006,7 +4006,6 @@ create_degenerate_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel, NULL, 0, false, - NIL, -1); } else diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index 86f794c19358b..becdcbb872533 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -620,7 +620,7 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root, * Append the child results together. */ path = (Path *) create_append_path(root, result_rel, pathlist, NIL, - NIL, NULL, 0, false, NIL, -1); + NIL, NULL, 0, false, -1); /* * For UNION ALL, we just need the Append path. For UNION, need to add @@ -677,7 +677,7 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root, create_append_path(root, result_rel, NIL, partial_pathlist, NIL, NULL, parallel_workers, enable_parallel_append, - NIL, -1); + -1); ppath = (Path *) create_gather_path(root, result_rel, ppath, result_rel->reltarget, NULL, NULL); @@ -787,7 +787,7 @@ generate_nonunion_paths(SetOperationStmt *op, PlannerInfo *root, * Append the child results together. */ path = (Path *) create_append_path(root, result_rel, pathlist, NIL, - NIL, NULL, 0, false, NIL, -1); + NIL, NULL, 0, false, -1); /* Identify the grouping semantics */ groupList = generate_setop_grouplist(op, tlist); diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index 7aea30b306dc4..9be0c4a6af592 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -1217,7 +1217,7 @@ create_append_path(PlannerInfo *root, List *subpaths, List *partial_subpaths, List *pathkeys, Relids required_outer, int parallel_workers, bool parallel_aware, - List *partitioned_rels, double rows) + double rows) { AppendPath *pathnode = makeNode(AppendPath); ListCell *l; @@ -1249,7 +1249,6 @@ create_append_path(PlannerInfo *root, pathnode->path.parallel_safe = rel->consider_parallel; pathnode->path.parallel_workers = parallel_workers; pathnode->path.pathkeys = pathkeys; - pathnode->partitioned_rels = list_copy(partitioned_rels); /* * For parallel append, non-partial paths are sorted by descending total @@ -1377,8 +1376,7 @@ create_merge_append_path(PlannerInfo *root, RelOptInfo *rel, List *subpaths, List *pathkeys, - Relids required_outer, - List *partitioned_rels) + Relids required_outer) { MergeAppendPath *pathnode = makeNode(MergeAppendPath); Cost input_startup_cost; @@ -1394,7 +1392,6 @@ create_merge_append_path(PlannerInfo *root, pathnode->path.parallel_safe = rel->consider_parallel; pathnode->path.parallel_workers = 0; pathnode->path.pathkeys = pathkeys; - pathnode->partitioned_rels = list_copy(partitioned_rels); pathnode->subpaths = subpaths; /* @@ -3847,7 +3844,6 @@ reparameterize_path(PlannerInfo *root, Path *path, apath->path.pathkeys, required_outer, apath->path.parallel_workers, apath->path.parallel_aware, - apath->partitioned_rels, -1); } default: diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c index 6df52bc6b7bdd..d08739127b9cf 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -220,7 +220,7 @@ static void partkey_datum_from_expr(PartitionPruneContext *context, */ PartitionPruneInfo * make_partition_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, - List *subpaths, List *unused_partitioned_rels, + List *subpaths, List *prunequal) { PartitionPruneInfo *pruneinfo; diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h index cde2637798557..0ec93e648c4c6 100644 --- a/src/include/nodes/pathnodes.h +++ b/src/include/nodes/pathnodes.h @@ -1403,9 +1403,6 @@ typedef struct CustomPath typedef struct AppendPath { Path path; - List *partitioned_rels; /* List of Relids containing RT indexes of - * non-leaf tables for each partition - * hierarchy whose paths are in 'subpaths' */ List *subpaths; /* list of component Paths */ /* Index of first partial path in subpaths; list_length(subpaths) if none */ int first_partial_path; @@ -1430,9 +1427,6 @@ extern bool is_dummy_rel(RelOptInfo *rel); typedef struct MergeAppendPath { Path path; - List *partitioned_rels; /* List of Relids containing RT indexes of - * non-leaf tables for each partition - * hierarchy whose paths are in 'subpaths' */ List *subpaths; /* list of component Paths */ double limit_tuples; /* hard limit on output tuples, or -1 */ } MergeAppendPath; diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h index 23dec14cbd38c..8dfc36a4e1546 100644 --- a/src/include/optimizer/pathnode.h +++ b/src/include/optimizer/pathnode.h @@ -67,13 +67,12 @@ extern AppendPath *create_append_path(PlannerInfo *root, RelOptInfo *rel, List *subpaths, List *partial_subpaths, List *pathkeys, Relids required_outer, int parallel_workers, bool parallel_aware, - List *partitioned_rels, double rows); + double rows); extern MergeAppendPath *create_merge_append_path(PlannerInfo *root, RelOptInfo *rel, List *subpaths, List *pathkeys, - Relids required_outer, - List *partitioned_rels); + Relids required_outer); extern GroupResultPath *create_group_result_path(PlannerInfo *root, RelOptInfo *rel, PathTarget *target, diff --git a/src/include/partitioning/partprune.h b/src/include/partitioning/partprune.h index 1f9544c0dcfd7..5f51e73a4d5a7 100644 --- a/src/include/partitioning/partprune.h +++ b/src/include/partitioning/partprune.h @@ -71,7 +71,6 @@ typedef struct PartitionPruneContext extern PartitionPruneInfo *make_partition_pruneinfo(struct PlannerInfo *root, struct RelOptInfo *parentrel, List *subpaths, - List *partitioned_rels, List *prunequal); extern Bitmapset *prune_append_rel_partitions(struct RelOptInfo *rel); extern Bitmapset *get_matching_partitions(PartitionPruneContext *context, From 9522085ac917af66dba29939af328ae67300f10a Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 1 Feb 2021 16:38:52 -0500 Subject: [PATCH 230/240] Doc: work a little harder on the initial examples for regex matching. Writing unnecessary '.*' at start and end of a POSIX regex doesn't do much except confuse the reader about whether that might be necessary after all. Make the examples in table 9.16 a tad more realistic, and try to turn the next group of examples into something self-contained. Per gripe from rmzgrimes. Back-patch to v13 because it's easy. Discussion: https://postgr.es/m/161215841824.14653.8969016349304314299@wrigleys.postgresql.org --- doc/src/sgml/func.sgml | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index f30eaa3e4bac6..081f04ce1a9fb 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -5329,7 +5329,7 @@ substring('foobar' similar '#"o_b#"%' escape '#') NULL - 'thomas' ~ '.*thom.*' + 'thomas' ~ 't.*ma' t @@ -5343,7 +5343,7 @@ substring('foobar' similar '#"o_b#"%' escape '#') NULL - 'thomas' ~* '.*Thom.*' + 'thomas' ~* 'T.*ma' t @@ -5357,8 +5357,8 @@ substring('foobar' similar '#"o_b#"%' escape '#') NULL - 'thomas' !~ '.*thomas.*' - f + 'thomas' !~ 't.*max' + t @@ -5371,8 +5371,8 @@ substring('foobar' similar '#"o_b#"%' escape '#') NULL - 'thomas' !~* '.*vadim.*' - t + 'thomas' !~* 'T.*ma' + f @@ -5406,10 +5406,12 @@ substring('foobar' similar '#"o_b#"%' escape '#') NULL Some examples: -'abc' ~ 'abc' true -'abc' ~ '^a' true -'abc' ~ '(b|d)' true -'abc' ~ '^(b|c)' false +'abcd' ~ 'bc' true +'abcd' ~ 'a.c' true — dot matches any character +'abcd' ~ 'a.*d' true — * repeats the preceding pattern item +'abcd' ~ '(b|x)' true — | means OR, parentheses group +'abcd' ~ '^a' true — ^ anchors to start of string +'abcd' ~ '^(b|c)' false — would match except for anchoring From 4ad31bb2ef2517b6e49ea9e8f01aaed250d4df38 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Tue, 2 Feb 2021 13:59:23 +0900 Subject: [PATCH 231/240] Remove unused column atttypmod from initial tablesync query MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The initial tablesync done by logical replication used a query to fetch the information of a relation's columns that included atttypmod, but it was left unused. This was added by 7c4f524. Author: Euler Taveira Reviewed-by: Önder Kalacı, Amit Langote, Japin Li Discussion: https://postgr.es/m/CAHE3wggb715X+mK_DitLXF25B=jE6xyNCH4YOwM860JR7HarGQ@mail.gmail.com --- src/backend/replication/logical/tablesync.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c index 863d196fd7c66..a18f847ade052 100644 --- a/src/backend/replication/logical/tablesync.c +++ b/src/backend/replication/logical/tablesync.c @@ -640,7 +640,7 @@ fetch_remote_table_info(char *nspname, char *relname, StringInfoData cmd; TupleTableSlot *slot; Oid tableRow[] = {OIDOID, CHAROID, CHAROID}; - Oid attrRow[] = {TEXTOID, OIDOID, INT4OID, BOOLOID}; + Oid attrRow[] = {TEXTOID, OIDOID, BOOLOID}; bool isnull; int natt; @@ -685,7 +685,6 @@ fetch_remote_table_info(char *nspname, char *relname, appendStringInfo(&cmd, "SELECT a.attname," " a.atttypid," - " a.atttypmod," " a.attnum = ANY(i.indkey)" " FROM pg_catalog.pg_attribute a" " LEFT JOIN pg_catalog.pg_index i" @@ -718,7 +717,7 @@ fetch_remote_table_info(char *nspname, char *relname, Assert(!isnull); lrel->atttyps[natt] = DatumGetObjectId(slot_getattr(slot, 2, &isnull)); Assert(!isnull); - if (DatumGetBool(slot_getattr(slot, 4, &isnull))) + if (DatumGetBool(slot_getattr(slot, 3, &isnull))) lrel->attkeys = bms_add_member(lrel->attkeys, natt); /* Should never happen. */ From 1d71f3c83c113849fe3aa60cb2d2c12729485e97 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Tue, 2 Feb 2021 09:20:22 +0100 Subject: [PATCH 232/240] Improve confusing variable names The prototype calls the second argument of pgstat_progress_update_multi_param() "index", and some callers name their local variable that way. But when the surrounding code deals with index relations, this is confusing, and in at least one case shadowed another variable that is referring to an index relation. Adjust those call sites to have clearer local variable naming, similar to existing callers in indexcmds.c. --- src/backend/access/nbtree/nbtsort.c | 6 +++--- src/backend/catalog/index.c | 18 +++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c index c319b6c88b3ee..5683daa34d3b7 100644 --- a/src/backend/access/nbtree/nbtsort.c +++ b/src/backend/access/nbtree/nbtsort.c @@ -486,17 +486,17 @@ _bt_spools_heapscan(Relation heap, Relation index, BTBuildState *buildstate, * values set by table_index_build_scan */ { - const int index[] = { + const int progress_index[] = { PROGRESS_CREATEIDX_TUPLES_TOTAL, PROGRESS_SCAN_BLOCKS_TOTAL, PROGRESS_SCAN_BLOCKS_DONE }; - const int64 val[] = { + const int64 progress_vals[] = { buildstate->indtuples, 0, 0 }; - pgstat_progress_update_multi_param(3, index, val); + pgstat_progress_update_multi_param(3, progress_index, progress_vals); } /* okay, all heap tuples are spooled */ diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index b8cd35e995d18..8350c65beb69e 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -3045,7 +3045,7 @@ index_build(Relation heapRelation, /* Set up initial progress report status */ { - const int index[] = { + const int progress_index[] = { PROGRESS_CREATEIDX_PHASE, PROGRESS_CREATEIDX_SUBPHASE, PROGRESS_CREATEIDX_TUPLES_DONE, @@ -3053,13 +3053,13 @@ index_build(Relation heapRelation, PROGRESS_SCAN_BLOCKS_DONE, PROGRESS_SCAN_BLOCKS_TOTAL }; - const int64 val[] = { + const int64 progress_vals[] = { PROGRESS_CREATEIDX_PHASE_BUILD, PROGRESS_CREATEIDX_SUBPHASE_INITIALIZE, 0, 0, 0, 0 }; - pgstat_progress_update_multi_param(6, index, val); + pgstat_progress_update_multi_param(6, progress_index, progress_vals); } /* @@ -3351,19 +3351,19 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot) int save_nestlevel; { - const int index[] = { + const int progress_index[] = { PROGRESS_CREATEIDX_PHASE, PROGRESS_CREATEIDX_TUPLES_DONE, PROGRESS_CREATEIDX_TUPLES_TOTAL, PROGRESS_SCAN_BLOCKS_DONE, PROGRESS_SCAN_BLOCKS_TOTAL }; - const int64 val[] = { + const int64 progress_vals[] = { PROGRESS_CREATEIDX_PHASE_VALIDATE_IDXSCAN, 0, 0, 0, 0 }; - pgstat_progress_update_multi_param(5, index, val); + pgstat_progress_update_multi_param(5, progress_index, progress_vals); } /* Open and lock the parent heap relation */ @@ -3420,17 +3420,17 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot) /* Execute the sort */ { - const int index[] = { + const int progress_index[] = { PROGRESS_CREATEIDX_PHASE, PROGRESS_SCAN_BLOCKS_DONE, PROGRESS_SCAN_BLOCKS_TOTAL }; - const int64 val[] = { + const int64 progress_vals[] = { PROGRESS_CREATEIDX_PHASE_VALIDATE_SORT, 0, 0 }; - pgstat_progress_update_multi_param(3, index, val); + pgstat_progress_update_multi_param(3, progress_index, progress_vals); } tuplesort_performsort(state.tuplesort); From 5c0f7cc5442108e113d4fb88c952329b467e2c6a Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 2 Feb 2021 13:49:08 -0500 Subject: [PATCH 233/240] Fix ancient memory leak in contrib/auto_explain. The ExecutorEnd hook is invoked in a context that could be quite long-lived, not the executor's own per-query context as I think we were sort of assuming. Thus, any cruft generated while producing the EXPLAIN output could accumulate over multiple queries. This can result in spectacular leakage if log_nested_statements is on, and even without that I'm surprised nobody complained before. To fix, just switch into the executor's context so that anything we allocate will be released when standard_ExecutorEnd frees the executor state. We might as well nuke the code's retail pfree of the explain output string, too; that's laughably inadequate to the need. Japin Li, per report from Jeff Janes. This bug is old, so back-patch to all supported branches. Discussion: https://postgr.es/m/CAMkU=1wCVtbeRn0s9gt12KwQ7PLXovbpM8eg25SYocKW3BT4hg@mail.gmail.com --- contrib/auto_explain/auto_explain.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/contrib/auto_explain/auto_explain.c b/contrib/auto_explain/auto_explain.c index faa6231d8722d..445bb37191217 100644 --- a/contrib/auto_explain/auto_explain.c +++ b/contrib/auto_explain/auto_explain.c @@ -371,8 +371,15 @@ explain_ExecutorEnd(QueryDesc *queryDesc) { if (queryDesc->totaltime && auto_explain_enabled()) { + MemoryContext oldcxt; double msec; + /* + * Make sure we operate in the per-query context, so any cruft will be + * discarded later during ExecutorEnd. + */ + oldcxt = MemoryContextSwitchTo(queryDesc->estate->es_query_cxt); + /* * Make sure stats accumulation is done. (Note: it's okay if several * levels of hook all do this.) @@ -424,9 +431,9 @@ explain_ExecutorEnd(QueryDesc *queryDesc) (errmsg("duration: %.3f ms plan:\n%s", msec, es->str->data), errhidestmt(true))); - - pfree(es->str->data); } + + MemoryContextSwitchTo(oldcxt); } if (prev_ExecutorEnd) From dfcc46fe3030b0114b7a5715d5fa40819561c04b Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 2 Feb 2021 14:35:12 -0500 Subject: [PATCH 234/240] Remove extra increment of plpgsql's statement counter for FOR loops. This left gaps in the internal statement numbering, which is not terribly harmful (else we'd have noticed sooner), but it's not great either. Oversight in bbd5c207b; backpatch to v12 where that came in. Pavel Stehule Discussion: https://postgr.es/m/CAFj8pRDXyQaJmpotNTQVc-t-WxdWZC35V2PnmwOaV1-taidFWA@mail.gmail.com --- src/pl/plpgsql/src/pl_gram.y | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y index abf196d4be149..34e0520719fea 100644 --- a/src/pl/plpgsql/src/pl_gram.y +++ b/src/pl/plpgsql/src/pl_gram.y @@ -1341,7 +1341,6 @@ stmt_for : opt_loop_label K_FOR for_control loop_body new = (PLpgSQL_stmt_fori *) $3; new->lineno = plpgsql_location_to_lineno(@2); - new->stmtid = ++plpgsql_curr_compile->nstatements; new->label = $1; new->body = $4.stmts; $$ = (PLpgSQL_stmt *) new; @@ -1356,7 +1355,6 @@ stmt_for : opt_loop_label K_FOR for_control loop_body /* forq is the common supertype of all three */ new = (PLpgSQL_stmt_forq *) $3; new->lineno = plpgsql_location_to_lineno(@2); - new->stmtid = ++plpgsql_curr_compile->nstatements; new->label = $1; new->body = $4.stmts; $$ = (PLpgSQL_stmt *) new; From 479331406e8403cc2e75d1082f8c613e7669c113 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 2 Feb 2021 16:15:29 -0500 Subject: [PATCH 235/240] Doc: consistently identify OID catalog columns that can be zero. Not all OID-reference columns that can contain zeroes (indicating "no reference") were explicitly marked in catalogs.sgml. Fix that, and try to make the style a little more consistent while at it --- for example, consistently write "zero" not "0" for these cases. Joel Jacobson and Tom Lane Discussion: https://postgr.es/m/4ed9a372-7bf9-479a-926c-ae8e774717a8@www.fastmail.com --- doc/src/sgml/catalogs.sgml | 128 ++++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 58 deletions(-) diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 865e826fb0b34..ea222c04640b1 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -1150,7 +1150,7 @@ (references pg_type.oid) - The data type of this column + The data type of this column (zero for a dropped column) @@ -1351,7 +1351,7 @@ The defined collation of the column, or zero if the column is - not of a collatable data type. + not of a collatable data type @@ -1899,8 +1899,8 @@ SCRAM-SHA-256$<iteration count>:&l The OID of the data type that corresponds to this table's row type, - if any (zero for indexes, sequences, and toast tables, which have - no pg_type entry) + if any; zero for indexes, sequences, and toast tables, which have + no pg_type entry @@ -1910,7 +1910,7 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_type.oid) - For typed tables, the OID of the underlying composite type, + For typed tables, the OID of the underlying composite type; zero for all other relations @@ -1932,7 +1932,8 @@ SCRAM-SHA-256$<iteration count>:&l If this is a table or an index, the access method used (heap, - B-tree, hash, etc.) + B-tree, hash, etc.); otherwise zero (zero occurs for sequences, + as well as relations without storage, such as views) @@ -2007,7 +2008,7 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_class.oid) - OID of the TOAST table associated with this table, 0 if none. The + OID of the TOAST table associated with this table, zero if none. The TOAST table stores large attributes out of line in a secondary table. @@ -2174,8 +2175,8 @@ SCRAM-SHA-256$<iteration count>:&l For new relations being written during a DDL operation that requires a table rewrite, this contains the OID of the original relation; - otherwise 0. That state is only visible internally; this field should - never contain anything other than 0 for a user-visible relation. + otherwise zero. That state is only visible internally; this field should + never contain anything other than zero for a user-visible relation. @@ -2507,7 +2508,7 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_class.oid) - The table this constraint is on; 0 if not a table constraint + The table this constraint is on; zero if not a table constraint @@ -2517,7 +2518,7 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_type.oid) - The domain this constraint is on; 0 if not a domain constraint + The domain this constraint is on; zero if not a domain constraint @@ -2528,7 +2529,7 @@ SCRAM-SHA-256$<iteration count>:&l The index supporting this constraint, if it's a unique, primary - key, foreign key, or exclusion constraint; else 0 + key, foreign key, or exclusion constraint; else zero @@ -2538,8 +2539,8 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_constraint.oid) - The corresponding constraint in the parent partitioned table, - if this is a constraint in a partition; else 0 + The corresponding constraint of the parent partitioned table, + if this is a constraint on a partition; else zero @@ -2549,7 +2550,7 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_class.oid) - If a foreign key, the referenced table; else 0 + If a foreign key, the referenced table; else zero @@ -3142,7 +3143,7 @@ SCRAM-SHA-256$<iteration count>:&l The OID of the namespace associated with this entry, - or 0 if none + or zero if none @@ -3176,7 +3177,7 @@ SCRAM-SHA-256$<iteration count>:&l A pg_default_acl entry shows the initial privileges to be assigned to an object belonging to the indicated user. There are currently two types of entry: global entries with - defaclnamespace = 0, and per-schema entries + defaclnamespace = zero, and per-schema entries that reference a particular schema. If a global entry is present then it overrides the normal hard-wired default privileges for the object type. A per-schema entry, if present, represents privileges @@ -3236,7 +3237,8 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_class.oid) - The OID of the system catalog the dependent object is in + The OID of the system catalog the dependent object is in, + or zero for a DEPENDENCY_PIN entry @@ -3246,7 +3248,8 @@ SCRAM-SHA-256$<iteration count>:&l (references any OID column) - The OID of the specific dependent object + The OID of the specific dependent object, + or zero for a DEPENDENCY_PIN entry @@ -4687,7 +4690,7 @@ SCRAM-SHA-256$<iteration count>:&l For noninternal languages this references the language handler, which is a special function that is responsible for executing all functions that are written in the particular - language + language. Zero for internal languages. @@ -5189,7 +5192,7 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_type.oid) - Type of the left operand (0 if none) + Type of the left operand (zero for a prefix operator) @@ -5210,6 +5213,7 @@ SCRAM-SHA-256$<iteration count>:&l Type of the result + (zero for a not-yet-defined shell operator) @@ -5219,7 +5223,7 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_operator.oid) - Commutator of this operator, if any + Commutator of this operator (zero if none) @@ -5229,7 +5233,7 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_operator.oid) - Negator of this operator, if any + Negator of this operator (zero if none) @@ -5240,6 +5244,7 @@ SCRAM-SHA-256$<iteration count>:&l Function that implements this operator + (zero for a not-yet-defined shell operator) @@ -5250,6 +5255,7 @@ SCRAM-SHA-256$<iteration count>:&l Restriction selectivity estimation function for this operator + (zero if none) @@ -5260,17 +5266,13 @@ SCRAM-SHA-256$<iteration count>:&l Join selectivity estimation function for this operator + (zero if none)
- - Unused columns contain zeroes. For example, oprleft - is zero for a prefix operator. - - @@ -5426,7 +5428,7 @@ SCRAM-SHA-256$<iteration count>:&l partnatts int2
- The number of columns in partition key + The number of columns in the partition key
@@ -5438,7 +5440,7 @@ SCRAM-SHA-256$<iteration count>:&l The OID of the pg_class entry for the default partition of this partitioned table, or zero if this partitioned table does not - have a default partition. + have a default partition @@ -5588,7 +5590,9 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_authid.oid) - The roles to which the policy is applied + The roles to which the policy is applied; + zero means PUBLIC + (and normally appears alone in the array) @@ -5744,8 +5748,8 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_proc.oid) - Optional planner support function for this function - (see ) + Planner support function for this function + (see ), or zero if none @@ -6256,7 +6260,7 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_collation.oid) - OID of the collation used for range comparisons, or 0 if none + OID of the collation used for range comparisons, or zero if none @@ -6277,7 +6281,7 @@ SCRAM-SHA-256$<iteration count>:&l OID of the function to convert a range value into canonical form, - or 0 if none + or zero if none @@ -6288,7 +6292,7 @@ SCRAM-SHA-256$<iteration count>:&l OID of the function to return the difference between two element - values as double precision, or 0 if none + values as double precision, or zero if none @@ -6733,6 +6737,7 @@ SCRAM-SHA-256$<iteration count>:&l The OID of the database the dependent object is in, or zero for a shared object + or a SHARED_DEPENDENCY_PIN entry @@ -6742,7 +6747,8 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_class.oid) - The OID of the system catalog the dependent object is in + The OID of the system catalog the dependent object is in, + or zero for a SHARED_DEPENDENCY_PIN entry @@ -6752,7 +6758,8 @@ SCRAM-SHA-256$<iteration count>:&l (references any OID column) - The OID of the specific dependent object + The OID of the specific dependent object, + or zero for a SHARED_DEPENDENCY_PIN entry @@ -7192,6 +7199,7 @@ SCRAM-SHA-256$<iteration count>:&l Nth slot. For example, a histogram slot would show the < operator that defines the sort order of the data. + Zero if the statistics kind does not require an operator. @@ -7836,7 +7844,7 @@ SCRAM-SHA-256$<iteration count>:&l The OID of the function to use when converting the data type for input to the procedural language (e.g., function parameters). Zero is stored - if this operation is not supported. + if the default behavior should be used. @@ -7848,7 +7856,7 @@ SCRAM-SHA-256$<iteration count>:&l The OID of the function to use when converting output from the procedural language (e.g., return values) to the data type. Zero is - stored if this operation is not supported. + stored if the default behavior should be used. @@ -7911,9 +7919,9 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_trigger.oid) - Parent trigger that this trigger is cloned from, zero if not a clone; - this happens when partitions are created or attached to a partitioned - table. + Parent trigger that this trigger is cloned from (this happens when + partitions are created or attached to a partitioned table); + zero if not a clone @@ -7976,6 +7984,7 @@ SCRAM-SHA-256$<iteration count>:&l The table referenced by a referential integrity constraint + (zero if trigger is not for a referential integrity constraint) @@ -7987,6 +7996,7 @@ SCRAM-SHA-256$<iteration count>:&l The index supporting a unique, primary key, referential integrity, or exclusion constraint + (zero if trigger is not for one of these types of constraint) @@ -7996,7 +8006,8 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_constraint.oid) - The pg_constraint entry associated with the trigger, if any + The pg_constraint entry associated with the trigger + (zero if trigger is not for a constraint) @@ -8478,7 +8489,7 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_proc.oid) - OID of the parser's headline function + OID of the parser's headline function (zero if none) @@ -8566,7 +8577,7 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_proc.oid) - OID of the template's initialization function + OID of the template's initialization function (zero if none) @@ -8786,11 +8797,11 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_type.oid) - If typelem is not 0 then it + If typelem is not zero then it identifies another row in pg_type, - defining the type yielded by subscripting. This should be 0 - if typsubscript is 0. However, it can - be 0 when typsubscript isn't 0, if the + defining the type yielded by subscripting. This should be zero + if typsubscript is zero. However, it can + be zero when typsubscript isn't zero, if the handler doesn't need typelem to determine the subscripting result type. Note that a typelem dependency is @@ -8806,7 +8817,7 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_type.oid) - If typarray is not 0 then it + If typarray is not zero then it identifies another row in pg_type, which is the true array type having this type as element @@ -8838,7 +8849,7 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_proc.oid) - Input conversion function (binary format), or 0 if none + Input conversion function (binary format), or zero if none @@ -8848,7 +8859,7 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_proc.oid) - Output conversion function (binary format), or 0 if none + Output conversion function (binary format), or zero if none @@ -8858,7 +8869,7 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_proc.oid) - Type modifier input function, or 0 if type does not support modifiers + Type modifier input function, or zero if type does not support modifiers @@ -8868,7 +8879,7 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_proc.oid) - Type modifier output function, or 0 to use the standard format + Type modifier output function, or zero to use the standard format @@ -8878,7 +8889,8 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_proc.oid) - Custom function, or 0 to use the standard function + Custom function, + or zero to use the standard function @@ -9198,7 +9210,7 @@ SCRAM-SHA-256$<iteration count>:&l (references pg_authid.oid) - OID of the local role being mapped, 0 if the user mapping is public + OID of the local role being mapped, or zero if the user mapping is public @@ -13403,7 +13415,7 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx (references pg_authid.oid) - OID of the local role being mapped, 0 if the user mapping is public + OID of the local role being mapped, or zero if the user mapping is public From 62f34097c88433ef1f3de604714fe7e7024f2fdf Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 2 Feb 2021 17:11:55 -0500 Subject: [PATCH 236/240] Build in some knowledge about foreign-key relationships in the catalogs. This follows in the spirit of commit dfb75e478, which created primary key and uniqueness constraints to improve the visibility of constraints imposed on the system catalogs. While our catalogs contain many foreign-key-like relationships, they don't quite follow SQL semantics, in that the convention for an omitted reference is to write zero not NULL. Plus, we have some cases in which there are arrays each of whose elements is supposed to be an FK reference; SQL has no way to model that. So we can't create actual foreign key constraints to describe the situation. Nonetheless, we can collect and use knowledge about these relationships. This patch therefore adds annotations to the catalog header files to declare foreign-key relationships. (The BKI_LOOKUP annotations cover simple cases, but we weren't previously distinguishing which such columns are allowed to contain zeroes; we also need new markings for multi-column FK references.) Then, Catalog.pm and genbki.pl are taught to collect this information into a table in a new generated header "system_fk_info.h". The only user of that at the moment is a new SQL function pg_get_catalog_foreign_keys(), which exposes the table to SQL. The oidjoins regression test is rewritten to use pg_get_catalog_foreign_keys() to find out which columns to check. Aside from removing the need for manual maintenance of that test script, this allows it to cover numerous relationships that were not checked by the old implementation based on findoidjoins. (As of this commit, 217 relationships are checked by the test, versus 181 before.) Discussion: https://postgr.es/m/3240355.1612129197@sss.pgh.pa.us --- doc/src/sgml/bki.sgml | 25 +- doc/src/sgml/func.sgml | 32 + src/backend/catalog/.gitignore | 1 + src/backend/catalog/Catalog.pm | 28 +- src/backend/catalog/Makefile | 2 +- src/backend/catalog/genbki.pl | 123 +- src/backend/utils/adt/misc.c | 80 + src/include/Makefile | 5 +- src/include/catalog/.gitignore | 1 + src/include/catalog/catversion.h | 2 +- src/include/catalog/genbki.h | 36 +- src/include/catalog/pg_aggregate.h | 18 +- src/include/catalog/pg_amop.h | 2 +- src/include/catalog/pg_attrdef.h | 5 +- src/include/catalog/pg_attribute.h | 14 +- src/include/catalog/pg_auth_members.h | 6 +- src/include/catalog/pg_cast.h | 2 +- src/include/catalog/pg_class.h | 22 +- src/include/catalog/pg_collation.dat | 15 +- src/include/catalog/pg_collation.h | 5 +- src/include/catalog/pg_constraint.h | 29 +- src/include/catalog/pg_conversion.h | 4 +- src/include/catalog/pg_database.h | 2 +- src/include/catalog/pg_db_role_setting.h | 7 +- src/include/catalog/pg_default_acl.h | 6 +- src/include/catalog/pg_depend.h | 6 +- src/include/catalog/pg_description.h | 3 + src/include/catalog/pg_enum.h | 2 +- src/include/catalog/pg_event_trigger.h | 5 +- src/include/catalog/pg_extension.h | 8 +- src/include/catalog/pg_foreign_data_wrapper.h | 9 +- src/include/catalog/pg_foreign_server.h | 4 +- src/include/catalog/pg_foreign_table.h | 4 +- src/include/catalog/pg_index.h | 12 +- src/include/catalog/pg_inherits.h | 4 +- src/include/catalog/pg_init_privs.h | 3 +- src/include/catalog/pg_language.h | 8 +- src/include/catalog/pg_largeobject.h | 3 +- src/include/catalog/pg_largeobject_metadata.h | 3 +- src/include/catalog/pg_namespace.dat | 6 +- src/include/catalog/pg_namespace.h | 2 +- src/include/catalog/pg_opclass.h | 8 +- src/include/catalog/pg_operator.h | 22 +- src/include/catalog/pg_opfamily.h | 4 +- src/include/catalog/pg_partitioned_table.h | 17 +- src/include/catalog/pg_policy.h | 7 +- src/include/catalog/pg_proc.dat | 12 +- src/include/catalog/pg_proc.h | 12 +- src/include/catalog/pg_publication.h | 2 +- src/include/catalog/pg_publication_rel.h | 4 +- src/include/catalog/pg_range.h | 6 +- src/include/catalog/pg_rewrite.h | 2 +- src/include/catalog/pg_seclabel.h | 3 +- src/include/catalog/pg_sequence.h | 4 +- src/include/catalog/pg_shdepend.h | 9 +- src/include/catalog/pg_shdescription.h | 3 + src/include/catalog/pg_shseclabel.h | 3 +- src/include/catalog/pg_statistic.h | 25 +- src/include/catalog/pg_statistic_ext.h | 10 +- src/include/catalog/pg_statistic_ext_data.h | 3 +- src/include/catalog/pg_subscription.h | 5 +- src/include/catalog/pg_subscription_rel.h | 4 +- src/include/catalog/pg_tablespace.dat | 6 +- src/include/catalog/pg_tablespace.h | 2 +- src/include/catalog/pg_transform.h | 8 +- src/include/catalog/pg_trigger.h | 21 +- src/include/catalog/pg_ts_config.h | 4 +- src/include/catalog/pg_ts_dict.h | 4 +- src/include/catalog/pg_ts_parser.h | 4 +- src/include/catalog/pg_ts_template.h | 4 +- src/include/catalog/pg_type.h | 26 +- src/include/catalog/pg_user_mapping.h | 8 +- src/test/regress/expected/oidjoins.out | 1713 +++-------------- src/test/regress/parallel_schedule | 5 +- src/test/regress/serial_schedule | 2 +- src/test/regress/sql/oidjoins.sql | 772 +------- src/tools/msvc/Solution.pm | 3 + src/tools/msvc/clean.bat | 2 + 78 files changed, 901 insertions(+), 2402 deletions(-) diff --git a/doc/src/sgml/bki.sgml b/doc/src/sgml/bki.sgml index 036a72c81e9c8..6d3c5be67f8d1 100644 --- a/doc/src/sgml/bki.sgml +++ b/doc/src/sgml/bki.sgml @@ -474,10 +474,15 @@ - In such a column, all entries must use the symbolic format except - when writing 0 for InvalidOid. (If the column is + In some catalog columns, it's allowed for entries to be zero instead + of a valid reference. If this is allowed, write + BKI_LOOKUP_OPT instead + of BKI_LOOKUP. Then you can + write 0 for an entry. (If the column is declared regproc, you can optionally write - instead of 0.) + Except for this special case, all entries in + a BKI_LOOKUP column must be symbolic references. genbki.pl will warn about unrecognized names. @@ -554,6 +559,22 @@ therefore no need for the bootstrap backend to deal with symbolic references. + + + It's desirable to mark OID reference columns + with BKI_LOOKUP or BKI_LOOKUP_OPT + even if the catalog has no initial data that requires lookup. This + allows genbki.pl to record the foreign key + relationships that exist in the system catalogs. That information is + used in the regression tests to check for incorrect entries. See also + the macros DECLARE_FOREIGN_KEY, + DECLARE_FOREIGN_KEY_OPT, + DECLARE_ARRAY_FOREIGN_KEY, + and DECLARE_ARRAY_FOREIGN_KEY_OPT, which are + used to declare foreign key relationships that are too complex + for BKI_LOOKUP (typically, multi-column foreign + keys). + diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 081f04ce1a9fb..b7150510aba46 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -22789,6 +22789,38 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); + + + + pg_get_catalog_foreign_keys + + pg_get_catalog_foreign_keys () + setof record + ( fktable regclass, + fkcols text[], + pktable regclass, + pkcols text[], + is_array boolean, + is_opt boolean ) + + + Returns a set of records describing the foreign key relationships + that exist within the PostgreSQL system + catalogs. + The fktable column contains the name of the + referencing catalog, and the fkcols column + contains the name(s) of the referencing column(s). Similarly, + the pktable column contains the name of the + referenced catalog, and the pkcols column + contains the name(s) of the referenced column(s). + If is_array is true, the last referencing + column is an array, each of whose elements should match some entry + in the referenced catalog. + If is_opt is true, the referencing column(s) + are allowed to contain zeroes instead of a valid reference. + + + diff --git a/src/backend/catalog/.gitignore b/src/backend/catalog/.gitignore index 4bd3ee9d7f391..237ff541659b1 100644 --- a/src/backend/catalog/.gitignore +++ b/src/backend/catalog/.gitignore @@ -1,5 +1,6 @@ /postgres.bki /schemapg.h +/system_fk_info.h /system_constraints.sql /pg_*_d.h /bki-stamp diff --git a/src/backend/catalog/Catalog.pm b/src/backend/catalog/Catalog.pm index 061f3d8c21ebd..b44d568b54440 100644 --- a/src/backend/catalog/Catalog.pm +++ b/src/backend/catalog/Catalog.pm @@ -105,6 +105,17 @@ sub ParseHeader index_decl => $5 }; } + elsif (/^DECLARE_(ARRAY_)?FOREIGN_KEY(_OPT)?\(\s*\(([^)]+)\),\s*(\w+),\s*\(([^)]+)\)\)/) + { + push @{ $catalog{foreign_keys} }, + { + is_array => $1 ? 1 : 0, + is_opt => $2 ? 1 : 0, + fk_cols => $3, + pk_table => $4, + pk_cols => $5 + }; + } elsif (/^CATALOG\((\w+),(\d+),(\w+)\)/) { $catalog{catname} = $1; @@ -197,9 +208,22 @@ sub ParseHeader { $column{array_default} = $1; } - elsif ($attopt =~ /BKI_LOOKUP\((\w+)\)/) + elsif ($attopt =~ /BKI_LOOKUP(_OPT)?\((\w+)\)/) { - $column{lookup} = $1; + $column{lookup} = $2; + $column{lookup_opt} = $1 ? 1 : 0; + # BKI_LOOKUP implicitly makes an FK reference + push @{ $catalog{foreign_keys} }, + { + is_array => + ($atttype eq 'oidvector' || $atttype eq '_oid') + ? 1 + : 0, + is_opt => $column{lookup_opt}, + fk_cols => $attname, + pk_table => $column{lookup}, + pk_cols => 'oid' + }; } else { diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index 995ddf128523f..70bc2123df7bf 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -70,7 +70,7 @@ CATALOG_HEADERS := \ pg_sequence.h pg_publication.h pg_publication_rel.h pg_subscription.h \ pg_subscription_rel.h -GENERATED_HEADERS := $(CATALOG_HEADERS:%.h=%_d.h) schemapg.h +GENERATED_HEADERS := $(CATALOG_HEADERS:%.h=%_d.h) schemapg.h system_fk_info.h POSTGRES_BKI_SRCS := $(addprefix $(top_srcdir)/src/include/catalog/, $(CATALOG_HEADERS)) diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl index b68c1752c0098..5bdc7adc44022 100644 --- a/src/backend/catalog/genbki.pl +++ b/src/backend/catalog/genbki.pl @@ -213,6 +213,12 @@ $amoids{ $row->{amname} } = $row->{oid}; } +# There is only one authid at bootstrap time, and we handle it specially: +# the usually-defaulted symbol PGUID becomes the bootstrap superuser's OID. +# (We could drop this in favor of writing out BKI_DEFAULT(POSTGRES) ...) +my %authidoids; +$authidoids{'PGUID'} = $BOOTSTRAP_SUPERUSERID; + # class (relation) OID lookup (note this only covers bootstrap catalogs!) my %classoids; foreach my $row (@{ $catalog_data{pg_class} }) @@ -234,6 +240,12 @@ $langoids{ $row->{lanname} } = $row->{oid}; } +# There is only one namespace at bootstrap time, and we handle it specially: +# the usually-defaulted symbol PGNSP becomes the pg_catalog namespace's OID. +# (We could drop this in favor of writing out BKI_DEFAULT(pg_catalog) ...) +my %namespaceoids; +$namespaceoids{'PGNSP'} = $PG_CATALOG_NAMESPACE; + # opclass OID lookup my %opcoids; foreach my $row (@{ $catalog_data{pg_opclass} }) @@ -376,9 +388,11 @@ # Map lookup name to the corresponding hash table. my %lookup_kind = ( pg_am => \%amoids, + pg_authid => \%authidoids, pg_class => \%classoids, pg_collation => \%collationoids, pg_language => \%langoids, + pg_namespace => \%namespaceoids, pg_opclass => \%opcoids, pg_operator => \%operoids, pg_opfamily => \%opfoids, @@ -400,6 +414,9 @@ my $schemafile = $output_path . 'schemapg.h'; open my $schemapg, '>', $schemafile . $tmpext or die "can't open $schemafile$tmpext: $!"; +my $fk_info_file = $output_path . 'system_fk_info.h'; +open my $fk_info, '>', $fk_info_file . $tmpext + or die "can't open $fk_info_file$tmpext: $!"; my $constraints_file = $output_path . 'system_constraints.sql'; open my $constraints, '>', $constraints_file . $tmpext or die "can't open $constraints_file$tmpext: $!"; @@ -554,18 +571,14 @@ $GenbkiNextOid++; } - # Substitute constant values we acquired above. - # (It's intentional that this can apply to parts of a field). - $bki_values{$attname} =~ s/\bPGUID\b/$BOOTSTRAP_SUPERUSERID/g; - $bki_values{$attname} =~ s/\bPGNSP\b/$PG_CATALOG_NAMESPACE/g; - # Replace OID synonyms with OIDs per the appropriate lookup rule. # # If the column type is oidvector or _oid, we have to replace # each element of the array as per the lookup rule. if ($column->{lookup}) { - my $lookup = $lookup_kind{ $column->{lookup} }; + my $lookup = $lookup_kind{ $column->{lookup} }; + my $lookup_opt = $column->{lookup_opt}; my @lookupnames; my @lookupoids; @@ -575,8 +588,9 @@ if ($atttype eq 'oidvector') { @lookupnames = split /\s+/, $bki_values{$attname}; - @lookupoids = lookup_oids($lookup, $catname, \%bki_values, - @lookupnames); + @lookupoids = + lookup_oids($lookup, $catname, $attname, $lookup_opt, + \%bki_values, @lookupnames); $bki_values{$attname} = join(' ', @lookupoids); } elsif ($atttype eq '_oid') @@ -586,8 +600,8 @@ $bki_values{$attname} =~ s/[{}]//g; @lookupnames = split /,/, $bki_values{$attname}; @lookupoids = - lookup_oids($lookup, $catname, \%bki_values, - @lookupnames); + lookup_oids($lookup, $catname, $attname, + $lookup_opt, \%bki_values, @lookupnames); $bki_values{$attname} = sprintf "{%s}", join(',', @lookupoids); } @@ -595,8 +609,9 @@ else { $lookupnames[0] = $bki_values{$attname}; - @lookupoids = lookup_oids($lookup, $catname, \%bki_values, - @lookupnames); + @lookupoids = + lookup_oids($lookup, $catname, $attname, $lookup_opt, + \%bki_values, @lookupnames); $bki_values{$attname} = $lookupoids[0]; } } @@ -706,14 +721,78 @@ # Closing boilerplate for schemapg.h print $schemapg "\n#endif\t\t\t\t\t\t\t/* SCHEMAPG_H */\n"; +# Now generate system_fk_info.h + +# Opening boilerplate for system_fk_info.h +print $fk_info <{foreign_keys} }) + { + my $pktabname = $fkinfo->{pk_table}; + + # We use BKI_LOOKUP for encodings, but there's no real catalog there + next if $pktabname eq 'encoding'; + + printf $fk_info + "\t{ /* %s */ %s, /* %s */ %s, \"{%s}\", \"{%s}\", %s, %s},\n", + $catname, $catalog->{relation_oid}, + $pktabname, $catalogs{$pktabname}->{relation_oid}, + $fkinfo->{fk_cols}, + $fkinfo->{pk_cols}, + ($fkinfo->{is_array} ? "true" : "false"), + ($fkinfo->{is_opt} ? "true" : "false"); + } +} + +# Closing boilerplate for system_fk_info.h +print $fk_info "};\n\n#endif\t\t\t\t\t\t\t/* SYSTEM_FK_INFO_H */\n"; + # We're done emitting data close $bki; close $schemapg; +close $fk_info; close $constraints; # Finally, rename the completed files into place. Catalog::RenameTempFile($bkifile, $tmpext); Catalog::RenameTempFile($schemafile, $tmpext); +Catalog::RenameTempFile($fk_info_file, $tmpext); Catalog::RenameTempFile($constraints_file, $tmpext); exit 0; @@ -948,7 +1027,8 @@ sub morph_row_for_schemapg # within this genbki.pl run.) sub lookup_oids { - my ($lookup, $catname, $bki_values, @lookupnames) = @_; + my ($lookup, $catname, $attname, $lookup_opt, $bki_values, @lookupnames) + = @_; my @lookupoids; foreach my $lookupname (@lookupnames) @@ -961,10 +1041,19 @@ sub lookup_oids else { push @lookupoids, $lookupname; - warn sprintf - "unresolved OID reference \"%s\" in %s.dat line %s\n", - $lookupname, $catname, $bki_values->{line_number} - if $lookupname ne '-' and $lookupname ne '0'; + if ($lookupname eq '-' or $lookupname eq '0') + { + warn sprintf + "invalid zero OID reference in %s.dat field %s line %s\n", + $catname, $attname, $bki_values->{line_number} + if !$lookup_opt; + } + else + { + warn sprintf + "unresolved OID reference \"%s\" in %s.dat field %s line %s\n", + $lookupname, $catname, $attname, $bki_values->{line_number}; + } } } return @lookupoids; diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index 4096faff9a196..634f574d7eb89 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -25,6 +25,7 @@ #include "catalog/catalog.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_type.h" +#include "catalog/system_fk_info.h" #include "commands/dbcommands.h" #include "commands/tablespace.h" #include "common/keywords.h" @@ -37,6 +38,7 @@ #include "storage/fd.h" #include "tcop/tcopprot.h" #include "utils/builtins.h" +#include "utils/fmgroids.h" #include "utils/lsyscache.h" #include "utils/ruleutils.h" #include "utils/timestamp.h" @@ -489,6 +491,84 @@ pg_get_keywords(PG_FUNCTION_ARGS) } +/* Function to return the list of catalog foreign key relationships */ +Datum +pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS) +{ + FuncCallContext *funcctx; + FmgrInfo *arrayinp; + + if (SRF_IS_FIRSTCALL()) + { + MemoryContext oldcontext; + TupleDesc tupdesc; + + funcctx = SRF_FIRSTCALL_INIT(); + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + + tupdesc = CreateTemplateTupleDesc(6); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "fktable", + REGCLASSOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "fkcols", + TEXTARRAYOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "pktable", + REGCLASSOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 4, "pkcols", + TEXTARRAYOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 5, "is_array", + BOOLOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 6, "is_opt", + BOOLOID, -1, 0); + + funcctx->tuple_desc = BlessTupleDesc(tupdesc); + + /* + * We use array_in to convert the C strings in sys_fk_relationships[] + * to text arrays. But we cannot use DirectFunctionCallN to call + * array_in, and it wouldn't be very efficient if we could. Fill an + * FmgrInfo to use for the call. + */ + arrayinp = (FmgrInfo *) palloc(sizeof(FmgrInfo)); + fmgr_info(F_ARRAY_IN, arrayinp); + funcctx->user_fctx = arrayinp; + + MemoryContextSwitchTo(oldcontext); + } + + funcctx = SRF_PERCALL_SETUP(); + arrayinp = (FmgrInfo *) funcctx->user_fctx; + + if (funcctx->call_cntr < lengthof(sys_fk_relationships)) + { + const SysFKRelationship *fkrel = &sys_fk_relationships[funcctx->call_cntr]; + Datum values[6]; + bool nulls[6]; + HeapTuple tuple; + + memset(nulls, false, sizeof(nulls)); + + values[0] = ObjectIdGetDatum(fkrel->fk_table); + values[1] = FunctionCall3(arrayinp, + CStringGetDatum(fkrel->fk_columns), + ObjectIdGetDatum(TEXTOID), + Int32GetDatum(-1)); + values[2] = ObjectIdGetDatum(fkrel->pk_table); + values[3] = FunctionCall3(arrayinp, + CStringGetDatum(fkrel->pk_columns), + ObjectIdGetDatum(TEXTOID), + Int32GetDatum(-1)); + values[4] = BoolGetDatum(fkrel->is_array); + values[5] = BoolGetDatum(fkrel->is_opt); + + tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); + + SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); + } + + SRF_RETURN_DONE(funcctx); +} + + /* * Return the type of the argument. */ diff --git a/src/include/Makefile b/src/include/Makefile index c557375ae310f..5f257a958c800 100644 --- a/src/include/Makefile +++ b/src/include/Makefile @@ -54,7 +54,7 @@ install: all installdirs cp $(srcdir)/$$dir/*.h '$(DESTDIR)$(includedir_server)'/$$dir/ || exit; \ done ifeq ($(vpath_build),yes) - for file in catalog/schemapg.h catalog/pg_*_d.h parser/gram.h storage/lwlocknames.h utils/probes.h; do \ + for file in catalog/schemapg.h catalog/system_fk_info.h catalog/pg_*_d.h parser/gram.h storage/lwlocknames.h utils/probes.h; do \ cp $$file '$(DESTDIR)$(includedir_server)'/$$file || exit; \ done endif @@ -79,7 +79,8 @@ uninstall: clean: rm -f utils/fmgroids.h utils/fmgrprotos.h utils/errcodes.h utils/header-stamp rm -f parser/gram.h storage/lwlocknames.h utils/probes.h - rm -f catalog/schemapg.h catalog/pg_*_d.h catalog/header-stamp + rm -f catalog/schemapg.h catalog/system_fk_info.h + rm -f catalog/pg_*_d.h catalog/header-stamp distclean maintainer-clean: clean rm -f pg_config.h pg_config_ext.h pg_config_os.h stamp-h stamp-ext-h diff --git a/src/include/catalog/.gitignore b/src/include/catalog/.gitignore index 6c8da5401ddf4..6b83d4c7e6e5c 100644 --- a/src/include/catalog/.gitignore +++ b/src/include/catalog/.gitignore @@ -1,3 +1,4 @@ /schemapg.h +/system_fk_info.h /pg_*_d.h /header-stamp diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 133f4ee3094ca..638830aaac1aa 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202101311 +#define CATALOG_VERSION_NO 202102021 #endif diff --git a/src/include/catalog/genbki.h b/src/include/catalog/genbki.h index 5d05fafb5dae9..b1fee54d3c290 100644 --- a/src/include/catalog/genbki.h +++ b/src/include/catalog/genbki.h @@ -36,10 +36,15 @@ /* Specifies a default value for auto-generated array types */ #define BKI_ARRAY_DEFAULT(value) /* - * Indicates how to perform name lookups, typically for an OID or - * OID-array field + * Indicates that the attribute contains OIDs referencing the named catalog; + * can be applied to columns of oid, regproc, oid[], or oidvector type. + * genbki.pl uses this to know how to perform name lookups in the initial + * data (if any), and it also feeds into regression-test validity checks. + * The _OPT suffix indicates that values can be zero instead of + * a valid OID reference. */ #define BKI_LOOKUP(catalog) +#define BKI_LOOKUP_OPT(catalog) /* * These lines are processed by genbki.pl to create the statements @@ -75,6 +80,33 @@ #define DECLARE_UNIQUE_INDEX(name,oid,decl) extern int no_such_variable #define DECLARE_UNIQUE_INDEX_PKEY(name,oid,decl) extern int no_such_variable +/* + * These lines are processed by genbki.pl to create a table for use + * by the pg_get_catalog_foreign_keys() function. We do not have any + * mechanism that actually enforces foreign-key relationships in the + * system catalogs, but it is still useful to record the intended + * relationships in a machine-readable form. + * + * The keyword is DECLARE_FOREIGN_KEY[_OPT] or DECLARE_ARRAY_FOREIGN_KEY[_OPT]. + * The first argument is a parenthesized list of the referencing columns; + * the second, the name of the referenced table; the third, a parenthesized + * list of the referenced columns. Use of the ARRAY macros means that the + * last referencing column is an array, each of whose elements is supposed + * to match some entry in the last referenced column. Use of the OPT suffix + * indicates that the referencing column(s) can be zero instead of a valid + * reference. + * + * Columns that are marked with a BKI_LOOKUP rule do not need an explicit + * DECLARE_FOREIGN_KEY macro, as genbki.pl can infer the FK relationship + * from that. Thus, these macros are only needed in special cases. + * + * The macro definitions are just to keep the C compiler from spitting up. + */ +#define DECLARE_FOREIGN_KEY(cols,reftbl,refcols) extern int no_such_variable +#define DECLARE_FOREIGN_KEY_OPT(cols,reftbl,refcols) extern int no_such_variable +#define DECLARE_ARRAY_FOREIGN_KEY(cols,reftbl,refcols) extern int no_such_variable +#define DECLARE_ARRAY_FOREIGN_KEY_OPT(cols,reftbl,refcols) extern int no_such_variable + /* The following are never defined; they are here only for documentation. */ /* diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h index 8b03cdeea2429..25feb41678ff0 100644 --- a/src/include/catalog/pg_aggregate.h +++ b/src/include/catalog/pg_aggregate.h @@ -44,25 +44,25 @@ CATALOG(pg_aggregate,2600,AggregateRelationId) regproc aggtransfn BKI_LOOKUP(pg_proc); /* final function (0 if none) */ - regproc aggfinalfn BKI_DEFAULT(-) BKI_LOOKUP(pg_proc); + regproc aggfinalfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc); /* combine function (0 if none) */ - regproc aggcombinefn BKI_DEFAULT(-) BKI_LOOKUP(pg_proc); + regproc aggcombinefn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc); /* function to convert transtype to bytea (0 if none) */ - regproc aggserialfn BKI_DEFAULT(-) BKI_LOOKUP(pg_proc); + regproc aggserialfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc); /* function to convert bytea to transtype (0 if none) */ - regproc aggdeserialfn BKI_DEFAULT(-) BKI_LOOKUP(pg_proc); + regproc aggdeserialfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc); /* forward function for moving-aggregate mode (0 if none) */ - regproc aggmtransfn BKI_DEFAULT(-) BKI_LOOKUP(pg_proc); + regproc aggmtransfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc); /* inverse function for moving-aggregate mode (0 if none) */ - regproc aggminvtransfn BKI_DEFAULT(-) BKI_LOOKUP(pg_proc); + regproc aggminvtransfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc); /* final function for moving-aggregate mode (0 if none) */ - regproc aggmfinalfn BKI_DEFAULT(-) BKI_LOOKUP(pg_proc); + regproc aggmfinalfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc); /* true to pass extra dummy arguments to aggfinalfn */ bool aggfinalextra BKI_DEFAULT(f); @@ -77,7 +77,7 @@ CATALOG(pg_aggregate,2600,AggregateRelationId) char aggmfinalmodify BKI_DEFAULT(r); /* associated sort operator (0 if none) */ - Oid aggsortop BKI_DEFAULT(0) BKI_LOOKUP(pg_operator); + Oid aggsortop BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_operator); /* type of aggregate's transition (state) data */ Oid aggtranstype BKI_LOOKUP(pg_type); @@ -86,7 +86,7 @@ CATALOG(pg_aggregate,2600,AggregateRelationId) int32 aggtransspace BKI_DEFAULT(0); /* type of moving-aggregate state data (0 if none) */ - Oid aggmtranstype BKI_DEFAULT(0) BKI_LOOKUP(pg_type); + Oid aggmtranstype BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_type); /* estimated size of moving-agg state (0 for default est) */ int32 aggmtransspace BKI_DEFAULT(0); diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h index 554fc41497d62..e1cca35e312a3 100644 --- a/src/include/catalog/pg_amop.h +++ b/src/include/catalog/pg_amop.h @@ -77,7 +77,7 @@ CATALOG(pg_amop,2602,AccessMethodOperatorRelationId) Oid amopmethod BKI_LOOKUP(pg_am); /* ordering opfamily OID, or 0 if search op */ - Oid amopsortfamily BKI_DEFAULT(0) BKI_LOOKUP(pg_opfamily); + Oid amopsortfamily BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_opfamily); } FormData_pg_amop; /* ---------------- diff --git a/src/include/catalog/pg_attrdef.h b/src/include/catalog/pg_attrdef.h index 03efaaded9cc1..d689ca20c8590 100644 --- a/src/include/catalog/pg_attrdef.h +++ b/src/include/catalog/pg_attrdef.h @@ -30,7 +30,8 @@ CATALOG(pg_attrdef,2604,AttrDefaultRelationId) { Oid oid; /* oid */ - Oid adrelid; /* OID of table containing attribute */ + Oid adrelid BKI_LOOKUP(pg_class); /* OID of table containing + * attribute */ int16 adnum; /* attnum of attribute */ #ifdef CATALOG_VARLEN /* variable-length fields start here */ @@ -53,4 +54,6 @@ DECLARE_UNIQUE_INDEX(pg_attrdef_adrelid_adnum_index, 2656, on pg_attrdef using b DECLARE_UNIQUE_INDEX_PKEY(pg_attrdef_oid_index, 2657, on pg_attrdef using btree(oid oid_ops)); #define AttrDefaultOidIndexId 2657 +DECLARE_FOREIGN_KEY((adrelid, adnum), pg_attribute, (attrelid, attnum)); + #endif /* PG_ATTRDEF_H */ diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h index ba0efff08c02b..3db42abf08745 100644 --- a/src/include/catalog/pg_attribute.h +++ b/src/include/catalog/pg_attribute.h @@ -36,7 +36,8 @@ */ CATALOG(pg_attribute,1249,AttributeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(75,AttributeRelation_Rowtype_Id) BKI_SCHEMA_MACRO { - Oid attrelid; /* OID of relation containing this attribute */ + Oid attrelid BKI_LOOKUP(pg_class); /* OID of relation containing + * this attribute */ NameData attname; /* name of attribute */ /* @@ -44,9 +45,12 @@ CATALOG(pg_attribute,1249,AttributeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(75, * defines the data type of this attribute (e.g. int4). Information in * that instance is redundant with the attlen, attbyval, and attalign * attributes of this instance, so they had better match or Postgres will - * fail. + * fail. In an entry for a dropped column, this field is set to zero + * since the pg_type entry may no longer exist; but we rely on attlen, + * attbyval, and attalign to still tell us how large the values in the + * table are. */ - Oid atttypid; + Oid atttypid BKI_LOOKUP_OPT(pg_type); /* * attstattarget is the target number of statistics datapoints to collect @@ -153,8 +157,8 @@ CATALOG(pg_attribute,1249,AttributeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(75, /* Number of times inherited from direct parent relation(s) */ int32 attinhcount BKI_DEFAULT(0); - /* attribute's collation */ - Oid attcollation; + /* attribute's collation, if any */ + Oid attcollation BKI_LOOKUP_OPT(pg_collation); #ifdef CATALOG_VARLEN /* variable-length fields start here */ /* NOTE: The following fields are not present in tuple descriptors. */ diff --git a/src/include/catalog/pg_auth_members.h b/src/include/catalog/pg_auth_members.h index e90c39564088f..76ab90c9395b3 100644 --- a/src/include/catalog/pg_auth_members.h +++ b/src/include/catalog/pg_auth_members.h @@ -29,9 +29,9 @@ */ CATALOG(pg_auth_members,1261,AuthMemRelationId) BKI_SHARED_RELATION BKI_ROWTYPE_OID(2843,AuthMemRelation_Rowtype_Id) BKI_SCHEMA_MACRO { - Oid roleid; /* ID of a role */ - Oid member; /* ID of a member of that role */ - Oid grantor; /* who granted the membership */ + Oid roleid BKI_LOOKUP(pg_authid); /* ID of a role */ + Oid member BKI_LOOKUP(pg_authid); /* ID of a member of that role */ + Oid grantor BKI_LOOKUP(pg_authid); /* who granted the membership */ bool admin_option; /* granted with admin option? */ } FormData_pg_auth_members; diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h index 2d36628c2011d..f64a9df54ce3a 100644 --- a/src/include/catalog/pg_cast.h +++ b/src/include/catalog/pg_cast.h @@ -40,7 +40,7 @@ CATALOG(pg_cast,2605,CastRelationId) Oid casttarget BKI_LOOKUP(pg_type); /* cast function; 0 = binary coercible */ - Oid castfunc BKI_LOOKUP(pg_proc); + Oid castfunc BKI_LOOKUP_OPT(pg_proc); /* contexts in which cast can be used */ char castcontext; diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h index eca306ca98f5d..bb6938caa23fd 100644 --- a/src/include/catalog/pg_class.h +++ b/src/include/catalog/pg_class.h @@ -38,26 +38,26 @@ CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,Relat NameData relname; /* OID of namespace containing this class */ - Oid relnamespace BKI_DEFAULT(PGNSP); + Oid relnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace); - /* OID of entry in pg_type for table's implicit row type */ - Oid reltype BKI_LOOKUP(pg_type); + /* OID of entry in pg_type for relation's implicit row type, if any */ + Oid reltype BKI_LOOKUP_OPT(pg_type); - /* OID of entry in pg_type for underlying composite type */ - Oid reloftype BKI_DEFAULT(0) BKI_LOOKUP(pg_type); + /* OID of entry in pg_type for underlying composite type, if any */ + Oid reloftype BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_type); /* class owner */ - Oid relowner BKI_DEFAULT(PGUID); + Oid relowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); /* access method; 0 if not a table / index */ - Oid relam BKI_DEFAULT(heap) BKI_LOOKUP(pg_am); + Oid relam BKI_DEFAULT(heap) BKI_LOOKUP_OPT(pg_am); /* identifier of physical storage file */ /* relfilenode == 0 means it is a "mapped" relation, see relmapper.c */ Oid relfilenode BKI_DEFAULT(0); /* identifier of table space for relation (0 means default for database) */ - Oid reltablespace BKI_DEFAULT(0) BKI_LOOKUP(pg_tablespace); + Oid reltablespace BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_tablespace); /* # of blocks (not always up-to-date) */ int32 relpages BKI_DEFAULT(0); @@ -69,7 +69,7 @@ CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,Relat int32 relallvisible BKI_DEFAULT(0); /* OID of toast table; 0 if none */ - Oid reltoastrelid BKI_DEFAULT(0); + Oid reltoastrelid BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_class); /* T if has (or has had) any indexes */ bool relhasindex BKI_DEFAULT(f); @@ -119,8 +119,8 @@ CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,Relat /* is relation a partition? */ bool relispartition BKI_DEFAULT(f); - /* heap for rewrite during DDL, link to original rel */ - Oid relrewrite BKI_DEFAULT(0); + /* link to original rel during table rewrite; otherwise 0 */ + Oid relrewrite BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_class); /* all Xids < this are frozen in this rel */ TransactionId relfrozenxid BKI_DEFAULT(3); /* FirstNormalTransactionId */ diff --git a/src/include/catalog/pg_collation.dat b/src/include/catalog/pg_collation.dat index ad57b0fa6d141..6e0ab1ab4b83a 100644 --- a/src/include/catalog/pg_collation.dat +++ b/src/include/catalog/pg_collation.dat @@ -14,18 +14,15 @@ { oid => '100', oid_symbol => 'DEFAULT_COLLATION_OID', descr => 'database\'s default collation', - collname => 'default', collnamespace => 'PGNSP', collowner => 'PGUID', - collprovider => 'd', collencoding => '-1', collcollate => '', - collctype => '' }, + collname => 'default', collprovider => 'd', collencoding => '-1', + collcollate => '', collctype => '' }, { oid => '950', oid_symbol => 'C_COLLATION_OID', descr => 'standard C collation', - collname => 'C', collnamespace => 'PGNSP', collowner => 'PGUID', - collprovider => 'c', collencoding => '-1', collcollate => 'C', - collctype => 'C' }, + collname => 'C', collprovider => 'c', collencoding => '-1', + collcollate => 'C', collctype => 'C' }, { oid => '951', oid_symbol => 'POSIX_COLLATION_OID', descr => 'standard POSIX collation', - collname => 'POSIX', collnamespace => 'PGNSP', collowner => 'PGUID', - collprovider => 'c', collencoding => '-1', collcollate => 'POSIX', - collctype => 'POSIX' }, + collname => 'POSIX', collprovider => 'c', collencoding => '-1', + collcollate => 'POSIX', collctype => 'POSIX' }, ] diff --git a/src/include/catalog/pg_collation.h b/src/include/catalog/pg_collation.h index 3c496ea914184..3bd7873c6885f 100644 --- a/src/include/catalog/pg_collation.h +++ b/src/include/catalog/pg_collation.h @@ -30,8 +30,9 @@ CATALOG(pg_collation,3456,CollationRelationId) { Oid oid; /* oid */ NameData collname; /* collation name */ - Oid collnamespace; /* OID of namespace containing collation */ - Oid collowner; /* owner of collation */ + Oid collnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace); /* OID of namespace + * containing collation */ + Oid collowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); /* owner of collation */ char collprovider; /* see constants below */ bool collisdeterministic BKI_DEFAULT(t); int32 collencoding; /* encoding for this collation; -1 = "all" */ diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h index 6449937b352db..63f0f8bf41852 100644 --- a/src/include/catalog/pg_constraint.h +++ b/src/include/catalog/pg_constraint.h @@ -46,7 +46,8 @@ CATALOG(pg_constraint,2606,ConstraintRelationId) * conrelid + contypid + conname. */ NameData conname; /* name of this constraint */ - Oid connamespace; /* OID of namespace containing constraint */ + Oid connamespace BKI_LOOKUP(pg_namespace); /* OID of namespace + * containing constraint */ char contype; /* constraint type; see codes below */ bool condeferrable; /* deferrable constraint? */ bool condeferred; /* deferred by default? */ @@ -57,7 +58,8 @@ CATALOG(pg_constraint,2606,ConstraintRelationId) * specific relation (this excludes domain constraints and assertions). * Otherwise conrelid is 0 and conkey is NULL. */ - Oid conrelid; /* relation this constraint constrains */ + Oid conrelid BKI_LOOKUP_OPT(pg_class); /* relation this + * constraint constrains */ /* * contypid links to the pg_type row for a domain if this is a domain @@ -66,7 +68,8 @@ CATALOG(pg_constraint,2606,ConstraintRelationId) * For SQL-style global ASSERTIONs, both conrelid and contypid would be * zero. This is not presently supported, however. */ - Oid contypid; /* domain this constraint constrains */ + Oid contypid BKI_LOOKUP_OPT(pg_type); /* domain this constraint + * constrains */ /* * conindid links to the index supporting the constraint, if any; @@ -76,19 +79,21 @@ CATALOG(pg_constraint,2606,ConstraintRelationId) * columns). Notice that the index is on conrelid in the first case but * confrelid in the second. */ - Oid conindid; /* index supporting this constraint */ + Oid conindid BKI_LOOKUP_OPT(pg_class); /* index supporting this + * constraint */ /* * If this constraint is on a partition inherited from a partitioned * table, this is the OID of the corresponding constraint in the parent. */ - Oid conparentid; + Oid conparentid BKI_LOOKUP_OPT(pg_constraint); /* * These fields, plus confkey, are only meaningful for a foreign-key * constraint. Otherwise confrelid is 0 and the char fields are spaces. */ - Oid confrelid; /* relation referenced by foreign key */ + Oid confrelid BKI_LOOKUP_OPT(pg_class); /* relation referenced by + * foreign key */ char confupdtype; /* foreign key's ON UPDATE action */ char confdeltype; /* foreign key's ON DELETE action */ char confmatchtype; /* foreign key's match type */ @@ -119,25 +124,25 @@ CATALOG(pg_constraint,2606,ConstraintRelationId) * If a foreign key, the OIDs of the PK = FK equality operators for each * column of the constraint */ - Oid conpfeqop[1]; + Oid conpfeqop[1] BKI_LOOKUP(pg_operator); /* * If a foreign key, the OIDs of the PK = PK equality operators for each * column of the constraint (i.e., equality for the referenced columns) */ - Oid conppeqop[1]; + Oid conppeqop[1] BKI_LOOKUP(pg_operator); /* * If a foreign key, the OIDs of the FK = FK equality operators for each * column of the constraint (i.e., equality for the referencing columns) */ - Oid conffeqop[1]; + Oid conffeqop[1] BKI_LOOKUP(pg_operator); /* * If an exclusion constraint, the OIDs of the exclusion operators for * each column of the constraint */ - Oid conexclop[1]; + Oid conexclop[1] BKI_LOOKUP(pg_operator); /* * If a check constraint, nodeToString representation of expression @@ -166,6 +171,10 @@ DECLARE_UNIQUE_INDEX_PKEY(pg_constraint_oid_index, 2667, on pg_constraint using DECLARE_INDEX(pg_constraint_conparentid_index, 2579, on pg_constraint using btree(conparentid oid_ops)); #define ConstraintParentIndexId 2579 +/* conkey can contain zero (InvalidAttrNumber) if a whole-row Var is used */ +DECLARE_ARRAY_FOREIGN_KEY_OPT((conrelid, conkey), pg_attribute, (attrelid, attnum)); +DECLARE_ARRAY_FOREIGN_KEY((confrelid, confkey), pg_attribute, (attrelid, attnum)); + #ifdef EXPOSE_TO_CLIENT_CODE /* Valid values for contype */ diff --git a/src/include/catalog/pg_conversion.h b/src/include/catalog/pg_conversion.h index b02dfe0c3f776..96bb92f251b1e 100644 --- a/src/include/catalog/pg_conversion.h +++ b/src/include/catalog/pg_conversion.h @@ -35,10 +35,10 @@ CATALOG(pg_conversion,2607,ConversionRelationId) NameData conname; /* namespace that the conversion belongs to */ - Oid connamespace BKI_DEFAULT(PGNSP); + Oid connamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace); /* owner of the conversion */ - Oid conowner BKI_DEFAULT(PGUID); + Oid conowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); /* FOR encoding id */ int32 conforencoding BKI_LOOKUP(encoding); diff --git a/src/include/catalog/pg_database.h b/src/include/catalog/pg_database.h index b7a0b6a381b4c..f0240c58cf1a3 100644 --- a/src/include/catalog/pg_database.h +++ b/src/include/catalog/pg_database.h @@ -35,7 +35,7 @@ CATALOG(pg_database,1262,DatabaseRelationId) BKI_SHARED_RELATION BKI_ROWTYPE_OID NameData datname; /* owner of database */ - Oid datdba BKI_DEFAULT(PGUID); + Oid datdba BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); /* character encoding */ int32 encoding; diff --git a/src/include/catalog/pg_db_role_setting.h b/src/include/catalog/pg_db_role_setting.h index f18819d670c45..705f698ae79fb 100644 --- a/src/include/catalog/pg_db_role_setting.h +++ b/src/include/catalog/pg_db_role_setting.h @@ -33,8 +33,11 @@ */ CATALOG(pg_db_role_setting,2964,DbRoleSettingRelationId) BKI_SHARED_RELATION { - Oid setdatabase; /* database */ - Oid setrole; /* role */ + /* database, or 0 for a role-specific setting */ + Oid setdatabase BKI_LOOKUP_OPT(pg_database); + + /* role, or 0 for a database-specific setting */ + Oid setrole BKI_LOOKUP_OPT(pg_authid); #ifdef CATALOG_VARLEN /* variable-length fields start here */ text setconfig[1]; /* GUC settings to apply at login */ diff --git a/src/include/catalog/pg_default_acl.h b/src/include/catalog/pg_default_acl.h index bb7db32cd6c39..156fc0712da74 100644 --- a/src/include/catalog/pg_default_acl.h +++ b/src/include/catalog/pg_default_acl.h @@ -30,8 +30,10 @@ CATALOG(pg_default_acl,826,DefaultAclRelationId) { Oid oid; /* oid */ - Oid defaclrole; /* OID of role owning this ACL */ - Oid defaclnamespace; /* OID of namespace, or 0 for all */ + Oid defaclrole BKI_LOOKUP(pg_authid); /* OID of role owning this + * ACL */ + Oid defaclnamespace BKI_LOOKUP_OPT(pg_namespace); /* OID of namespace, or + * 0 for all */ char defaclobjtype; /* see DEFACLOBJ_xxx constants below */ #ifdef CATALOG_VARLEN /* variable-length fields start here */ diff --git a/src/include/catalog/pg_depend.h b/src/include/catalog/pg_depend.h index b0837901806f3..606a2a8e192ec 100644 --- a/src/include/catalog/pg_depend.h +++ b/src/include/catalog/pg_depend.h @@ -45,14 +45,16 @@ CATALOG(pg_depend,2608,DependRelationId) * * These fields are all zeroes for a DEPENDENCY_PIN entry. */ - Oid classid; /* OID of table containing object */ + Oid classid BKI_LOOKUP_OPT(pg_class); /* OID of table containing + * object */ Oid objid; /* OID of object itself */ int32 objsubid; /* column number, or 0 if not used */ /* * Identification of the independent (referenced) object. */ - Oid refclassid; /* OID of table containing object */ + Oid refclassid BKI_LOOKUP(pg_class); /* OID of table containing + * object */ Oid refobjid; /* OID of object itself */ int32 refobjsubid; /* column number, or 0 if not used */ diff --git a/src/include/catalog/pg_description.h b/src/include/catalog/pg_description.h index ad9de5e0a0623..adc06a854d9a5 100644 --- a/src/include/catalog/pg_description.h +++ b/src/include/catalog/pg_description.h @@ -68,4 +68,7 @@ DECLARE_TOAST(pg_description, 2834, 2835); DECLARE_UNIQUE_INDEX_PKEY(pg_description_o_c_o_index, 2675, on pg_description using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops)); #define DescriptionObjIndexId 2675 +/* We do not use BKI_LOOKUP here because it causes problems for genbki.pl */ +DECLARE_FOREIGN_KEY((classoid), pg_class, (oid)); + #endif /* PG_DESCRIPTION_H */ diff --git a/src/include/catalog/pg_enum.h b/src/include/catalog/pg_enum.h index 5eaf70772c714..78a183b27d4bc 100644 --- a/src/include/catalog/pg_enum.h +++ b/src/include/catalog/pg_enum.h @@ -31,7 +31,7 @@ CATALOG(pg_enum,3501,EnumRelationId) { Oid oid; /* oid */ - Oid enumtypid; /* OID of owning enum type */ + Oid enumtypid BKI_LOOKUP(pg_type); /* OID of owning enum type */ float4 enumsortorder; /* sort position of this enum value */ NameData enumlabel; /* text representation of enum value */ } FormData_pg_enum; diff --git a/src/include/catalog/pg_event_trigger.h b/src/include/catalog/pg_event_trigger.h index 6f0266ed0fae2..eeaa6be518447 100644 --- a/src/include/catalog/pg_event_trigger.h +++ b/src/include/catalog/pg_event_trigger.h @@ -31,8 +31,9 @@ CATALOG(pg_event_trigger,3466,EventTriggerRelationId) Oid oid; /* oid */ NameData evtname; /* trigger's name */ NameData evtevent; /* trigger's event */ - Oid evtowner; /* trigger's owner */ - Oid evtfoid; /* OID of function to be called */ + Oid evtowner BKI_LOOKUP(pg_authid); /* trigger's owner */ + Oid evtfoid BKI_LOOKUP(pg_proc); /* OID of function to be + * called */ char evtenabled; /* trigger's firing configuration WRT * session_replication_role */ diff --git a/src/include/catalog/pg_extension.h b/src/include/catalog/pg_extension.h index af119bfea7a8c..2d6ad9fa88881 100644 --- a/src/include/catalog/pg_extension.h +++ b/src/include/catalog/pg_extension.h @@ -30,14 +30,16 @@ CATALOG(pg_extension,3079,ExtensionRelationId) { Oid oid; /* oid */ NameData extname; /* extension name */ - Oid extowner; /* extension owner */ - Oid extnamespace; /* namespace of contained objects */ + Oid extowner BKI_LOOKUP(pg_authid); /* extension owner */ + Oid extnamespace BKI_LOOKUP(pg_namespace); /* namespace of + * contained objects */ bool extrelocatable; /* if true, allow ALTER EXTENSION SET SCHEMA */ #ifdef CATALOG_VARLEN /* variable-length fields start here */ /* extversion may never be null, but the others can be. */ text extversion BKI_FORCE_NOT_NULL; /* extension version name */ - Oid extconfig[1]; /* dumpable configuration tables */ + Oid extconfig[1] BKI_LOOKUP(pg_class); /* dumpable configuration + * tables */ text extcondition[1]; /* WHERE clauses for config tables */ #endif } FormData_pg_extension; diff --git a/src/include/catalog/pg_foreign_data_wrapper.h b/src/include/catalog/pg_foreign_data_wrapper.h index 0f523a26b9c4f..f6240d9eb326b 100644 --- a/src/include/catalog/pg_foreign_data_wrapper.h +++ b/src/include/catalog/pg_foreign_data_wrapper.h @@ -30,9 +30,12 @@ CATALOG(pg_foreign_data_wrapper,2328,ForeignDataWrapperRelationId) { Oid oid; /* oid */ NameData fdwname; /* foreign-data wrapper name */ - Oid fdwowner; /* FDW owner */ - Oid fdwhandler; /* handler function, or 0 if none */ - Oid fdwvalidator; /* option validation function, or 0 if none */ + Oid fdwowner BKI_LOOKUP(pg_authid); /* FDW owner */ + Oid fdwhandler BKI_LOOKUP_OPT(pg_proc); /* handler function, or 0 + * if none */ + Oid fdwvalidator BKI_LOOKUP_OPT(pg_proc); /* option validation + * function, or 0 if + * none */ #ifdef CATALOG_VARLEN /* variable-length fields start here */ aclitem fdwacl[1]; /* access permissions */ diff --git a/src/include/catalog/pg_foreign_server.h b/src/include/catalog/pg_foreign_server.h index 385b896e970d5..a173699aef6bc 100644 --- a/src/include/catalog/pg_foreign_server.h +++ b/src/include/catalog/pg_foreign_server.h @@ -29,8 +29,8 @@ CATALOG(pg_foreign_server,1417,ForeignServerRelationId) { Oid oid; /* oid */ NameData srvname; /* foreign server name */ - Oid srvowner; /* server owner */ - Oid srvfdw; /* server FDW */ + Oid srvowner BKI_LOOKUP(pg_authid); /* server owner */ + Oid srvfdw BKI_LOOKUP(pg_foreign_data_wrapper); /* server FDW */ #ifdef CATALOG_VARLEN /* variable-length fields start here */ text srvtype; diff --git a/src/include/catalog/pg_foreign_table.h b/src/include/catalog/pg_foreign_table.h index 24f7f2998eb80..3b6221b0e64b5 100644 --- a/src/include/catalog/pg_foreign_table.h +++ b/src/include/catalog/pg_foreign_table.h @@ -27,8 +27,8 @@ */ CATALOG(pg_foreign_table,3118,ForeignTableRelationId) { - Oid ftrelid; /* OID of foreign table */ - Oid ftserver; /* OID of foreign server */ + Oid ftrelid BKI_LOOKUP(pg_class); /* OID of foreign table */ + Oid ftserver BKI_LOOKUP(pg_foreign_server); /* OID of foreign server */ #ifdef CATALOG_VARLEN /* variable-length fields start here */ text ftoptions[1]; /* FDW-specific options */ diff --git a/src/include/catalog/pg_index.h b/src/include/catalog/pg_index.h index 1a7aef18ce85f..00d0b439f5c94 100644 --- a/src/include/catalog/pg_index.h +++ b/src/include/catalog/pg_index.h @@ -28,8 +28,9 @@ */ CATALOG(pg_index,2610,IndexRelationId) BKI_SCHEMA_MACRO { - Oid indexrelid; /* OID of the index */ - Oid indrelid; /* OID of the relation it indexes */ + Oid indexrelid BKI_LOOKUP(pg_class); /* OID of the index */ + Oid indrelid BKI_LOOKUP(pg_class); /* OID of the relation it + * indexes */ int16 indnatts; /* total number of columns in index */ int16 indnkeyatts; /* number of key columns in index */ bool indisunique; /* is this a unique index? */ @@ -48,8 +49,8 @@ CATALOG(pg_index,2610,IndexRelationId) BKI_SCHEMA_MACRO * or 0 */ #ifdef CATALOG_VARLEN - oidvector indcollation BKI_FORCE_NOT_NULL; /* collation identifiers */ - oidvector indclass BKI_FORCE_NOT_NULL; /* opclass identifiers */ + oidvector indcollation BKI_LOOKUP_OPT(pg_collation) BKI_FORCE_NOT_NULL; /* collation identifiers */ + oidvector indclass BKI_LOOKUP(pg_opclass) BKI_FORCE_NOT_NULL; /* opclass identifiers */ int2vector indoption BKI_FORCE_NOT_NULL; /* per-column flags * (AM-specific meanings) */ pg_node_tree indexprs; /* expression trees for index attributes that @@ -72,6 +73,9 @@ DECLARE_INDEX(pg_index_indrelid_index, 2678, on pg_index using btree(indrelid oi DECLARE_UNIQUE_INDEX_PKEY(pg_index_indexrelid_index, 2679, on pg_index using btree(indexrelid oid_ops)); #define IndexRelidIndexId 2679 +/* indkey can contain zero (InvalidAttrNumber) to represent expressions */ +DECLARE_ARRAY_FOREIGN_KEY_OPT((indrelid, indkey), pg_attribute, (attrelid, attnum)); + #ifdef EXPOSE_TO_CLIENT_CODE /* diff --git a/src/include/catalog/pg_inherits.h b/src/include/catalog/pg_inherits.h index b8147796d855f..2b71cad9a2a48 100644 --- a/src/include/catalog/pg_inherits.h +++ b/src/include/catalog/pg_inherits.h @@ -31,8 +31,8 @@ */ CATALOG(pg_inherits,2611,InheritsRelationId) { - Oid inhrelid; - Oid inhparent; + Oid inhrelid BKI_LOOKUP(pg_class); + Oid inhparent BKI_LOOKUP(pg_class); int32 inhseqno; } FormData_pg_inherits; diff --git a/src/include/catalog/pg_init_privs.h b/src/include/catalog/pg_init_privs.h index 983b1857c0c7d..4aafeb246d7e1 100644 --- a/src/include/catalog/pg_init_privs.h +++ b/src/include/catalog/pg_init_privs.h @@ -46,7 +46,8 @@ CATALOG(pg_init_privs,3394,InitPrivsRelationId) { Oid objoid; /* OID of object itself */ - Oid classoid; /* OID of table containing object */ + Oid classoid BKI_LOOKUP(pg_class); /* OID of table containing + * object */ int32 objsubid; /* column number, or 0 if not used */ char privtype; /* from initdb or extension? */ diff --git a/src/include/catalog/pg_language.h b/src/include/catalog/pg_language.h index b1dcd0a4f579d..e9df9dac09f30 100644 --- a/src/include/catalog/pg_language.h +++ b/src/include/catalog/pg_language.h @@ -34,7 +34,7 @@ CATALOG(pg_language,2612,LanguageRelationId) NameData lanname; /* Language's owner */ - Oid lanowner BKI_DEFAULT(PGUID); + Oid lanowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); /* Is a procedural language */ bool lanispl BKI_DEFAULT(f); @@ -43,13 +43,13 @@ CATALOG(pg_language,2612,LanguageRelationId) bool lanpltrusted BKI_DEFAULT(f); /* Call handler, if it's a PL */ - Oid lanplcallfoid BKI_DEFAULT(0) BKI_LOOKUP(pg_proc); + Oid lanplcallfoid BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_proc); /* Optional anonymous-block handler function */ - Oid laninline BKI_DEFAULT(0) BKI_LOOKUP(pg_proc); + Oid laninline BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_proc); /* Optional validation function */ - Oid lanvalidator BKI_DEFAULT(0) BKI_LOOKUP(pg_proc); + Oid lanvalidator BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_proc); #ifdef CATALOG_VARLEN /* variable-length fields start here */ /* Access privileges */ diff --git a/src/include/catalog/pg_largeobject.h b/src/include/catalog/pg_largeobject.h index f453319322aa7..32225f4de7d37 100644 --- a/src/include/catalog/pg_largeobject.h +++ b/src/include/catalog/pg_largeobject.h @@ -28,7 +28,8 @@ */ CATALOG(pg_largeobject,2613,LargeObjectRelationId) { - Oid loid; /* Identifier of large object */ + Oid loid BKI_LOOKUP(pg_largeobject_metadata); /* Identifier of large + * object */ int32 pageno; /* Page number (starting from 0) */ /* data has variable length, but we allow direct access; see inv_api.c */ diff --git a/src/include/catalog/pg_largeobject_metadata.h b/src/include/catalog/pg_largeobject_metadata.h index 220988b0ad600..9b689bab849bd 100644 --- a/src/include/catalog/pg_largeobject_metadata.h +++ b/src/include/catalog/pg_largeobject_metadata.h @@ -31,7 +31,8 @@ CATALOG(pg_largeobject_metadata,2995,LargeObjectMetadataRelationId) { Oid oid; /* oid */ - Oid lomowner; /* OID of the largeobject owner */ + Oid lomowner BKI_LOOKUP(pg_authid); /* OID of the largeobject + * owner */ #ifdef CATALOG_VARLEN /* variable-length fields start here */ aclitem lomacl[1]; /* access permissions */ diff --git a/src/include/catalog/pg_namespace.dat b/src/include/catalog/pg_namespace.dat index 76257e98fcc91..2ed136b787ede 100644 --- a/src/include/catalog/pg_namespace.dat +++ b/src/include/catalog/pg_namespace.dat @@ -14,12 +14,12 @@ { oid => '11', oid_symbol => 'PG_CATALOG_NAMESPACE', descr => 'system catalog schema', - nspname => 'pg_catalog', nspowner => 'PGUID', nspacl => '_null_' }, + nspname => 'pg_catalog', nspacl => '_null_' }, { oid => '99', oid_symbol => 'PG_TOAST_NAMESPACE', descr => 'reserved schema for TOAST tables', - nspname => 'pg_toast', nspowner => 'PGUID', nspacl => '_null_' }, + nspname => 'pg_toast', nspacl => '_null_' }, { oid => '2200', oid_symbol => 'PG_PUBLIC_NAMESPACE', descr => 'standard public schema', - nspname => 'public', nspowner => 'PGUID', nspacl => '_null_' }, + nspname => 'public', nspacl => '_null_' }, ] diff --git a/src/include/catalog/pg_namespace.h b/src/include/catalog/pg_namespace.h index 0a68958b1c4c9..d920c6cfc64a3 100644 --- a/src/include/catalog/pg_namespace.h +++ b/src/include/catalog/pg_namespace.h @@ -37,7 +37,7 @@ CATALOG(pg_namespace,2615,NamespaceRelationId) Oid oid; /* oid */ NameData nspname; - Oid nspowner; + Oid nspowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); #ifdef CATALOG_VARLEN /* variable-length fields start here */ aclitem nspacl[1]; diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h index d132df1f2f7ee..9f321f2a85ce5 100644 --- a/src/include/catalog/pg_opclass.h +++ b/src/include/catalog/pg_opclass.h @@ -57,10 +57,10 @@ CATALOG(pg_opclass,2616,OperatorClassRelationId) NameData opcname; /* namespace of this opclass */ - Oid opcnamespace BKI_DEFAULT(PGNSP); + Oid opcnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace); /* opclass owner */ - Oid opcowner BKI_DEFAULT(PGUID); + Oid opcowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); /* containing operator family */ Oid opcfamily BKI_LOOKUP(pg_opfamily); @@ -71,8 +71,8 @@ CATALOG(pg_opclass,2616,OperatorClassRelationId) /* T if opclass is default for opcintype */ bool opcdefault BKI_DEFAULT(t); - /* type of data in index, or InvalidOid */ - Oid opckeytype BKI_DEFAULT(0) BKI_LOOKUP(pg_type); + /* type of data in index, or InvalidOid if same as input column type */ + Oid opckeytype BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_type); } FormData_pg_opclass; /* ---------------- diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h index 3ca57e7c1b4b1..7f06abaeec1ef 100644 --- a/src/include/catalog/pg_operator.h +++ b/src/include/catalog/pg_operator.h @@ -36,10 +36,10 @@ CATALOG(pg_operator,2617,OperatorRelationId) NameData oprname; /* OID of namespace containing this oper */ - Oid oprnamespace BKI_DEFAULT(PGNSP); + Oid oprnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace); /* operator owner */ - Oid oprowner BKI_DEFAULT(PGUID); + Oid oprowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); /* 'l' for prefix or 'b' for infix */ char oprkind BKI_DEFAULT(b); @@ -51,28 +51,28 @@ CATALOG(pg_operator,2617,OperatorRelationId) bool oprcanhash BKI_DEFAULT(f); /* left arg type, or 0 if prefix operator */ - Oid oprleft BKI_LOOKUP(pg_type); + Oid oprleft BKI_LOOKUP_OPT(pg_type); /* right arg type */ Oid oprright BKI_LOOKUP(pg_type); - /* result datatype */ - Oid oprresult BKI_LOOKUP(pg_type); + /* result datatype; can be 0 in a "shell" operator */ + Oid oprresult BKI_LOOKUP_OPT(pg_type); /* OID of commutator oper, or 0 if none */ - Oid oprcom BKI_DEFAULT(0) BKI_LOOKUP(pg_operator); + Oid oprcom BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_operator); /* OID of negator oper, or 0 if none */ - Oid oprnegate BKI_DEFAULT(0) BKI_LOOKUP(pg_operator); + Oid oprnegate BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_operator); - /* OID of underlying function */ - regproc oprcode BKI_LOOKUP(pg_proc); + /* OID of underlying function; can be 0 in a "shell" operator */ + regproc oprcode BKI_LOOKUP_OPT(pg_proc); /* OID of restriction estimator, or 0 */ - regproc oprrest BKI_DEFAULT(-) BKI_LOOKUP(pg_proc); + regproc oprrest BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc); /* OID of join estimator, or 0 */ - regproc oprjoin BKI_DEFAULT(-) BKI_LOOKUP(pg_proc); + regproc oprjoin BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc); } FormData_pg_operator; /* ---------------- diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h index 18385a6fd6c09..1a723b76f6392 100644 --- a/src/include/catalog/pg_opfamily.h +++ b/src/include/catalog/pg_opfamily.h @@ -37,10 +37,10 @@ CATALOG(pg_opfamily,2753,OperatorFamilyRelationId) NameData opfname; /* namespace of this opfamily */ - Oid opfnamespace BKI_DEFAULT(PGNSP); + Oid opfnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace); /* opfamily owner */ - Oid opfowner BKI_DEFAULT(PGUID); + Oid opfowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); } FormData_pg_opfamily; /* ---------------- diff --git a/src/include/catalog/pg_partitioned_table.h b/src/include/catalog/pg_partitioned_table.h index 038730b00536c..48cbaf30ff8ef 100644 --- a/src/include/catalog/pg_partitioned_table.h +++ b/src/include/catalog/pg_partitioned_table.h @@ -29,11 +29,11 @@ */ CATALOG(pg_partitioned_table,3350,PartitionedRelationId) { - Oid partrelid; /* partitioned table oid */ + Oid partrelid BKI_LOOKUP(pg_class); /* partitioned table oid */ char partstrat; /* partitioning strategy */ int16 partnatts; /* number of partition key columns */ - Oid partdefid; /* default partition oid; InvalidOid if there - * isn't one */ + Oid partdefid BKI_LOOKUP_OPT(pg_class); /* default partition oid; + * 0 if there isn't one */ /* * variable-length fields start here, but we allow direct access to @@ -48,10 +48,10 @@ CATALOG(pg_partitioned_table,3350,PartitionedRelationId) * an expression */ #ifdef CATALOG_VARLEN - oidvector partclass BKI_FORCE_NOT_NULL; /* operator class to compare - * keys */ - oidvector partcollation BKI_FORCE_NOT_NULL; /* user-specified - * collation for keys */ + oidvector partclass BKI_LOOKUP(pg_opclass) BKI_FORCE_NOT_NULL; /* operator class to + * compare keys */ + oidvector partcollation BKI_LOOKUP_OPT(pg_collation) BKI_FORCE_NOT_NULL; /* user-specified + * collation for keys */ pg_node_tree partexprs; /* list of expressions in the partition key; * one item for each zero entry in partattrs[] */ #endif @@ -69,4 +69,7 @@ DECLARE_TOAST(pg_partitioned_table, 4165, 4166); DECLARE_UNIQUE_INDEX_PKEY(pg_partitioned_table_partrelid_index, 3351, on pg_partitioned_table using btree(partrelid oid_ops)); #define PartitionedRelidIndexId 3351 +/* partattrs can contain zero (InvalidAttrNumber) to represent expressions */ +DECLARE_ARRAY_FOREIGN_KEY_OPT((partrelid, partattrs), pg_attribute, (attrelid, attnum)); + #endif /* PG_PARTITIONED_TABLE_H */ diff --git a/src/include/catalog/pg_policy.h b/src/include/catalog/pg_policy.h index 44197613e06be..645b8fe498c54 100644 --- a/src/include/catalog/pg_policy.h +++ b/src/include/catalog/pg_policy.h @@ -30,13 +30,14 @@ CATALOG(pg_policy,3256,PolicyRelationId) { Oid oid; /* oid */ NameData polname; /* Policy name. */ - Oid polrelid; /* Oid of the relation with policy. */ + Oid polrelid BKI_LOOKUP(pg_class); /* Oid of the relation with + * policy. */ char polcmd; /* One of ACL_*_CHR, or '*' for all */ bool polpermissive; /* restrictive or permissive policy */ #ifdef CATALOG_VARLEN - Oid polroles[1] BKI_FORCE_NOT_NULL; /* Roles associated with - * policy */ + /* Roles to which the policy is applied; zero means PUBLIC */ + Oid polroles[1] BKI_LOOKUP_OPT(pg_authid) BKI_FORCE_NOT_NULL; pg_node_tree polqual; /* Policy quals. */ pg_node_tree polwithcheck; /* WITH CHECK quals. */ #endif diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index f8174061ef359..4e0c9be58c314 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -2405,7 +2405,7 @@ { oid => '1215', descr => 'get description for object id and catalog name', proname => 'obj_description', prolang => 'sql', procost => '100', provolatile => 's', prorettype => 'text', proargtypes => 'oid name', - prosrc => 'select description from pg_catalog.pg_description where objoid = $1 and classoid = (select oid from pg_catalog.pg_class where relname = $2 and relnamespace = PGNSP) and objsubid = 0' }, + prosrc => 'select description from pg_catalog.pg_description where objoid = $1 and classoid = (select oid from pg_catalog.pg_class where relname = $2 and relnamespace = \'pg_catalog\'::pg_catalog.regnamespace) and objsubid = 0' }, { oid => '1216', descr => 'get description for table column', proname => 'col_description', prolang => 'sql', procost => '100', provolatile => 's', prorettype => 'text', proargtypes => 'oid int4', @@ -2414,7 +2414,7 @@ descr => 'get description for object id and shared catalog name', proname => 'shobj_description', prolang => 'sql', procost => '100', provolatile => 's', prorettype => 'text', proargtypes => 'oid name', - prosrc => 'select description from pg_catalog.pg_shdescription where objoid = $1 and classoid = (select oid from pg_catalog.pg_class where relname = $2 and relnamespace = PGNSP)' }, + prosrc => 'select description from pg_catalog.pg_shdescription where objoid = $1 and classoid = (select oid from pg_catalog.pg_class where relname = $2 and relnamespace = \'pg_catalog\'::pg_catalog.regnamespace)' }, { oid => '1217', descr => 'truncate timestamp with time zone to specified units', @@ -3698,6 +3698,14 @@ proargnames => '{word,catcode,barelabel,catdesc,baredesc}', prosrc => 'pg_get_keywords' }, +{ oid => '8103', descr => 'list of catalog foreign key relationships', + proname => 'pg_get_catalog_foreign_keys', procost => '10', prorows => '250', + proretset => 't', provolatile => 's', prorettype => 'record', + proargtypes => '', proallargtypes => '{regclass,_text,regclass,_text,bool,bool}', + proargmodes => '{o,o,o,o,o,o}', + proargnames => '{fktable,fkcols,pktable,pkcols,is_array,is_opt}', + prosrc => 'pg_get_catalog_foreign_keys' }, + { oid => '2289', descr => 'convert generic options array to name/value table', proname => 'pg_options_to_table', prorows => '3', proretset => 't', provolatile => 's', prorettype => 'record', proargtypes => '_text', diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 03c8bef42274d..2f54aa171edd2 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -35,10 +35,10 @@ CATALOG(pg_proc,1255,ProcedureRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(81,Proce NameData proname; /* OID of namespace containing this proc */ - Oid pronamespace BKI_DEFAULT(PGNSP); + Oid pronamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace); /* procedure owner */ - Oid proowner BKI_DEFAULT(PGUID); + Oid proowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); /* OID of pg_language entry */ Oid prolang BKI_DEFAULT(internal) BKI_LOOKUP(pg_language); @@ -49,11 +49,11 @@ CATALOG(pg_proc,1255,ProcedureRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(81,Proce /* estimated # of rows out (if proretset) */ float4 prorows BKI_DEFAULT(0); - /* element type of variadic array, or 0 */ - Oid provariadic BKI_DEFAULT(0) BKI_LOOKUP(pg_type); + /* element type of variadic array, or 0 if not variadic */ + Oid provariadic BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_type); /* planner support function for this function, or 0 if none */ - regproc prosupport BKI_DEFAULT(0) BKI_LOOKUP(pg_proc); + regproc prosupport BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_proc); /* see PROKIND_ categories below */ char prokind BKI_DEFAULT(f); @@ -109,7 +109,7 @@ CATALOG(pg_proc,1255,ProcedureRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(81,Proce pg_node_tree proargdefaults BKI_DEFAULT(_null_); /* types for which to apply transforms */ - Oid protrftypes[1] BKI_DEFAULT(_null_); + Oid protrftypes[1] BKI_DEFAULT(_null_) BKI_LOOKUP(pg_type); /* procedure source text */ text prosrc BKI_FORCE_NOT_NULL; diff --git a/src/include/catalog/pg_publication.h b/src/include/catalog/pg_publication.h index 4127611f5a6b5..1b31fee9e3cfa 100644 --- a/src/include/catalog/pg_publication.h +++ b/src/include/catalog/pg_publication.h @@ -32,7 +32,7 @@ CATALOG(pg_publication,6104,PublicationRelationId) NameData pubname; /* name of the publication */ - Oid pubowner; /* publication owner */ + Oid pubowner BKI_LOOKUP(pg_authid); /* publication owner */ /* * indicates that this is special publication which should encompass all diff --git a/src/include/catalog/pg_publication_rel.h b/src/include/catalog/pg_publication_rel.h index c79b7fb4874a5..aecf53b3b3976 100644 --- a/src/include/catalog/pg_publication_rel.h +++ b/src/include/catalog/pg_publication_rel.h @@ -29,8 +29,8 @@ CATALOG(pg_publication_rel,6106,PublicationRelRelationId) { Oid oid; /* oid */ - Oid prpubid; /* Oid of the publication */ - Oid prrelid; /* Oid of the relation */ + Oid prpubid BKI_LOOKUP(pg_publication); /* Oid of the publication */ + Oid prrelid BKI_LOOKUP(pg_class); /* Oid of the relation */ } FormData_pg_publication_rel; /* ---------------- diff --git a/src/include/catalog/pg_range.h b/src/include/catalog/pg_range.h index 2ec6a4b126bb2..5dfa4eef8baf9 100644 --- a/src/include/catalog/pg_range.h +++ b/src/include/catalog/pg_range.h @@ -38,16 +38,16 @@ CATALOG(pg_range,3541,RangeRelationId) Oid rngmultitypid BKI_LOOKUP(pg_type); /* collation for this range type, or 0 */ - Oid rngcollation BKI_DEFAULT(0); + Oid rngcollation BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_collation); /* subtype's btree opclass */ Oid rngsubopc BKI_LOOKUP(pg_opclass); /* canonicalize range, or 0 */ - regproc rngcanonical BKI_LOOKUP(pg_proc); + regproc rngcanonical BKI_LOOKUP_OPT(pg_proc); /* subtype difference as a float8, or 0 */ - regproc rngsubdiff BKI_LOOKUP(pg_proc); + regproc rngsubdiff BKI_LOOKUP_OPT(pg_proc); } FormData_pg_range; /* ---------------- diff --git a/src/include/catalog/pg_rewrite.h b/src/include/catalog/pg_rewrite.h index 36f92b1cf1358..89c72545d0bfb 100644 --- a/src/include/catalog/pg_rewrite.h +++ b/src/include/catalog/pg_rewrite.h @@ -33,7 +33,7 @@ CATALOG(pg_rewrite,2618,RewriteRelationId) { Oid oid; /* oid */ NameData rulename; - Oid ev_class; + Oid ev_class BKI_LOOKUP(pg_class); char ev_type; char ev_enabled; bool is_instead; diff --git a/src/include/catalog/pg_seclabel.h b/src/include/catalog/pg_seclabel.h index b14fd7febe814..0a12225eb70fe 100644 --- a/src/include/catalog/pg_seclabel.h +++ b/src/include/catalog/pg_seclabel.h @@ -28,7 +28,8 @@ CATALOG(pg_seclabel,3596,SecLabelRelationId) { Oid objoid; /* OID of the object itself */ - Oid classoid; /* OID of table containing the object */ + Oid classoid BKI_LOOKUP(pg_class); /* OID of table containing the + * object */ int32 objsubid; /* column number, or 0 if not used */ #ifdef CATALOG_VARLEN /* variable-length fields start here */ diff --git a/src/include/catalog/pg_sequence.h b/src/include/catalog/pg_sequence.h index addf21abce95b..8d0a00baf69e8 100644 --- a/src/include/catalog/pg_sequence.h +++ b/src/include/catalog/pg_sequence.h @@ -22,8 +22,8 @@ CATALOG(pg_sequence,2224,SequenceRelationId) { - Oid seqrelid; - Oid seqtypid; + Oid seqrelid BKI_LOOKUP(pg_class); + Oid seqtypid BKI_LOOKUP(pg_type); int64 seqstart; int64 seqincrement; int64 seqmax; diff --git a/src/include/catalog/pg_shdepend.h b/src/include/catalog/pg_shdepend.h index f5863954e9fbf..4faa95794db94 100644 --- a/src/include/catalog/pg_shdepend.h +++ b/src/include/catalog/pg_shdepend.h @@ -42,8 +42,10 @@ CATALOG(pg_shdepend,1214,SharedDependRelationId) BKI_SHARED_RELATION * These fields are all zeroes for a DEPENDENCY_PIN entry. Also, dbid can * be zero to denote a shared object. */ - Oid dbid; /* OID of database containing object */ - Oid classid; /* OID of table containing object */ + Oid dbid BKI_LOOKUP_OPT(pg_database); /* OID of database + * containing object */ + Oid classid BKI_LOOKUP_OPT(pg_class); /* OID of table containing + * object */ Oid objid; /* OID of object itself */ int32 objsubid; /* column number, or 0 if not used */ @@ -52,7 +54,8 @@ CATALOG(pg_shdepend,1214,SharedDependRelationId) BKI_SHARED_RELATION * a shared object, so we need no database ID field. We don't bother with * a sub-object ID either. */ - Oid refclassid; /* OID of table containing object */ + Oid refclassid BKI_LOOKUP(pg_class); /* OID of table containing + * object */ Oid refobjid; /* OID of object itself */ /* diff --git a/src/include/catalog/pg_shdescription.h b/src/include/catalog/pg_shdescription.h index a37db4fa0b44e..543e216710b5b 100644 --- a/src/include/catalog/pg_shdescription.h +++ b/src/include/catalog/pg_shdescription.h @@ -62,4 +62,7 @@ DECLARE_TOAST(pg_shdescription, 2846, 2847); DECLARE_UNIQUE_INDEX_PKEY(pg_shdescription_o_c_index, 2397, on pg_shdescription using btree(objoid oid_ops, classoid oid_ops)); #define SharedDescriptionObjIndexId 2397 +/* We do not use BKI_LOOKUP here because it causes problems for genbki.pl */ +DECLARE_FOREIGN_KEY((classoid), pg_class, (oid)); + #endif /* PG_SHDESCRIPTION_H */ diff --git a/src/include/catalog/pg_shseclabel.h b/src/include/catalog/pg_shseclabel.h index 406f5328a7031..5d6864cf8cf0e 100644 --- a/src/include/catalog/pg_shseclabel.h +++ b/src/include/catalog/pg_shseclabel.h @@ -28,7 +28,8 @@ CATALOG(pg_shseclabel,3592,SharedSecLabelRelationId) BKI_SHARED_RELATION BKI_ROWTYPE_OID(4066,SharedSecLabelRelation_Rowtype_Id) BKI_SCHEMA_MACRO { Oid objoid; /* OID of the shared object itself */ - Oid classoid; /* OID of table containing the shared object */ + Oid classoid BKI_LOOKUP(pg_class); /* OID of table containing the + * shared object */ #ifdef CATALOG_VARLEN /* variable-length fields start here */ text provider BKI_FORCE_NOT_NULL; /* name of label provider */ diff --git a/src/include/catalog/pg_statistic.h b/src/include/catalog/pg_statistic.h index 4a66bda879ca3..d1827858e2d76 100644 --- a/src/include/catalog/pg_statistic.h +++ b/src/include/catalog/pg_statistic.h @@ -29,7 +29,8 @@ CATALOG(pg_statistic,2619,StatisticRelationId) { /* These fields form the unique key for the entry: */ - Oid starelid; /* relation containing attribute */ + Oid starelid BKI_LOOKUP(pg_class); /* relation containing + * attribute */ int16 staattnum; /* attribute (column) stats are for */ bool stainherit; /* true if inheritance children are included */ @@ -90,17 +91,17 @@ CATALOG(pg_statistic,2619,StatisticRelationId) int16 stakind4; int16 stakind5; - Oid staop1; - Oid staop2; - Oid staop3; - Oid staop4; - Oid staop5; + Oid staop1 BKI_LOOKUP_OPT(pg_operator); + Oid staop2 BKI_LOOKUP_OPT(pg_operator); + Oid staop3 BKI_LOOKUP_OPT(pg_operator); + Oid staop4 BKI_LOOKUP_OPT(pg_operator); + Oid staop5 BKI_LOOKUP_OPT(pg_operator); - Oid stacoll1; - Oid stacoll2; - Oid stacoll3; - Oid stacoll4; - Oid stacoll5; + Oid stacoll1 BKI_LOOKUP_OPT(pg_collation); + Oid stacoll2 BKI_LOOKUP_OPT(pg_collation); + Oid stacoll3 BKI_LOOKUP_OPT(pg_collation); + Oid stacoll4 BKI_LOOKUP_OPT(pg_collation); + Oid stacoll5 BKI_LOOKUP_OPT(pg_collation); #ifdef CATALOG_VARLEN /* variable-length fields start here */ float4 stanumbers1[1]; @@ -138,6 +139,8 @@ DECLARE_TOAST(pg_statistic, 2840, 2841); DECLARE_UNIQUE_INDEX_PKEY(pg_statistic_relid_att_inh_index, 2696, on pg_statistic using btree(starelid oid_ops, staattnum int2_ops, stainherit bool_ops)); #define StatisticRelidAttnumInhIndexId 2696 +DECLARE_FOREIGN_KEY((starelid, staattnum), pg_attribute, (attrelid, attnum)); + #ifdef EXPOSE_TO_CLIENT_CODE /* diff --git a/src/include/catalog/pg_statistic_ext.h b/src/include/catalog/pg_statistic_ext.h index 10f52f912cb7f..29649f58143b8 100644 --- a/src/include/catalog/pg_statistic_ext.h +++ b/src/include/catalog/pg_statistic_ext.h @@ -34,13 +34,15 @@ CATALOG(pg_statistic_ext,3381,StatisticExtRelationId) { Oid oid; /* oid */ - Oid stxrelid; /* relation containing attributes */ + Oid stxrelid BKI_LOOKUP(pg_class); /* relation containing + * attributes */ /* These two fields form the unique key for the entry: */ NameData stxname; /* statistics object name */ - Oid stxnamespace; /* OID of statistics object's namespace */ + Oid stxnamespace BKI_LOOKUP(pg_namespace); /* OID of statistics + * object's namespace */ - Oid stxowner; /* statistics object's owner */ + Oid stxowner BKI_LOOKUP(pg_authid); /* statistics object's owner */ int32 stxstattarget BKI_DEFAULT(-1); /* statistics target */ /* @@ -72,6 +74,8 @@ DECLARE_UNIQUE_INDEX(pg_statistic_ext_name_index, 3997, on pg_statistic_ext usin DECLARE_INDEX(pg_statistic_ext_relid_index, 3379, on pg_statistic_ext using btree(stxrelid oid_ops)); #define StatisticExtRelidIndexId 3379 +DECLARE_ARRAY_FOREIGN_KEY((stxrelid, stxkeys), pg_attribute, (attrelid, attnum)); + #ifdef EXPOSE_TO_CLIENT_CODE #define STATS_EXT_NDISTINCT 'd' diff --git a/src/include/catalog/pg_statistic_ext_data.h b/src/include/catalog/pg_statistic_ext_data.h index 6f7a36c14181a..2f2577c218877 100644 --- a/src/include/catalog/pg_statistic_ext_data.h +++ b/src/include/catalog/pg_statistic_ext_data.h @@ -30,7 +30,8 @@ */ CATALOG(pg_statistic_ext_data,3429,StatisticExtDataRelationId) { - Oid stxoid; /* statistics object this data is for */ + Oid stxoid BKI_LOOKUP(pg_statistic_ext); /* statistics object + * this data is for */ #ifdef CATALOG_VARLEN /* variable-length fields start here */ diff --git a/src/include/catalog/pg_subscription.h b/src/include/catalog/pg_subscription.h index 4e44c29149631..a5d6efdf205b9 100644 --- a/src/include/catalog/pg_subscription.h +++ b/src/include/catalog/pg_subscription.h @@ -40,10 +40,11 @@ CATALOG(pg_subscription,6100,SubscriptionRelationId) BKI_SHARED_RELATION BKI_ROW { Oid oid; /* oid */ - Oid subdbid; /* Database the subscription is in. */ + Oid subdbid BKI_LOOKUP(pg_database); /* Database the + * subscription is in. */ NameData subname; /* Name of the subscription */ - Oid subowner; /* Owner of the subscription */ + Oid subowner BKI_LOOKUP(pg_authid); /* Owner of the subscription */ bool subenabled; /* True if the subscription is enabled (the * worker should be running) */ diff --git a/src/include/catalog/pg_subscription_rel.h b/src/include/catalog/pg_subscription_rel.h index ab1202cf9bff8..2bea2c52aa760 100644 --- a/src/include/catalog/pg_subscription_rel.h +++ b/src/include/catalog/pg_subscription_rel.h @@ -30,8 +30,8 @@ */ CATALOG(pg_subscription_rel,6102,SubscriptionRelRelationId) { - Oid srsubid; /* Oid of subscription */ - Oid srrelid; /* Oid of relation */ + Oid srsubid BKI_LOOKUP(pg_subscription); /* Oid of subscription */ + Oid srrelid BKI_LOOKUP(pg_class); /* Oid of relation */ char srsubstate; /* state of the relation in subscription */ /* diff --git a/src/include/catalog/pg_tablespace.dat b/src/include/catalog/pg_tablespace.dat index 212a0ad07fb5f..bf0d81d3061a8 100644 --- a/src/include/catalog/pg_tablespace.dat +++ b/src/include/catalog/pg_tablespace.dat @@ -13,10 +13,8 @@ [ { oid => '1663', oid_symbol => 'DEFAULTTABLESPACE_OID', - spcname => 'pg_default', spcowner => 'PGUID', spcacl => '_null_', - spcoptions => '_null_' }, + spcname => 'pg_default', spcacl => '_null_', spcoptions => '_null_' }, { oid => '1664', oid_symbol => 'GLOBALTABLESPACE_OID', - spcname => 'pg_global', spcowner => 'PGUID', spcacl => '_null_', - spcoptions => '_null_' }, + spcname => 'pg_global', spcacl => '_null_', spcoptions => '_null_' }, ] diff --git a/src/include/catalog/pg_tablespace.h b/src/include/catalog/pg_tablespace.h index 6a6c66a61c848..ed38e6950ddcb 100644 --- a/src/include/catalog/pg_tablespace.h +++ b/src/include/catalog/pg_tablespace.h @@ -30,7 +30,7 @@ CATALOG(pg_tablespace,1213,TableSpaceRelationId) BKI_SHARED_RELATION { Oid oid; /* oid */ NameData spcname; /* tablespace name */ - Oid spcowner; /* owner of tablespace */ + Oid spcowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); /* owner of tablespace */ #ifdef CATALOG_VARLEN /* variable-length fields start here */ aclitem spcacl[1]; /* access permissions */ diff --git a/src/include/catalog/pg_transform.h b/src/include/catalog/pg_transform.h index ad25db1841199..d60324613857f 100644 --- a/src/include/catalog/pg_transform.h +++ b/src/include/catalog/pg_transform.h @@ -29,10 +29,10 @@ CATALOG(pg_transform,3576,TransformRelationId) { Oid oid; /* oid */ - Oid trftype; - Oid trflang; - regproc trffromsql; - regproc trftosql; + Oid trftype BKI_LOOKUP(pg_type); + Oid trflang BKI_LOOKUP(pg_language); + regproc trffromsql BKI_LOOKUP_OPT(pg_proc); + regproc trftosql BKI_LOOKUP_OPT(pg_proc); } FormData_pg_transform; /* ---------------- diff --git a/src/include/catalog/pg_trigger.h b/src/include/catalog/pg_trigger.h index 55111ed864e9b..2e3d2338763f3 100644 --- a/src/include/catalog/pg_trigger.h +++ b/src/include/catalog/pg_trigger.h @@ -34,18 +34,25 @@ CATALOG(pg_trigger,2620,TriggerRelationId) { Oid oid; /* oid */ - Oid tgrelid; /* relation trigger is attached to */ - Oid tgparentid; /* OID of parent trigger, if any */ + Oid tgrelid BKI_LOOKUP(pg_class); /* relation trigger is + * attached to */ + Oid tgparentid BKI_LOOKUP_OPT(pg_trigger); /* OID of parent + * trigger, if any */ NameData tgname; /* trigger's name */ - Oid tgfoid; /* OID of function to be called */ + Oid tgfoid BKI_LOOKUP(pg_proc); /* OID of function to be called */ int16 tgtype; /* BEFORE/AFTER/INSTEAD, UPDATE/DELETE/INSERT, * ROW/STATEMENT; see below */ char tgenabled; /* trigger's firing configuration WRT * session_replication_role */ bool tgisinternal; /* trigger is system-generated */ - Oid tgconstrrelid; /* constraint's FROM table, if any */ - Oid tgconstrindid; /* constraint's supporting index, if any */ - Oid tgconstraint; /* associated pg_constraint entry, if any */ + Oid tgconstrrelid BKI_LOOKUP_OPT(pg_class); /* constraint's FROM + * table, if any */ + Oid tgconstrindid BKI_LOOKUP_OPT(pg_class); /* constraint's + * supporting index, if + * any */ + Oid tgconstraint BKI_LOOKUP_OPT(pg_constraint); /* associated + * pg_constraint entry, + * if any */ bool tgdeferrable; /* constraint trigger is deferrable */ bool tginitdeferred; /* constraint trigger is deferred initially */ int16 tgnargs; /* # of extra arguments in tgargs */ @@ -81,6 +88,8 @@ DECLARE_UNIQUE_INDEX(pg_trigger_tgrelid_tgname_index, 2701, on pg_trigger using DECLARE_UNIQUE_INDEX_PKEY(pg_trigger_oid_index, 2702, on pg_trigger using btree(oid oid_ops)); #define TriggerOidIndexId 2702 +DECLARE_ARRAY_FOREIGN_KEY((tgrelid, tgattr), pg_attribute, (attrelid, attnum)); + #ifdef EXPOSE_TO_CLIENT_CODE /* Bits within tgtype */ diff --git a/src/include/catalog/pg_ts_config.h b/src/include/catalog/pg_ts_config.h index 02ef1a1554404..e705899b179e0 100644 --- a/src/include/catalog/pg_ts_config.h +++ b/src/include/catalog/pg_ts_config.h @@ -36,10 +36,10 @@ CATALOG(pg_ts_config,3602,TSConfigRelationId) NameData cfgname; /* name space */ - Oid cfgnamespace BKI_DEFAULT(PGNSP); + Oid cfgnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace); /* owner */ - Oid cfgowner BKI_DEFAULT(PGUID); + Oid cfgowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); /* OID of parser */ Oid cfgparser BKI_LOOKUP(pg_ts_parser); diff --git a/src/include/catalog/pg_ts_dict.h b/src/include/catalog/pg_ts_dict.h index bfe3378ff893c..57f626e7b592c 100644 --- a/src/include/catalog/pg_ts_dict.h +++ b/src/include/catalog/pg_ts_dict.h @@ -35,10 +35,10 @@ CATALOG(pg_ts_dict,3600,TSDictionaryRelationId) NameData dictname; /* name space */ - Oid dictnamespace BKI_DEFAULT(PGNSP); + Oid dictnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace); /* owner */ - Oid dictowner BKI_DEFAULT(PGUID); + Oid dictowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); /* dictionary's template */ Oid dicttemplate BKI_LOOKUP(pg_ts_template); diff --git a/src/include/catalog/pg_ts_parser.h b/src/include/catalog/pg_ts_parser.h index f9f22716fd470..e0d705fd9ae57 100644 --- a/src/include/catalog/pg_ts_parser.h +++ b/src/include/catalog/pg_ts_parser.h @@ -34,7 +34,7 @@ CATALOG(pg_ts_parser,3601,TSParserRelationId) NameData prsname; /* name space */ - Oid prsnamespace BKI_DEFAULT(PGNSP); + Oid prsnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace); /* init parsing session */ regproc prsstart BKI_LOOKUP(pg_proc); @@ -46,7 +46,7 @@ CATALOG(pg_ts_parser,3601,TSParserRelationId) regproc prsend BKI_LOOKUP(pg_proc); /* return data for headline creation */ - regproc prsheadline BKI_LOOKUP(pg_proc); + regproc prsheadline BKI_LOOKUP_OPT(pg_proc); /* return descriptions of lexeme's types */ regproc prslextype BKI_LOOKUP(pg_proc); diff --git a/src/include/catalog/pg_ts_template.h b/src/include/catalog/pg_ts_template.h index ae91922688989..2ee1ae4e85f62 100644 --- a/src/include/catalog/pg_ts_template.h +++ b/src/include/catalog/pg_ts_template.h @@ -34,10 +34,10 @@ CATALOG(pg_ts_template,3764,TSTemplateRelationId) NameData tmplname; /* name space */ - Oid tmplnamespace BKI_DEFAULT(PGNSP); + Oid tmplnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace); /* initialization method of dict (may be 0) */ - regproc tmplinit BKI_LOOKUP(pg_proc); + regproc tmplinit BKI_LOOKUP_OPT(pg_proc); /* base method of dictionary */ regproc tmpllexize BKI_LOOKUP(pg_proc); diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index 0d6981bc879d1..1ec8606703811 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -41,10 +41,10 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati NameData typname; /* OID of namespace containing this type */ - Oid typnamespace BKI_DEFAULT(PGNSP); + Oid typnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace); /* type owner */ - Oid typowner BKI_DEFAULT(PGUID); + Oid typowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); /* * For a fixed-size type, typlen is the number of bytes we use to @@ -98,7 +98,7 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati char typdelim BKI_DEFAULT(','); /* associated pg_class OID if a composite type, else 0 */ - Oid typrelid BKI_DEFAULT(0) BKI_ARRAY_DEFAULT(0) BKI_LOOKUP(pg_class); + Oid typrelid BKI_DEFAULT(0) BKI_ARRAY_DEFAULT(0) BKI_LOOKUP_OPT(pg_class); /* * Type-specific subscripting handler. If typsubscript is 0, it means @@ -106,7 +106,7 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati * of the system deem types to be "true" array types only if their * typsubscript is array_subscript_handler. */ - regproc typsubscript BKI_DEFAULT(-) BKI_ARRAY_DEFAULT(array_subscript_handler) BKI_LOOKUP(pg_proc); + regproc typsubscript BKI_DEFAULT(-) BKI_ARRAY_DEFAULT(array_subscript_handler) BKI_LOOKUP_OPT(pg_proc); /* * If typelem is not 0 then it identifies another row in pg_type, defining @@ -117,13 +117,13 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati * of the element type in this type; so DDL changes on the element type * might be restricted by the presence of this type. */ - Oid typelem BKI_DEFAULT(0) BKI_LOOKUP(pg_type); + Oid typelem BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_type); /* * If there is a "true" array type having this type as element type, * typarray links to it. Zero if no associated "true" array type. */ - Oid typarray BKI_DEFAULT(0) BKI_ARRAY_DEFAULT(0) BKI_LOOKUP(pg_type); + Oid typarray BKI_DEFAULT(0) BKI_ARRAY_DEFAULT(0) BKI_LOOKUP_OPT(pg_type); /* * I/O conversion procedures for the datatype. @@ -134,19 +134,19 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati regproc typoutput BKI_ARRAY_DEFAULT(array_out) BKI_LOOKUP(pg_proc); /* binary format (optional) */ - regproc typreceive BKI_ARRAY_DEFAULT(array_recv) BKI_LOOKUP(pg_proc); - regproc typsend BKI_ARRAY_DEFAULT(array_send) BKI_LOOKUP(pg_proc); + regproc typreceive BKI_ARRAY_DEFAULT(array_recv) BKI_LOOKUP_OPT(pg_proc); + regproc typsend BKI_ARRAY_DEFAULT(array_send) BKI_LOOKUP_OPT(pg_proc); /* * I/O functions for optional type modifiers. */ - regproc typmodin BKI_DEFAULT(-) BKI_LOOKUP(pg_proc); - regproc typmodout BKI_DEFAULT(-) BKI_LOOKUP(pg_proc); + regproc typmodin BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc); + regproc typmodout BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc); /* * Custom ANALYZE procedure for the datatype (0 selects the default). */ - regproc typanalyze BKI_DEFAULT(-) BKI_ARRAY_DEFAULT(array_typanalyze) BKI_LOOKUP(pg_proc); + regproc typanalyze BKI_DEFAULT(-) BKI_ARRAY_DEFAULT(array_typanalyze) BKI_LOOKUP_OPT(pg_proc); /* ---------------- * typalign is the alignment required when storing a value of this @@ -205,7 +205,7 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati * Domains use typbasetype to show the base (or domain) type that the * domain is based on. Zero if the type is not a domain. */ - Oid typbasetype BKI_DEFAULT(0); + Oid typbasetype BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_type); /* * Domains use typtypmod to record the typmod to be applied to their base @@ -225,7 +225,7 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati * DEFAULT_COLLATION_OID) for collatable base types, possibly some other * OID for domains over collatable types */ - Oid typcollation BKI_DEFAULT(0) BKI_LOOKUP(pg_collation); + Oid typcollation BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_collation); #ifdef CATALOG_VARLEN /* variable-length fields start here */ diff --git a/src/include/catalog/pg_user_mapping.h b/src/include/catalog/pg_user_mapping.h index cabca048a928b..d440c67da191f 100644 --- a/src/include/catalog/pg_user_mapping.h +++ b/src/include/catalog/pg_user_mapping.h @@ -29,9 +29,11 @@ CATALOG(pg_user_mapping,1418,UserMappingRelationId) { Oid oid; /* oid */ - Oid umuser; /* Id of the user, InvalidOid if PUBLIC is - * wanted */ - Oid umserver; /* server of this mapping */ + Oid umuser BKI_LOOKUP_OPT(pg_authid); /* Id of the user, + * InvalidOid if PUBLIC is + * wanted */ + Oid umserver BKI_LOOKUP(pg_foreign_server); /* server of this + * mapping */ #ifdef CATALOG_VARLEN /* variable-length fields start here */ text umoptions[1]; /* user mapping options */ diff --git a/src/test/regress/expected/oidjoins.out b/src/test/regress/expected/oidjoins.out index 4731dacfbf429..50d046d3ef1ad 100644 --- a/src/test/regress/expected/oidjoins.out +++ b/src/test/regress/expected/oidjoins.out @@ -1,1451 +1,266 @@ -- --- This is created by pgsql/src/tools/findoidjoins/make_oidjoins_check +-- Verify system catalog foreign key relationships -- -SELECT ctid, aggfnoid -FROM pg_catalog.pg_aggregate fk -WHERE aggfnoid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggfnoid); - ctid | aggfnoid -------+---------- -(0 rows) - -SELECT ctid, aggtransfn -FROM pg_catalog.pg_aggregate fk -WHERE aggtransfn != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggtransfn); - ctid | aggtransfn -------+------------ -(0 rows) - -SELECT ctid, aggfinalfn -FROM pg_catalog.pg_aggregate fk -WHERE aggfinalfn != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggfinalfn); - ctid | aggfinalfn -------+------------ -(0 rows) - -SELECT ctid, aggcombinefn -FROM pg_catalog.pg_aggregate fk -WHERE aggcombinefn != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggcombinefn); - ctid | aggcombinefn -------+-------------- -(0 rows) - -SELECT ctid, aggserialfn -FROM pg_catalog.pg_aggregate fk -WHERE aggserialfn != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggserialfn); - ctid | aggserialfn -------+------------- -(0 rows) - -SELECT ctid, aggdeserialfn -FROM pg_catalog.pg_aggregate fk -WHERE aggdeserialfn != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggdeserialfn); - ctid | aggdeserialfn -------+--------------- -(0 rows) - -SELECT ctid, aggmtransfn -FROM pg_catalog.pg_aggregate fk -WHERE aggmtransfn != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggmtransfn); - ctid | aggmtransfn -------+------------- -(0 rows) - -SELECT ctid, aggminvtransfn -FROM pg_catalog.pg_aggregate fk -WHERE aggminvtransfn != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggminvtransfn); - ctid | aggminvtransfn -------+---------------- -(0 rows) - -SELECT ctid, aggmfinalfn -FROM pg_catalog.pg_aggregate fk -WHERE aggmfinalfn != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggmfinalfn); - ctid | aggmfinalfn -------+------------- -(0 rows) - -SELECT ctid, aggsortop -FROM pg_catalog.pg_aggregate fk -WHERE aggsortop != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.aggsortop); - ctid | aggsortop -------+----------- -(0 rows) - -SELECT ctid, aggtranstype -FROM pg_catalog.pg_aggregate fk -WHERE aggtranstype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggtranstype); - ctid | aggtranstype -------+-------------- -(0 rows) - -SELECT ctid, aggmtranstype -FROM pg_catalog.pg_aggregate fk -WHERE aggmtranstype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggmtranstype); - ctid | aggmtranstype -------+--------------- -(0 rows) - -SELECT ctid, amhandler -FROM pg_catalog.pg_am fk -WHERE amhandler != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amhandler); - ctid | amhandler -------+----------- -(0 rows) - -SELECT ctid, amopfamily -FROM pg_catalog.pg_amop fk -WHERE amopfamily != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amopfamily); - ctid | amopfamily -------+------------ -(0 rows) - -SELECT ctid, amoplefttype -FROM pg_catalog.pg_amop fk -WHERE amoplefttype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amoplefttype); - ctid | amoplefttype -------+-------------- -(0 rows) - -SELECT ctid, amoprighttype -FROM pg_catalog.pg_amop fk -WHERE amoprighttype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amoprighttype); - ctid | amoprighttype -------+--------------- -(0 rows) - -SELECT ctid, amopopr -FROM pg_catalog.pg_amop fk -WHERE amopopr != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.amopopr); - ctid | amopopr -------+--------- -(0 rows) - -SELECT ctid, amopmethod -FROM pg_catalog.pg_amop fk -WHERE amopmethod != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.amopmethod); - ctid | amopmethod -------+------------ -(0 rows) - -SELECT ctid, amopsortfamily -FROM pg_catalog.pg_amop fk -WHERE amopsortfamily != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amopsortfamily); - ctid | amopsortfamily -------+---------------- -(0 rows) - -SELECT ctid, amprocfamily -FROM pg_catalog.pg_amproc fk -WHERE amprocfamily != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amprocfamily); - ctid | amprocfamily -------+-------------- -(0 rows) - -SELECT ctid, amproclefttype -FROM pg_catalog.pg_amproc fk -WHERE amproclefttype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amproclefttype); - ctid | amproclefttype -------+---------------- -(0 rows) - -SELECT ctid, amprocrighttype -FROM pg_catalog.pg_amproc fk -WHERE amprocrighttype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amprocrighttype); - ctid | amprocrighttype -------+----------------- -(0 rows) - -SELECT ctid, amproc -FROM pg_catalog.pg_amproc fk -WHERE amproc != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amproc); - ctid | amproc -------+-------- -(0 rows) - -SELECT ctid, adrelid -FROM pg_catalog.pg_attrdef fk -WHERE adrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.adrelid); - ctid | adrelid -------+--------- -(0 rows) - -SELECT ctid, attrelid -FROM pg_catalog.pg_attribute fk -WHERE attrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.attrelid); - ctid | attrelid -------+---------- -(0 rows) - -SELECT ctid, atttypid -FROM pg_catalog.pg_attribute fk -WHERE atttypid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.atttypid); - ctid | atttypid -------+---------- -(0 rows) - -SELECT ctid, attcollation -FROM pg_catalog.pg_attribute fk -WHERE attcollation != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.attcollation); - ctid | attcollation -------+-------------- -(0 rows) - -SELECT ctid, roleid -FROM pg_catalog.pg_auth_members fk -WHERE roleid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.roleid); - ctid | roleid -------+-------- -(0 rows) - -SELECT ctid, member -FROM pg_catalog.pg_auth_members fk -WHERE member != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.member); - ctid | member -------+-------- -(0 rows) - -SELECT ctid, grantor -FROM pg_catalog.pg_auth_members fk -WHERE grantor != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.grantor); - ctid | grantor -------+--------- -(0 rows) - -SELECT ctid, castsource -FROM pg_catalog.pg_cast fk -WHERE castsource != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.castsource); - ctid | castsource -------+------------ -(0 rows) - -SELECT ctid, casttarget -FROM pg_catalog.pg_cast fk -WHERE casttarget != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.casttarget); - ctid | casttarget -------+------------ -(0 rows) - -SELECT ctid, castfunc -FROM pg_catalog.pg_cast fk -WHERE castfunc != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.castfunc); - ctid | castfunc -------+---------- -(0 rows) - -SELECT ctid, relnamespace -FROM pg_catalog.pg_class fk -WHERE relnamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.relnamespace); - ctid | relnamespace -------+-------------- -(0 rows) - -SELECT ctid, reltype -FROM pg_catalog.pg_class fk -WHERE reltype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.reltype); - ctid | reltype -------+--------- -(0 rows) - -SELECT ctid, reloftype -FROM pg_catalog.pg_class fk -WHERE reloftype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.reloftype); - ctid | reloftype -------+----------- -(0 rows) - -SELECT ctid, relowner -FROM pg_catalog.pg_class fk -WHERE relowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.relowner); - ctid | relowner -------+---------- -(0 rows) - -SELECT ctid, relam -FROM pg_catalog.pg_class fk -WHERE relam != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.relam); - ctid | relam -------+------- -(0 rows) - -SELECT ctid, reltablespace -FROM pg_catalog.pg_class fk -WHERE reltablespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_tablespace pk WHERE pk.oid = fk.reltablespace); - ctid | reltablespace -------+--------------- -(0 rows) - -SELECT ctid, reltoastrelid -FROM pg_catalog.pg_class fk -WHERE reltoastrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.reltoastrelid); - ctid | reltoastrelid -------+--------------- -(0 rows) - -SELECT ctid, collnamespace -FROM pg_catalog.pg_collation fk -WHERE collnamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.collnamespace); - ctid | collnamespace -------+--------------- -(0 rows) - -SELECT ctid, collowner -FROM pg_catalog.pg_collation fk -WHERE collowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.collowner); - ctid | collowner -------+----------- -(0 rows) - -SELECT ctid, connamespace -FROM pg_catalog.pg_constraint fk -WHERE connamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.connamespace); - ctid | connamespace -------+-------------- -(0 rows) - -SELECT ctid, conrelid -FROM pg_catalog.pg_constraint fk -WHERE conrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.conrelid); - ctid | conrelid -------+---------- -(0 rows) - -SELECT ctid, contypid -FROM pg_catalog.pg_constraint fk -WHERE contypid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.contypid); - ctid | contypid -------+---------- -(0 rows) - -SELECT ctid, conindid -FROM pg_catalog.pg_constraint fk -WHERE conindid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.conindid); - ctid | conindid -------+---------- -(0 rows) - -SELECT ctid, conparentid -FROM pg_catalog.pg_constraint fk -WHERE conparentid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_constraint pk WHERE pk.oid = fk.conparentid); - ctid | conparentid -------+------------- -(0 rows) - -SELECT ctid, confrelid -FROM pg_catalog.pg_constraint fk -WHERE confrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.confrelid); - ctid | confrelid -------+----------- -(0 rows) - -SELECT ctid, connamespace -FROM pg_catalog.pg_conversion fk -WHERE connamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.connamespace); - ctid | connamespace -------+-------------- -(0 rows) - -SELECT ctid, conowner -FROM pg_catalog.pg_conversion fk -WHERE conowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.conowner); - ctid | conowner -------+---------- -(0 rows) - -SELECT ctid, conproc -FROM pg_catalog.pg_conversion fk -WHERE conproc != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.conproc); - ctid | conproc -------+--------- -(0 rows) - -SELECT ctid, datdba -FROM pg_catalog.pg_database fk -WHERE datdba != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.datdba); - ctid | datdba -------+-------- -(0 rows) - -SELECT ctid, dattablespace -FROM pg_catalog.pg_database fk -WHERE dattablespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_tablespace pk WHERE pk.oid = fk.dattablespace); - ctid | dattablespace -------+--------------- -(0 rows) - -SELECT ctid, setdatabase -FROM pg_catalog.pg_db_role_setting fk -WHERE setdatabase != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_database pk WHERE pk.oid = fk.setdatabase); - ctid | setdatabase -------+------------- -(0 rows) - -SELECT ctid, classid -FROM pg_catalog.pg_depend fk -WHERE classid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classid); - ctid | classid -------+--------- -(0 rows) - -SELECT ctid, refclassid -FROM pg_catalog.pg_depend fk -WHERE refclassid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.refclassid); - ctid | refclassid -------+------------ -(0 rows) - -SELECT ctid, classoid -FROM pg_catalog.pg_description fk -WHERE classoid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classoid); - ctid | classoid -------+---------- -(0 rows) - -SELECT ctid, enumtypid -FROM pg_catalog.pg_enum fk -WHERE enumtypid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.enumtypid); - ctid | enumtypid -------+----------- -(0 rows) - -SELECT ctid, extowner -FROM pg_catalog.pg_extension fk -WHERE extowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.extowner); - ctid | extowner -------+---------- -(0 rows) - -SELECT ctid, extnamespace -FROM pg_catalog.pg_extension fk -WHERE extnamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.extnamespace); - ctid | extnamespace -------+-------------- -(0 rows) - -SELECT ctid, fdwowner -FROM pg_catalog.pg_foreign_data_wrapper fk -WHERE fdwowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.fdwowner); - ctid | fdwowner -------+---------- -(0 rows) - -SELECT ctid, srvowner -FROM pg_catalog.pg_foreign_server fk -WHERE srvowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.srvowner); - ctid | srvowner -------+---------- -(0 rows) - -SELECT ctid, srvfdw -FROM pg_catalog.pg_foreign_server fk -WHERE srvfdw != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_foreign_data_wrapper pk WHERE pk.oid = fk.srvfdw); - ctid | srvfdw -------+-------- -(0 rows) - -SELECT ctid, indexrelid -FROM pg_catalog.pg_index fk -WHERE indexrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.indexrelid); - ctid | indexrelid -------+------------ -(0 rows) - -SELECT ctid, indrelid -FROM pg_catalog.pg_index fk -WHERE indrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.indrelid); - ctid | indrelid -------+---------- -(0 rows) - -SELECT ctid, inhrelid -FROM pg_catalog.pg_inherits fk -WHERE inhrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.inhrelid); - ctid | inhrelid -------+---------- -(0 rows) - -SELECT ctid, inhparent -FROM pg_catalog.pg_inherits fk -WHERE inhparent != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.inhparent); - ctid | inhparent -------+----------- -(0 rows) - -SELECT ctid, classoid -FROM pg_catalog.pg_init_privs fk -WHERE classoid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classoid); - ctid | classoid -------+---------- -(0 rows) - -SELECT ctid, lanowner -FROM pg_catalog.pg_language fk -WHERE lanowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.lanowner); - ctid | lanowner -------+---------- -(0 rows) - -SELECT ctid, lanplcallfoid -FROM pg_catalog.pg_language fk -WHERE lanplcallfoid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.lanplcallfoid); - ctid | lanplcallfoid -------+--------------- -(0 rows) - -SELECT ctid, laninline -FROM pg_catalog.pg_language fk -WHERE laninline != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.laninline); - ctid | laninline -------+----------- -(0 rows) - -SELECT ctid, lanvalidator -FROM pg_catalog.pg_language fk -WHERE lanvalidator != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.lanvalidator); - ctid | lanvalidator -------+-------------- -(0 rows) - -SELECT ctid, loid -FROM pg_catalog.pg_largeobject fk -WHERE loid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_largeobject_metadata pk WHERE pk.oid = fk.loid); - ctid | loid -------+------ -(0 rows) - -SELECT ctid, lomowner -FROM pg_catalog.pg_largeobject_metadata fk -WHERE lomowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.lomowner); - ctid | lomowner -------+---------- -(0 rows) - -SELECT ctid, nspowner -FROM pg_catalog.pg_namespace fk -WHERE nspowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.nspowner); - ctid | nspowner -------+---------- -(0 rows) - -SELECT ctid, opcmethod -FROM pg_catalog.pg_opclass fk -WHERE opcmethod != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.opcmethod); - ctid | opcmethod -------+----------- -(0 rows) - -SELECT ctid, opcnamespace -FROM pg_catalog.pg_opclass fk -WHERE opcnamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.opcnamespace); - ctid | opcnamespace -------+-------------- -(0 rows) - -SELECT ctid, opcowner -FROM pg_catalog.pg_opclass fk -WHERE opcowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.opcowner); - ctid | opcowner -------+---------- -(0 rows) - -SELECT ctid, opcfamily -FROM pg_catalog.pg_opclass fk -WHERE opcfamily != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.opcfamily); - ctid | opcfamily -------+----------- -(0 rows) - -SELECT ctid, opcintype -FROM pg_catalog.pg_opclass fk -WHERE opcintype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.opcintype); - ctid | opcintype -------+----------- -(0 rows) - -SELECT ctid, opckeytype -FROM pg_catalog.pg_opclass fk -WHERE opckeytype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.opckeytype); - ctid | opckeytype -------+------------ -(0 rows) - -SELECT ctid, oprnamespace -FROM pg_catalog.pg_operator fk -WHERE oprnamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.oprnamespace); - ctid | oprnamespace -------+-------------- -(0 rows) - -SELECT ctid, oprowner -FROM pg_catalog.pg_operator fk -WHERE oprowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.oprowner); - ctid | oprowner -------+---------- -(0 rows) - -SELECT ctid, oprleft -FROM pg_catalog.pg_operator fk -WHERE oprleft != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.oprleft); - ctid | oprleft -------+--------- -(0 rows) - -SELECT ctid, oprright -FROM pg_catalog.pg_operator fk -WHERE oprright != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.oprright); - ctid | oprright -------+---------- -(0 rows) - -SELECT ctid, oprresult -FROM pg_catalog.pg_operator fk -WHERE oprresult != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.oprresult); - ctid | oprresult -------+----------- -(0 rows) - -SELECT ctid, oprcom -FROM pg_catalog.pg_operator fk -WHERE oprcom != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.oprcom); - ctid | oprcom -------+-------- -(0 rows) - -SELECT ctid, oprnegate -FROM pg_catalog.pg_operator fk -WHERE oprnegate != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.oprnegate); - ctid | oprnegate -------+----------- -(0 rows) - -SELECT ctid, oprcode -FROM pg_catalog.pg_operator fk -WHERE oprcode != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.oprcode); - ctid | oprcode -------+--------- -(0 rows) - -SELECT ctid, oprrest -FROM pg_catalog.pg_operator fk -WHERE oprrest != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.oprrest); - ctid | oprrest -------+--------- -(0 rows) - -SELECT ctid, oprjoin -FROM pg_catalog.pg_operator fk -WHERE oprjoin != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.oprjoin); - ctid | oprjoin -------+--------- -(0 rows) - -SELECT ctid, opfmethod -FROM pg_catalog.pg_opfamily fk -WHERE opfmethod != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.opfmethod); - ctid | opfmethod -------+----------- -(0 rows) - -SELECT ctid, opfnamespace -FROM pg_catalog.pg_opfamily fk -WHERE opfnamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.opfnamespace); - ctid | opfnamespace -------+-------------- -(0 rows) - -SELECT ctid, opfowner -FROM pg_catalog.pg_opfamily fk -WHERE opfowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.opfowner); - ctid | opfowner -------+---------- -(0 rows) - -SELECT ctid, partrelid -FROM pg_catalog.pg_partitioned_table fk -WHERE partrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.partrelid); - ctid | partrelid -------+----------- -(0 rows) - -SELECT ctid, partdefid -FROM pg_catalog.pg_partitioned_table fk -WHERE partdefid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.partdefid); - ctid | partdefid -------+----------- -(0 rows) - -SELECT ctid, polrelid -FROM pg_catalog.pg_policy fk -WHERE polrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.polrelid); - ctid | polrelid -------+---------- -(0 rows) - -SELECT ctid, pronamespace -FROM pg_catalog.pg_proc fk -WHERE pronamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.pronamespace); - ctid | pronamespace -------+-------------- -(0 rows) - -SELECT ctid, proowner -FROM pg_catalog.pg_proc fk -WHERE proowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.proowner); - ctid | proowner -------+---------- -(0 rows) - -SELECT ctid, prolang -FROM pg_catalog.pg_proc fk -WHERE prolang != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_language pk WHERE pk.oid = fk.prolang); - ctid | prolang -------+--------- -(0 rows) - -SELECT ctid, provariadic -FROM pg_catalog.pg_proc fk -WHERE provariadic != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.provariadic); - ctid | provariadic -------+------------- -(0 rows) - -SELECT ctid, prosupport -FROM pg_catalog.pg_proc fk -WHERE prosupport != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prosupport); - ctid | prosupport -------+------------ -(0 rows) - -SELECT ctid, prorettype -FROM pg_catalog.pg_proc fk -WHERE prorettype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.prorettype); - ctid | prorettype -------+------------ -(0 rows) - -SELECT ctid, rngtypid -FROM pg_catalog.pg_range fk -WHERE rngtypid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.rngtypid); - ctid | rngtypid -------+---------- -(0 rows) - -SELECT ctid, rngsubtype -FROM pg_catalog.pg_range fk -WHERE rngsubtype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.rngsubtype); - ctid | rngsubtype -------+------------ -(0 rows) - -SELECT ctid, rngcollation -FROM pg_catalog.pg_range fk -WHERE rngcollation != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.rngcollation); - ctid | rngcollation -------+-------------- -(0 rows) - -SELECT ctid, rngsubopc -FROM pg_catalog.pg_range fk -WHERE rngsubopc != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.rngsubopc); - ctid | rngsubopc -------+----------- -(0 rows) - -SELECT ctid, rngcanonical -FROM pg_catalog.pg_range fk -WHERE rngcanonical != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.rngcanonical); - ctid | rngcanonical -------+-------------- -(0 rows) - -SELECT ctid, rngsubdiff -FROM pg_catalog.pg_range fk -WHERE rngsubdiff != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.rngsubdiff); - ctid | rngsubdiff -------+------------ -(0 rows) - -SELECT ctid, ev_class -FROM pg_catalog.pg_rewrite fk -WHERE ev_class != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.ev_class); - ctid | ev_class -------+---------- -(0 rows) - -SELECT ctid, seqrelid -FROM pg_catalog.pg_sequence fk -WHERE seqrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.seqrelid); - ctid | seqrelid -------+---------- -(0 rows) - -SELECT ctid, seqtypid -FROM pg_catalog.pg_sequence fk -WHERE seqtypid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.seqtypid); - ctid | seqtypid -------+---------- -(0 rows) - -SELECT ctid, refclassid -FROM pg_catalog.pg_shdepend fk -WHERE refclassid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.refclassid); - ctid | refclassid -------+------------ -(0 rows) - -SELECT ctid, classoid -FROM pg_catalog.pg_shdescription fk -WHERE classoid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classoid); - ctid | classoid -------+---------- -(0 rows) - -SELECT ctid, starelid -FROM pg_catalog.pg_statistic fk -WHERE starelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.starelid); - ctid | starelid -------+---------- -(0 rows) - -SELECT ctid, staop1 -FROM pg_catalog.pg_statistic fk -WHERE staop1 != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop1); - ctid | staop1 -------+-------- -(0 rows) - -SELECT ctid, staop2 -FROM pg_catalog.pg_statistic fk -WHERE staop2 != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop2); - ctid | staop2 -------+-------- -(0 rows) - -SELECT ctid, staop3 -FROM pg_catalog.pg_statistic fk -WHERE staop3 != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop3); - ctid | staop3 -------+-------- -(0 rows) - -SELECT ctid, staop4 -FROM pg_catalog.pg_statistic fk -WHERE staop4 != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop4); - ctid | staop4 -------+-------- -(0 rows) - -SELECT ctid, staop5 -FROM pg_catalog.pg_statistic fk -WHERE staop5 != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop5); - ctid | staop5 -------+-------- -(0 rows) - -SELECT ctid, stacoll1 -FROM pg_catalog.pg_statistic fk -WHERE stacoll1 != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll1); - ctid | stacoll1 -------+---------- -(0 rows) - -SELECT ctid, stacoll2 -FROM pg_catalog.pg_statistic fk -WHERE stacoll2 != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll2); - ctid | stacoll2 -------+---------- -(0 rows) - -SELECT ctid, stacoll3 -FROM pg_catalog.pg_statistic fk -WHERE stacoll3 != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll3); - ctid | stacoll3 -------+---------- -(0 rows) - -SELECT ctid, stacoll4 -FROM pg_catalog.pg_statistic fk -WHERE stacoll4 != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll4); - ctid | stacoll4 -------+---------- -(0 rows) - -SELECT ctid, stacoll5 -FROM pg_catalog.pg_statistic fk -WHERE stacoll5 != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll5); - ctid | stacoll5 -------+---------- -(0 rows) - -SELECT ctid, stxrelid -FROM pg_catalog.pg_statistic_ext fk -WHERE stxrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.stxrelid); - ctid | stxrelid -------+---------- -(0 rows) - -SELECT ctid, stxnamespace -FROM pg_catalog.pg_statistic_ext fk -WHERE stxnamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.stxnamespace); - ctid | stxnamespace -------+-------------- -(0 rows) - -SELECT ctid, stxowner -FROM pg_catalog.pg_statistic_ext fk -WHERE stxowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.stxowner); - ctid | stxowner -------+---------- -(0 rows) - -SELECT ctid, stxoid -FROM pg_catalog.pg_statistic_ext_data fk -WHERE stxoid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_statistic_ext pk WHERE pk.oid = fk.stxoid); - ctid | stxoid -------+-------- -(0 rows) - -SELECT ctid, spcowner -FROM pg_catalog.pg_tablespace fk -WHERE spcowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.spcowner); - ctid | spcowner -------+---------- -(0 rows) - -SELECT ctid, trftype -FROM pg_catalog.pg_transform fk -WHERE trftype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.trftype); - ctid | trftype -------+--------- -(0 rows) - -SELECT ctid, trflang -FROM pg_catalog.pg_transform fk -WHERE trflang != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_language pk WHERE pk.oid = fk.trflang); - ctid | trflang -------+--------- -(0 rows) - -SELECT ctid, trffromsql -FROM pg_catalog.pg_transform fk -WHERE trffromsql != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.trffromsql); - ctid | trffromsql -------+------------ -(0 rows) - -SELECT ctid, trftosql -FROM pg_catalog.pg_transform fk -WHERE trftosql != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.trftosql); - ctid | trftosql -------+---------- -(0 rows) - -SELECT ctid, tgrelid -FROM pg_catalog.pg_trigger fk -WHERE tgrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.tgrelid); - ctid | tgrelid -------+--------- -(0 rows) - -SELECT ctid, tgparentid -FROM pg_catalog.pg_trigger fk -WHERE tgparentid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_trigger pk WHERE pk.oid = fk.tgparentid); - ctid | tgparentid -------+------------ -(0 rows) - -SELECT ctid, tgfoid -FROM pg_catalog.pg_trigger fk -WHERE tgfoid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.tgfoid); - ctid | tgfoid -------+-------- -(0 rows) - -SELECT ctid, tgconstrrelid -FROM pg_catalog.pg_trigger fk -WHERE tgconstrrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.tgconstrrelid); - ctid | tgconstrrelid -------+--------------- -(0 rows) - -SELECT ctid, tgconstrindid -FROM pg_catalog.pg_trigger fk -WHERE tgconstrindid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.tgconstrindid); - ctid | tgconstrindid -------+--------------- -(0 rows) - -SELECT ctid, tgconstraint -FROM pg_catalog.pg_trigger fk -WHERE tgconstraint != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_constraint pk WHERE pk.oid = fk.tgconstraint); - ctid | tgconstraint -------+-------------- -(0 rows) - -SELECT ctid, cfgnamespace -FROM pg_catalog.pg_ts_config fk -WHERE cfgnamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.cfgnamespace); - ctid | cfgnamespace -------+-------------- -(0 rows) - -SELECT ctid, cfgowner -FROM pg_catalog.pg_ts_config fk -WHERE cfgowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.cfgowner); - ctid | cfgowner -------+---------- -(0 rows) - -SELECT ctid, cfgparser -FROM pg_catalog.pg_ts_config fk -WHERE cfgparser != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_ts_parser pk WHERE pk.oid = fk.cfgparser); - ctid | cfgparser -------+----------- -(0 rows) - -SELECT ctid, mapcfg -FROM pg_catalog.pg_ts_config_map fk -WHERE mapcfg != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_ts_config pk WHERE pk.oid = fk.mapcfg); - ctid | mapcfg -------+-------- -(0 rows) - -SELECT ctid, mapdict -FROM pg_catalog.pg_ts_config_map fk -WHERE mapdict != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_ts_dict pk WHERE pk.oid = fk.mapdict); - ctid | mapdict -------+--------- -(0 rows) - -SELECT ctid, dictnamespace -FROM pg_catalog.pg_ts_dict fk -WHERE dictnamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.dictnamespace); - ctid | dictnamespace -------+--------------- -(0 rows) - -SELECT ctid, dictowner -FROM pg_catalog.pg_ts_dict fk -WHERE dictowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.dictowner); - ctid | dictowner -------+----------- -(0 rows) - -SELECT ctid, dicttemplate -FROM pg_catalog.pg_ts_dict fk -WHERE dicttemplate != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_ts_template pk WHERE pk.oid = fk.dicttemplate); - ctid | dicttemplate -------+-------------- -(0 rows) - -SELECT ctid, prsnamespace -FROM pg_catalog.pg_ts_parser fk -WHERE prsnamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.prsnamespace); - ctid | prsnamespace -------+-------------- -(0 rows) - -SELECT ctid, prsstart -FROM pg_catalog.pg_ts_parser fk -WHERE prsstart != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prsstart); - ctid | prsstart -------+---------- -(0 rows) - -SELECT ctid, prstoken -FROM pg_catalog.pg_ts_parser fk -WHERE prstoken != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prstoken); - ctid | prstoken -------+---------- -(0 rows) - -SELECT ctid, prsend -FROM pg_catalog.pg_ts_parser fk -WHERE prsend != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prsend); - ctid | prsend -------+-------- -(0 rows) - -SELECT ctid, prsheadline -FROM pg_catalog.pg_ts_parser fk -WHERE prsheadline != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prsheadline); - ctid | prsheadline -------+------------- -(0 rows) - -SELECT ctid, prslextype -FROM pg_catalog.pg_ts_parser fk -WHERE prslextype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prslextype); - ctid | prslextype -------+------------ -(0 rows) - -SELECT ctid, tmplnamespace -FROM pg_catalog.pg_ts_template fk -WHERE tmplnamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.tmplnamespace); - ctid | tmplnamespace -------+--------------- -(0 rows) - -SELECT ctid, tmplinit -FROM pg_catalog.pg_ts_template fk -WHERE tmplinit != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.tmplinit); - ctid | tmplinit -------+---------- -(0 rows) - -SELECT ctid, tmpllexize -FROM pg_catalog.pg_ts_template fk -WHERE tmpllexize != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.tmpllexize); - ctid | tmpllexize -------+------------ -(0 rows) - -SELECT ctid, typnamespace -FROM pg_catalog.pg_type fk -WHERE typnamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.typnamespace); - ctid | typnamespace -------+-------------- -(0 rows) - -SELECT ctid, typowner -FROM pg_catalog.pg_type fk -WHERE typowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.typowner); - ctid | typowner -------+---------- -(0 rows) - -SELECT ctid, typrelid -FROM pg_catalog.pg_type fk -WHERE typrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.typrelid); - ctid | typrelid -------+---------- -(0 rows) - -SELECT ctid, typelem -FROM pg_catalog.pg_type fk -WHERE typelem != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.typelem); - ctid | typelem -------+--------- -(0 rows) - -SELECT ctid, typarray -FROM pg_catalog.pg_type fk -WHERE typarray != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.typarray); - ctid | typarray -------+---------- -(0 rows) - -SELECT ctid, typinput -FROM pg_catalog.pg_type fk -WHERE typinput != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typinput); - ctid | typinput -------+---------- -(0 rows) - -SELECT ctid, typoutput -FROM pg_catalog.pg_type fk -WHERE typoutput != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typoutput); - ctid | typoutput -------+----------- -(0 rows) - -SELECT ctid, typreceive -FROM pg_catalog.pg_type fk -WHERE typreceive != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typreceive); - ctid | typreceive -------+------------ -(0 rows) - -SELECT ctid, typsend -FROM pg_catalog.pg_type fk -WHERE typsend != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typsend); - ctid | typsend -------+--------- -(0 rows) - -SELECT ctid, typmodin -FROM pg_catalog.pg_type fk -WHERE typmodin != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typmodin); - ctid | typmodin -------+---------- -(0 rows) - -SELECT ctid, typmodout -FROM pg_catalog.pg_type fk -WHERE typmodout != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typmodout); - ctid | typmodout -------+----------- -(0 rows) - -SELECT ctid, typanalyze -FROM pg_catalog.pg_type fk -WHERE typanalyze != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typanalyze); - ctid | typanalyze -------+------------ -(0 rows) - -SELECT ctid, typbasetype -FROM pg_catalog.pg_type fk -WHERE typbasetype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.typbasetype); - ctid | typbasetype -------+------------- -(0 rows) - -SELECT ctid, typcollation -FROM pg_catalog.pg_type fk -WHERE typcollation != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.typcollation); - ctid | typcollation -------+-------------- -(0 rows) - -SELECT ctid, conpfeqop -FROM (SELECT ctid, unnest(conpfeqop) AS conpfeqop FROM pg_catalog.pg_constraint) fk -WHERE conpfeqop != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.conpfeqop); - ctid | conpfeqop -------+----------- -(0 rows) - -SELECT ctid, conppeqop -FROM (SELECT ctid, unnest(conppeqop) AS conppeqop FROM pg_catalog.pg_constraint) fk -WHERE conppeqop != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.conppeqop); - ctid | conppeqop -------+----------- -(0 rows) - -SELECT ctid, conffeqop -FROM (SELECT ctid, unnest(conffeqop) AS conffeqop FROM pg_catalog.pg_constraint) fk -WHERE conffeqop != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.conffeqop); - ctid | conffeqop -------+----------- -(0 rows) - -SELECT ctid, conexclop -FROM (SELECT ctid, unnest(conexclop) AS conexclop FROM pg_catalog.pg_constraint) fk -WHERE conexclop != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.conexclop); - ctid | conexclop -------+----------- -(0 rows) - -SELECT ctid, indcollation -FROM (SELECT ctid, unnest(indcollation) AS indcollation FROM pg_catalog.pg_index) fk -WHERE indcollation != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.indcollation); - ctid | indcollation -------+-------------- -(0 rows) - -SELECT ctid, indclass -FROM (SELECT ctid, unnest(indclass) AS indclass FROM pg_catalog.pg_index) fk -WHERE indclass != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.indclass); - ctid | indclass -------+---------- -(0 rows) - -SELECT ctid, partclass -FROM (SELECT ctid, unnest(partclass) AS partclass FROM pg_catalog.pg_partitioned_table) fk -WHERE partclass != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.partclass); - ctid | partclass -------+----------- -(0 rows) - -SELECT ctid, partcollation -FROM (SELECT ctid, unnest(partcollation) AS partcollation FROM pg_catalog.pg_partitioned_table) fk -WHERE partcollation != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.partcollation); - ctid | partcollation -------+--------------- -(0 rows) - -SELECT ctid, proargtypes -FROM (SELECT ctid, unnest(proargtypes) AS proargtypes FROM pg_catalog.pg_proc) fk -WHERE proargtypes != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.proargtypes); - ctid | proargtypes -------+------------- -(0 rows) - -SELECT ctid, proallargtypes -FROM (SELECT ctid, unnest(proallargtypes) AS proallargtypes FROM pg_catalog.pg_proc) fk -WHERE proallargtypes != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.proallargtypes); - ctid | proallargtypes -------+---------------- -(0 rows) - +DO $doblock$ +declare + fk record; + nkeys integer; + cmd text; + err record; +begin + for fk in select * from pg_get_catalog_foreign_keys() + loop + raise notice 'checking % % => % %', + fk.fktable, fk.fkcols, fk.pktable, fk.pkcols; + nkeys := array_length(fk.fkcols, 1); + cmd := 'SELECT ctid'; + for i in 1 .. nkeys loop + cmd := cmd || ', ' || quote_ident(fk.fkcols[i]); + end loop; + if fk.is_array then + cmd := cmd || ' FROM (SELECT ctid'; + for i in 1 .. nkeys-1 loop + cmd := cmd || ', ' || quote_ident(fk.fkcols[i]); + end loop; + cmd := cmd || ', unnest(' || quote_ident(fk.fkcols[nkeys]); + cmd := cmd || ') as ' || quote_ident(fk.fkcols[nkeys]); + cmd := cmd || ' FROM ' || fk.fktable::text || ') fk WHERE '; + else + cmd := cmd || ' FROM ' || fk.fktable::text || ' fk WHERE '; + end if; + if fk.is_opt then + for i in 1 .. nkeys loop + cmd := cmd || quote_ident(fk.fkcols[i]) || ' != 0 AND '; + end loop; + end if; + cmd := cmd || 'NOT EXISTS(SELECT 1 FROM ' || fk.pktable::text || ' pk WHERE '; + for i in 1 .. nkeys loop + if i > 1 then cmd := cmd || ' AND '; end if; + cmd := cmd || 'pk.' || quote_ident(fk.pkcols[i]); + cmd := cmd || ' = fk.' || quote_ident(fk.fkcols[i]); + end loop; + cmd := cmd || ')'; + -- raise notice 'cmd = %', cmd; + for err in execute cmd loop + raise warning 'FK VIOLATION IN %(%): %', fk.fktable, fk.fkcols, err; + end loop; + end loop; +end +$doblock$; +NOTICE: checking pg_proc {pronamespace} => pg_namespace {oid} +NOTICE: checking pg_proc {proowner} => pg_authid {oid} +NOTICE: checking pg_proc {prolang} => pg_language {oid} +NOTICE: checking pg_proc {provariadic} => pg_type {oid} +NOTICE: checking pg_proc {prosupport} => pg_proc {oid} +NOTICE: checking pg_proc {prorettype} => pg_type {oid} +NOTICE: checking pg_proc {proargtypes} => pg_type {oid} +NOTICE: checking pg_proc {proallargtypes} => pg_type {oid} +NOTICE: checking pg_proc {protrftypes} => pg_type {oid} +NOTICE: checking pg_type {typnamespace} => pg_namespace {oid} +NOTICE: checking pg_type {typowner} => pg_authid {oid} +NOTICE: checking pg_type {typrelid} => pg_class {oid} +NOTICE: checking pg_type {typsubscript} => pg_proc {oid} +NOTICE: checking pg_type {typelem} => pg_type {oid} +NOTICE: checking pg_type {typarray} => pg_type {oid} +NOTICE: checking pg_type {typinput} => pg_proc {oid} +NOTICE: checking pg_type {typoutput} => pg_proc {oid} +NOTICE: checking pg_type {typreceive} => pg_proc {oid} +NOTICE: checking pg_type {typsend} => pg_proc {oid} +NOTICE: checking pg_type {typmodin} => pg_proc {oid} +NOTICE: checking pg_type {typmodout} => pg_proc {oid} +NOTICE: checking pg_type {typanalyze} => pg_proc {oid} +NOTICE: checking pg_type {typbasetype} => pg_type {oid} +NOTICE: checking pg_type {typcollation} => pg_collation {oid} +NOTICE: checking pg_attribute {attrelid} => pg_class {oid} +NOTICE: checking pg_attribute {atttypid} => pg_type {oid} +NOTICE: checking pg_attribute {attcollation} => pg_collation {oid} +NOTICE: checking pg_class {relnamespace} => pg_namespace {oid} +NOTICE: checking pg_class {reltype} => pg_type {oid} +NOTICE: checking pg_class {reloftype} => pg_type {oid} +NOTICE: checking pg_class {relowner} => pg_authid {oid} +NOTICE: checking pg_class {relam} => pg_am {oid} +NOTICE: checking pg_class {reltablespace} => pg_tablespace {oid} +NOTICE: checking pg_class {reltoastrelid} => pg_class {oid} +NOTICE: checking pg_class {relrewrite} => pg_class {oid} +NOTICE: checking pg_attrdef {adrelid} => pg_class {oid} +NOTICE: checking pg_attrdef {adrelid,adnum} => pg_attribute {attrelid,attnum} +NOTICE: checking pg_constraint {connamespace} => pg_namespace {oid} +NOTICE: checking pg_constraint {conrelid} => pg_class {oid} +NOTICE: checking pg_constraint {contypid} => pg_type {oid} +NOTICE: checking pg_constraint {conindid} => pg_class {oid} +NOTICE: checking pg_constraint {conparentid} => pg_constraint {oid} +NOTICE: checking pg_constraint {confrelid} => pg_class {oid} +NOTICE: checking pg_constraint {conpfeqop} => pg_operator {oid} +NOTICE: checking pg_constraint {conppeqop} => pg_operator {oid} +NOTICE: checking pg_constraint {conffeqop} => pg_operator {oid} +NOTICE: checking pg_constraint {conexclop} => pg_operator {oid} +NOTICE: checking pg_constraint {conrelid,conkey} => pg_attribute {attrelid,attnum} +NOTICE: checking pg_constraint {confrelid,confkey} => pg_attribute {attrelid,attnum} +NOTICE: checking pg_inherits {inhrelid} => pg_class {oid} +NOTICE: checking pg_inherits {inhparent} => pg_class {oid} +NOTICE: checking pg_index {indexrelid} => pg_class {oid} +NOTICE: checking pg_index {indrelid} => pg_class {oid} +NOTICE: checking pg_index {indcollation} => pg_collation {oid} +NOTICE: checking pg_index {indclass} => pg_opclass {oid} +NOTICE: checking pg_index {indrelid,indkey} => pg_attribute {attrelid,attnum} +NOTICE: checking pg_operator {oprnamespace} => pg_namespace {oid} +NOTICE: checking pg_operator {oprowner} => pg_authid {oid} +NOTICE: checking pg_operator {oprleft} => pg_type {oid} +NOTICE: checking pg_operator {oprright} => pg_type {oid} +NOTICE: checking pg_operator {oprresult} => pg_type {oid} +NOTICE: checking pg_operator {oprcom} => pg_operator {oid} +NOTICE: checking pg_operator {oprnegate} => pg_operator {oid} +NOTICE: checking pg_operator {oprcode} => pg_proc {oid} +NOTICE: checking pg_operator {oprrest} => pg_proc {oid} +NOTICE: checking pg_operator {oprjoin} => pg_proc {oid} +NOTICE: checking pg_opfamily {opfmethod} => pg_am {oid} +NOTICE: checking pg_opfamily {opfnamespace} => pg_namespace {oid} +NOTICE: checking pg_opfamily {opfowner} => pg_authid {oid} +NOTICE: checking pg_opclass {opcmethod} => pg_am {oid} +NOTICE: checking pg_opclass {opcnamespace} => pg_namespace {oid} +NOTICE: checking pg_opclass {opcowner} => pg_authid {oid} +NOTICE: checking pg_opclass {opcfamily} => pg_opfamily {oid} +NOTICE: checking pg_opclass {opcintype} => pg_type {oid} +NOTICE: checking pg_opclass {opckeytype} => pg_type {oid} +NOTICE: checking pg_am {amhandler} => pg_proc {oid} +NOTICE: checking pg_amop {amopfamily} => pg_opfamily {oid} +NOTICE: checking pg_amop {amoplefttype} => pg_type {oid} +NOTICE: checking pg_amop {amoprighttype} => pg_type {oid} +NOTICE: checking pg_amop {amopopr} => pg_operator {oid} +NOTICE: checking pg_amop {amopmethod} => pg_am {oid} +NOTICE: checking pg_amop {amopsortfamily} => pg_opfamily {oid} +NOTICE: checking pg_amproc {amprocfamily} => pg_opfamily {oid} +NOTICE: checking pg_amproc {amproclefttype} => pg_type {oid} +NOTICE: checking pg_amproc {amprocrighttype} => pg_type {oid} +NOTICE: checking pg_amproc {amproc} => pg_proc {oid} +NOTICE: checking pg_language {lanowner} => pg_authid {oid} +NOTICE: checking pg_language {lanplcallfoid} => pg_proc {oid} +NOTICE: checking pg_language {laninline} => pg_proc {oid} +NOTICE: checking pg_language {lanvalidator} => pg_proc {oid} +NOTICE: checking pg_largeobject_metadata {lomowner} => pg_authid {oid} +NOTICE: checking pg_largeobject {loid} => pg_largeobject_metadata {oid} +NOTICE: checking pg_aggregate {aggfnoid} => pg_proc {oid} +NOTICE: checking pg_aggregate {aggtransfn} => pg_proc {oid} +NOTICE: checking pg_aggregate {aggfinalfn} => pg_proc {oid} +NOTICE: checking pg_aggregate {aggcombinefn} => pg_proc {oid} +NOTICE: checking pg_aggregate {aggserialfn} => pg_proc {oid} +NOTICE: checking pg_aggregate {aggdeserialfn} => pg_proc {oid} +NOTICE: checking pg_aggregate {aggmtransfn} => pg_proc {oid} +NOTICE: checking pg_aggregate {aggminvtransfn} => pg_proc {oid} +NOTICE: checking pg_aggregate {aggmfinalfn} => pg_proc {oid} +NOTICE: checking pg_aggregate {aggsortop} => pg_operator {oid} +NOTICE: checking pg_aggregate {aggtranstype} => pg_type {oid} +NOTICE: checking pg_aggregate {aggmtranstype} => pg_type {oid} +NOTICE: checking pg_statistic_ext {stxrelid} => pg_class {oid} +NOTICE: checking pg_statistic_ext {stxnamespace} => pg_namespace {oid} +NOTICE: checking pg_statistic_ext {stxowner} => pg_authid {oid} +NOTICE: checking pg_statistic_ext {stxrelid,stxkeys} => pg_attribute {attrelid,attnum} +NOTICE: checking pg_statistic_ext_data {stxoid} => pg_statistic_ext {oid} +NOTICE: checking pg_statistic {starelid} => pg_class {oid} +NOTICE: checking pg_statistic {staop1} => pg_operator {oid} +NOTICE: checking pg_statistic {staop2} => pg_operator {oid} +NOTICE: checking pg_statistic {staop3} => pg_operator {oid} +NOTICE: checking pg_statistic {staop4} => pg_operator {oid} +NOTICE: checking pg_statistic {staop5} => pg_operator {oid} +NOTICE: checking pg_statistic {stacoll1} => pg_collation {oid} +NOTICE: checking pg_statistic {stacoll2} => pg_collation {oid} +NOTICE: checking pg_statistic {stacoll3} => pg_collation {oid} +NOTICE: checking pg_statistic {stacoll4} => pg_collation {oid} +NOTICE: checking pg_statistic {stacoll5} => pg_collation {oid} +NOTICE: checking pg_statistic {starelid,staattnum} => pg_attribute {attrelid,attnum} +NOTICE: checking pg_rewrite {ev_class} => pg_class {oid} +NOTICE: checking pg_trigger {tgrelid} => pg_class {oid} +NOTICE: checking pg_trigger {tgparentid} => pg_trigger {oid} +NOTICE: checking pg_trigger {tgfoid} => pg_proc {oid} +NOTICE: checking pg_trigger {tgconstrrelid} => pg_class {oid} +NOTICE: checking pg_trigger {tgconstrindid} => pg_class {oid} +NOTICE: checking pg_trigger {tgconstraint} => pg_constraint {oid} +NOTICE: checking pg_trigger {tgrelid,tgattr} => pg_attribute {attrelid,attnum} +NOTICE: checking pg_event_trigger {evtowner} => pg_authid {oid} +NOTICE: checking pg_event_trigger {evtfoid} => pg_proc {oid} +NOTICE: checking pg_description {classoid} => pg_class {oid} +NOTICE: checking pg_cast {castsource} => pg_type {oid} +NOTICE: checking pg_cast {casttarget} => pg_type {oid} +NOTICE: checking pg_cast {castfunc} => pg_proc {oid} +NOTICE: checking pg_enum {enumtypid} => pg_type {oid} +NOTICE: checking pg_namespace {nspowner} => pg_authid {oid} +NOTICE: checking pg_conversion {connamespace} => pg_namespace {oid} +NOTICE: checking pg_conversion {conowner} => pg_authid {oid} +NOTICE: checking pg_conversion {conproc} => pg_proc {oid} +NOTICE: checking pg_depend {classid} => pg_class {oid} +NOTICE: checking pg_depend {refclassid} => pg_class {oid} +NOTICE: checking pg_database {datdba} => pg_authid {oid} +NOTICE: checking pg_database {dattablespace} => pg_tablespace {oid} +NOTICE: checking pg_db_role_setting {setdatabase} => pg_database {oid} +NOTICE: checking pg_db_role_setting {setrole} => pg_authid {oid} +NOTICE: checking pg_tablespace {spcowner} => pg_authid {oid} +NOTICE: checking pg_auth_members {roleid} => pg_authid {oid} +NOTICE: checking pg_auth_members {member} => pg_authid {oid} +NOTICE: checking pg_auth_members {grantor} => pg_authid {oid} +NOTICE: checking pg_shdepend {dbid} => pg_database {oid} +NOTICE: checking pg_shdepend {classid} => pg_class {oid} +NOTICE: checking pg_shdepend {refclassid} => pg_class {oid} +NOTICE: checking pg_shdescription {classoid} => pg_class {oid} +NOTICE: checking pg_ts_config {cfgnamespace} => pg_namespace {oid} +NOTICE: checking pg_ts_config {cfgowner} => pg_authid {oid} +NOTICE: checking pg_ts_config {cfgparser} => pg_ts_parser {oid} +NOTICE: checking pg_ts_config_map {mapcfg} => pg_ts_config {oid} +NOTICE: checking pg_ts_config_map {mapdict} => pg_ts_dict {oid} +NOTICE: checking pg_ts_dict {dictnamespace} => pg_namespace {oid} +NOTICE: checking pg_ts_dict {dictowner} => pg_authid {oid} +NOTICE: checking pg_ts_dict {dicttemplate} => pg_ts_template {oid} +NOTICE: checking pg_ts_parser {prsnamespace} => pg_namespace {oid} +NOTICE: checking pg_ts_parser {prsstart} => pg_proc {oid} +NOTICE: checking pg_ts_parser {prstoken} => pg_proc {oid} +NOTICE: checking pg_ts_parser {prsend} => pg_proc {oid} +NOTICE: checking pg_ts_parser {prsheadline} => pg_proc {oid} +NOTICE: checking pg_ts_parser {prslextype} => pg_proc {oid} +NOTICE: checking pg_ts_template {tmplnamespace} => pg_namespace {oid} +NOTICE: checking pg_ts_template {tmplinit} => pg_proc {oid} +NOTICE: checking pg_ts_template {tmpllexize} => pg_proc {oid} +NOTICE: checking pg_extension {extowner} => pg_authid {oid} +NOTICE: checking pg_extension {extnamespace} => pg_namespace {oid} +NOTICE: checking pg_extension {extconfig} => pg_class {oid} +NOTICE: checking pg_foreign_data_wrapper {fdwowner} => pg_authid {oid} +NOTICE: checking pg_foreign_data_wrapper {fdwhandler} => pg_proc {oid} +NOTICE: checking pg_foreign_data_wrapper {fdwvalidator} => pg_proc {oid} +NOTICE: checking pg_foreign_server {srvowner} => pg_authid {oid} +NOTICE: checking pg_foreign_server {srvfdw} => pg_foreign_data_wrapper {oid} +NOTICE: checking pg_user_mapping {umuser} => pg_authid {oid} +NOTICE: checking pg_user_mapping {umserver} => pg_foreign_server {oid} +NOTICE: checking pg_foreign_table {ftrelid} => pg_class {oid} +NOTICE: checking pg_foreign_table {ftserver} => pg_foreign_server {oid} +NOTICE: checking pg_policy {polrelid} => pg_class {oid} +NOTICE: checking pg_policy {polroles} => pg_authid {oid} +NOTICE: checking pg_default_acl {defaclrole} => pg_authid {oid} +NOTICE: checking pg_default_acl {defaclnamespace} => pg_namespace {oid} +NOTICE: checking pg_init_privs {classoid} => pg_class {oid} +NOTICE: checking pg_seclabel {classoid} => pg_class {oid} +NOTICE: checking pg_shseclabel {classoid} => pg_class {oid} +NOTICE: checking pg_collation {collnamespace} => pg_namespace {oid} +NOTICE: checking pg_collation {collowner} => pg_authid {oid} +NOTICE: checking pg_partitioned_table {partrelid} => pg_class {oid} +NOTICE: checking pg_partitioned_table {partdefid} => pg_class {oid} +NOTICE: checking pg_partitioned_table {partclass} => pg_opclass {oid} +NOTICE: checking pg_partitioned_table {partcollation} => pg_collation {oid} +NOTICE: checking pg_partitioned_table {partrelid,partattrs} => pg_attribute {attrelid,attnum} +NOTICE: checking pg_range {rngtypid} => pg_type {oid} +NOTICE: checking pg_range {rngsubtype} => pg_type {oid} +NOTICE: checking pg_range {rngmultitypid} => pg_type {oid} +NOTICE: checking pg_range {rngcollation} => pg_collation {oid} +NOTICE: checking pg_range {rngsubopc} => pg_opclass {oid} +NOTICE: checking pg_range {rngcanonical} => pg_proc {oid} +NOTICE: checking pg_range {rngsubdiff} => pg_proc {oid} +NOTICE: checking pg_transform {trftype} => pg_type {oid} +NOTICE: checking pg_transform {trflang} => pg_language {oid} +NOTICE: checking pg_transform {trffromsql} => pg_proc {oid} +NOTICE: checking pg_transform {trftosql} => pg_proc {oid} +NOTICE: checking pg_sequence {seqrelid} => pg_class {oid} +NOTICE: checking pg_sequence {seqtypid} => pg_type {oid} +NOTICE: checking pg_publication {pubowner} => pg_authid {oid} +NOTICE: checking pg_publication_rel {prpubid} => pg_publication {oid} +NOTICE: checking pg_publication_rel {prrelid} => pg_class {oid} +NOTICE: checking pg_subscription {subdbid} => pg_database {oid} +NOTICE: checking pg_subscription {subowner} => pg_authid {oid} +NOTICE: checking pg_subscription_rel {srsubid} => pg_subscription {oid} +NOTICE: checking pg_subscription_rel {srrelid} => pg_class {oid} diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index e0e1ef71dd790..12bb67e491188 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -29,7 +29,7 @@ test: strings numerology point lseg line box path polygon circle date time timet # geometry depends on point, lseg, box, path, polygon and circle # horology depends on interval, timetz, timestamp, timestamptz # ---------- -test: geometry horology regex oidjoins type_sanity opr_sanity misc_sanity comments expressions unicode xid +test: geometry horology regex type_sanity opr_sanity misc_sanity comments expressions unicode xid # ---------- # These four each depend on the previous one @@ -117,7 +117,8 @@ test: plancache limit plpgsql copy2 temp domain rangefuncs prepare conversion tr test: partition_join partition_prune reloptions hash_part indexing partition_aggregate partition_info tuplesort explain # event triggers cannot run concurrently with any test that runs DDL -test: event_trigger +# oidjoins is read-only, though, and should run late for best coverage +test: event_trigger oidjoins # this test also uses event triggers, so likewise run it by itself test: fast_default diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule index 081fce32e75b6..59b416fd80cb4 100644 --- a/src/test/regress/serial_schedule +++ b/src/test/regress/serial_schedule @@ -45,7 +45,6 @@ test: tstypes test: geometry test: horology test: regex -test: oidjoins test: type_sanity test: opr_sanity test: misc_sanity @@ -201,5 +200,6 @@ test: partition_info test: tuplesort test: explain test: event_trigger +test: oidjoins test: fast_default test: stats diff --git a/src/test/regress/sql/oidjoins.sql b/src/test/regress/sql/oidjoins.sql index f6d2d3c68c36f..8b22e6d10c5ec 100644 --- a/src/test/regress/sql/oidjoins.sql +++ b/src/test/regress/sql/oidjoins.sql @@ -1,727 +1,49 @@ -- --- This is created by pgsql/src/tools/findoidjoins/make_oidjoins_check +-- Verify system catalog foreign key relationships -- -SELECT ctid, aggfnoid -FROM pg_catalog.pg_aggregate fk -WHERE aggfnoid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggfnoid); -SELECT ctid, aggtransfn -FROM pg_catalog.pg_aggregate fk -WHERE aggtransfn != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggtransfn); -SELECT ctid, aggfinalfn -FROM pg_catalog.pg_aggregate fk -WHERE aggfinalfn != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggfinalfn); -SELECT ctid, aggcombinefn -FROM pg_catalog.pg_aggregate fk -WHERE aggcombinefn != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggcombinefn); -SELECT ctid, aggserialfn -FROM pg_catalog.pg_aggregate fk -WHERE aggserialfn != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggserialfn); -SELECT ctid, aggdeserialfn -FROM pg_catalog.pg_aggregate fk -WHERE aggdeserialfn != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggdeserialfn); -SELECT ctid, aggmtransfn -FROM pg_catalog.pg_aggregate fk -WHERE aggmtransfn != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggmtransfn); -SELECT ctid, aggminvtransfn -FROM pg_catalog.pg_aggregate fk -WHERE aggminvtransfn != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggminvtransfn); -SELECT ctid, aggmfinalfn -FROM pg_catalog.pg_aggregate fk -WHERE aggmfinalfn != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggmfinalfn); -SELECT ctid, aggsortop -FROM pg_catalog.pg_aggregate fk -WHERE aggsortop != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.aggsortop); -SELECT ctid, aggtranstype -FROM pg_catalog.pg_aggregate fk -WHERE aggtranstype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggtranstype); -SELECT ctid, aggmtranstype -FROM pg_catalog.pg_aggregate fk -WHERE aggmtranstype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggmtranstype); -SELECT ctid, amhandler -FROM pg_catalog.pg_am fk -WHERE amhandler != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amhandler); -SELECT ctid, amopfamily -FROM pg_catalog.pg_amop fk -WHERE amopfamily != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amopfamily); -SELECT ctid, amoplefttype -FROM pg_catalog.pg_amop fk -WHERE amoplefttype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amoplefttype); -SELECT ctid, amoprighttype -FROM pg_catalog.pg_amop fk -WHERE amoprighttype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amoprighttype); -SELECT ctid, amopopr -FROM pg_catalog.pg_amop fk -WHERE amopopr != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.amopopr); -SELECT ctid, amopmethod -FROM pg_catalog.pg_amop fk -WHERE amopmethod != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.amopmethod); -SELECT ctid, amopsortfamily -FROM pg_catalog.pg_amop fk -WHERE amopsortfamily != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amopsortfamily); -SELECT ctid, amprocfamily -FROM pg_catalog.pg_amproc fk -WHERE amprocfamily != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amprocfamily); -SELECT ctid, amproclefttype -FROM pg_catalog.pg_amproc fk -WHERE amproclefttype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amproclefttype); -SELECT ctid, amprocrighttype -FROM pg_catalog.pg_amproc fk -WHERE amprocrighttype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amprocrighttype); -SELECT ctid, amproc -FROM pg_catalog.pg_amproc fk -WHERE amproc != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amproc); -SELECT ctid, adrelid -FROM pg_catalog.pg_attrdef fk -WHERE adrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.adrelid); -SELECT ctid, attrelid -FROM pg_catalog.pg_attribute fk -WHERE attrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.attrelid); -SELECT ctid, atttypid -FROM pg_catalog.pg_attribute fk -WHERE atttypid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.atttypid); -SELECT ctid, attcollation -FROM pg_catalog.pg_attribute fk -WHERE attcollation != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.attcollation); -SELECT ctid, roleid -FROM pg_catalog.pg_auth_members fk -WHERE roleid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.roleid); -SELECT ctid, member -FROM pg_catalog.pg_auth_members fk -WHERE member != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.member); -SELECT ctid, grantor -FROM pg_catalog.pg_auth_members fk -WHERE grantor != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.grantor); -SELECT ctid, castsource -FROM pg_catalog.pg_cast fk -WHERE castsource != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.castsource); -SELECT ctid, casttarget -FROM pg_catalog.pg_cast fk -WHERE casttarget != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.casttarget); -SELECT ctid, castfunc -FROM pg_catalog.pg_cast fk -WHERE castfunc != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.castfunc); -SELECT ctid, relnamespace -FROM pg_catalog.pg_class fk -WHERE relnamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.relnamespace); -SELECT ctid, reltype -FROM pg_catalog.pg_class fk -WHERE reltype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.reltype); -SELECT ctid, reloftype -FROM pg_catalog.pg_class fk -WHERE reloftype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.reloftype); -SELECT ctid, relowner -FROM pg_catalog.pg_class fk -WHERE relowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.relowner); -SELECT ctid, relam -FROM pg_catalog.pg_class fk -WHERE relam != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.relam); -SELECT ctid, reltablespace -FROM pg_catalog.pg_class fk -WHERE reltablespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_tablespace pk WHERE pk.oid = fk.reltablespace); -SELECT ctid, reltoastrelid -FROM pg_catalog.pg_class fk -WHERE reltoastrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.reltoastrelid); -SELECT ctid, collnamespace -FROM pg_catalog.pg_collation fk -WHERE collnamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.collnamespace); -SELECT ctid, collowner -FROM pg_catalog.pg_collation fk -WHERE collowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.collowner); -SELECT ctid, connamespace -FROM pg_catalog.pg_constraint fk -WHERE connamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.connamespace); -SELECT ctid, conrelid -FROM pg_catalog.pg_constraint fk -WHERE conrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.conrelid); -SELECT ctid, contypid -FROM pg_catalog.pg_constraint fk -WHERE contypid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.contypid); -SELECT ctid, conindid -FROM pg_catalog.pg_constraint fk -WHERE conindid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.conindid); -SELECT ctid, conparentid -FROM pg_catalog.pg_constraint fk -WHERE conparentid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_constraint pk WHERE pk.oid = fk.conparentid); -SELECT ctid, confrelid -FROM pg_catalog.pg_constraint fk -WHERE confrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.confrelid); -SELECT ctid, connamespace -FROM pg_catalog.pg_conversion fk -WHERE connamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.connamespace); -SELECT ctid, conowner -FROM pg_catalog.pg_conversion fk -WHERE conowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.conowner); -SELECT ctid, conproc -FROM pg_catalog.pg_conversion fk -WHERE conproc != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.conproc); -SELECT ctid, datdba -FROM pg_catalog.pg_database fk -WHERE datdba != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.datdba); -SELECT ctid, dattablespace -FROM pg_catalog.pg_database fk -WHERE dattablespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_tablespace pk WHERE pk.oid = fk.dattablespace); -SELECT ctid, setdatabase -FROM pg_catalog.pg_db_role_setting fk -WHERE setdatabase != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_database pk WHERE pk.oid = fk.setdatabase); -SELECT ctid, classid -FROM pg_catalog.pg_depend fk -WHERE classid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classid); -SELECT ctid, refclassid -FROM pg_catalog.pg_depend fk -WHERE refclassid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.refclassid); -SELECT ctid, classoid -FROM pg_catalog.pg_description fk -WHERE classoid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classoid); -SELECT ctid, enumtypid -FROM pg_catalog.pg_enum fk -WHERE enumtypid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.enumtypid); -SELECT ctid, extowner -FROM pg_catalog.pg_extension fk -WHERE extowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.extowner); -SELECT ctid, extnamespace -FROM pg_catalog.pg_extension fk -WHERE extnamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.extnamespace); -SELECT ctid, fdwowner -FROM pg_catalog.pg_foreign_data_wrapper fk -WHERE fdwowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.fdwowner); -SELECT ctid, srvowner -FROM pg_catalog.pg_foreign_server fk -WHERE srvowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.srvowner); -SELECT ctid, srvfdw -FROM pg_catalog.pg_foreign_server fk -WHERE srvfdw != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_foreign_data_wrapper pk WHERE pk.oid = fk.srvfdw); -SELECT ctid, indexrelid -FROM pg_catalog.pg_index fk -WHERE indexrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.indexrelid); -SELECT ctid, indrelid -FROM pg_catalog.pg_index fk -WHERE indrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.indrelid); -SELECT ctid, inhrelid -FROM pg_catalog.pg_inherits fk -WHERE inhrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.inhrelid); -SELECT ctid, inhparent -FROM pg_catalog.pg_inherits fk -WHERE inhparent != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.inhparent); -SELECT ctid, classoid -FROM pg_catalog.pg_init_privs fk -WHERE classoid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classoid); -SELECT ctid, lanowner -FROM pg_catalog.pg_language fk -WHERE lanowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.lanowner); -SELECT ctid, lanplcallfoid -FROM pg_catalog.pg_language fk -WHERE lanplcallfoid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.lanplcallfoid); -SELECT ctid, laninline -FROM pg_catalog.pg_language fk -WHERE laninline != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.laninline); -SELECT ctid, lanvalidator -FROM pg_catalog.pg_language fk -WHERE lanvalidator != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.lanvalidator); -SELECT ctid, loid -FROM pg_catalog.pg_largeobject fk -WHERE loid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_largeobject_metadata pk WHERE pk.oid = fk.loid); -SELECT ctid, lomowner -FROM pg_catalog.pg_largeobject_metadata fk -WHERE lomowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.lomowner); -SELECT ctid, nspowner -FROM pg_catalog.pg_namespace fk -WHERE nspowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.nspowner); -SELECT ctid, opcmethod -FROM pg_catalog.pg_opclass fk -WHERE opcmethod != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.opcmethod); -SELECT ctid, opcnamespace -FROM pg_catalog.pg_opclass fk -WHERE opcnamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.opcnamespace); -SELECT ctid, opcowner -FROM pg_catalog.pg_opclass fk -WHERE opcowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.opcowner); -SELECT ctid, opcfamily -FROM pg_catalog.pg_opclass fk -WHERE opcfamily != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.opcfamily); -SELECT ctid, opcintype -FROM pg_catalog.pg_opclass fk -WHERE opcintype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.opcintype); -SELECT ctid, opckeytype -FROM pg_catalog.pg_opclass fk -WHERE opckeytype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.opckeytype); -SELECT ctid, oprnamespace -FROM pg_catalog.pg_operator fk -WHERE oprnamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.oprnamespace); -SELECT ctid, oprowner -FROM pg_catalog.pg_operator fk -WHERE oprowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.oprowner); -SELECT ctid, oprleft -FROM pg_catalog.pg_operator fk -WHERE oprleft != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.oprleft); -SELECT ctid, oprright -FROM pg_catalog.pg_operator fk -WHERE oprright != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.oprright); -SELECT ctid, oprresult -FROM pg_catalog.pg_operator fk -WHERE oprresult != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.oprresult); -SELECT ctid, oprcom -FROM pg_catalog.pg_operator fk -WHERE oprcom != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.oprcom); -SELECT ctid, oprnegate -FROM pg_catalog.pg_operator fk -WHERE oprnegate != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.oprnegate); -SELECT ctid, oprcode -FROM pg_catalog.pg_operator fk -WHERE oprcode != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.oprcode); -SELECT ctid, oprrest -FROM pg_catalog.pg_operator fk -WHERE oprrest != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.oprrest); -SELECT ctid, oprjoin -FROM pg_catalog.pg_operator fk -WHERE oprjoin != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.oprjoin); -SELECT ctid, opfmethod -FROM pg_catalog.pg_opfamily fk -WHERE opfmethod != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.opfmethod); -SELECT ctid, opfnamespace -FROM pg_catalog.pg_opfamily fk -WHERE opfnamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.opfnamespace); -SELECT ctid, opfowner -FROM pg_catalog.pg_opfamily fk -WHERE opfowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.opfowner); -SELECT ctid, partrelid -FROM pg_catalog.pg_partitioned_table fk -WHERE partrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.partrelid); -SELECT ctid, partdefid -FROM pg_catalog.pg_partitioned_table fk -WHERE partdefid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.partdefid); -SELECT ctid, polrelid -FROM pg_catalog.pg_policy fk -WHERE polrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.polrelid); -SELECT ctid, pronamespace -FROM pg_catalog.pg_proc fk -WHERE pronamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.pronamespace); -SELECT ctid, proowner -FROM pg_catalog.pg_proc fk -WHERE proowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.proowner); -SELECT ctid, prolang -FROM pg_catalog.pg_proc fk -WHERE prolang != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_language pk WHERE pk.oid = fk.prolang); -SELECT ctid, provariadic -FROM pg_catalog.pg_proc fk -WHERE provariadic != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.provariadic); -SELECT ctid, prosupport -FROM pg_catalog.pg_proc fk -WHERE prosupport != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prosupport); -SELECT ctid, prorettype -FROM pg_catalog.pg_proc fk -WHERE prorettype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.prorettype); -SELECT ctid, rngtypid -FROM pg_catalog.pg_range fk -WHERE rngtypid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.rngtypid); -SELECT ctid, rngsubtype -FROM pg_catalog.pg_range fk -WHERE rngsubtype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.rngsubtype); -SELECT ctid, rngcollation -FROM pg_catalog.pg_range fk -WHERE rngcollation != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.rngcollation); -SELECT ctid, rngsubopc -FROM pg_catalog.pg_range fk -WHERE rngsubopc != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.rngsubopc); -SELECT ctid, rngcanonical -FROM pg_catalog.pg_range fk -WHERE rngcanonical != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.rngcanonical); -SELECT ctid, rngsubdiff -FROM pg_catalog.pg_range fk -WHERE rngsubdiff != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.rngsubdiff); -SELECT ctid, ev_class -FROM pg_catalog.pg_rewrite fk -WHERE ev_class != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.ev_class); -SELECT ctid, seqrelid -FROM pg_catalog.pg_sequence fk -WHERE seqrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.seqrelid); -SELECT ctid, seqtypid -FROM pg_catalog.pg_sequence fk -WHERE seqtypid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.seqtypid); -SELECT ctid, refclassid -FROM pg_catalog.pg_shdepend fk -WHERE refclassid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.refclassid); -SELECT ctid, classoid -FROM pg_catalog.pg_shdescription fk -WHERE classoid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classoid); -SELECT ctid, starelid -FROM pg_catalog.pg_statistic fk -WHERE starelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.starelid); -SELECT ctid, staop1 -FROM pg_catalog.pg_statistic fk -WHERE staop1 != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop1); -SELECT ctid, staop2 -FROM pg_catalog.pg_statistic fk -WHERE staop2 != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop2); -SELECT ctid, staop3 -FROM pg_catalog.pg_statistic fk -WHERE staop3 != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop3); -SELECT ctid, staop4 -FROM pg_catalog.pg_statistic fk -WHERE staop4 != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop4); -SELECT ctid, staop5 -FROM pg_catalog.pg_statistic fk -WHERE staop5 != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop5); -SELECT ctid, stacoll1 -FROM pg_catalog.pg_statistic fk -WHERE stacoll1 != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll1); -SELECT ctid, stacoll2 -FROM pg_catalog.pg_statistic fk -WHERE stacoll2 != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll2); -SELECT ctid, stacoll3 -FROM pg_catalog.pg_statistic fk -WHERE stacoll3 != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll3); -SELECT ctid, stacoll4 -FROM pg_catalog.pg_statistic fk -WHERE stacoll4 != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll4); -SELECT ctid, stacoll5 -FROM pg_catalog.pg_statistic fk -WHERE stacoll5 != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll5); -SELECT ctid, stxrelid -FROM pg_catalog.pg_statistic_ext fk -WHERE stxrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.stxrelid); -SELECT ctid, stxnamespace -FROM pg_catalog.pg_statistic_ext fk -WHERE stxnamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.stxnamespace); -SELECT ctid, stxowner -FROM pg_catalog.pg_statistic_ext fk -WHERE stxowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.stxowner); -SELECT ctid, stxoid -FROM pg_catalog.pg_statistic_ext_data fk -WHERE stxoid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_statistic_ext pk WHERE pk.oid = fk.stxoid); -SELECT ctid, spcowner -FROM pg_catalog.pg_tablespace fk -WHERE spcowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.spcowner); -SELECT ctid, trftype -FROM pg_catalog.pg_transform fk -WHERE trftype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.trftype); -SELECT ctid, trflang -FROM pg_catalog.pg_transform fk -WHERE trflang != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_language pk WHERE pk.oid = fk.trflang); -SELECT ctid, trffromsql -FROM pg_catalog.pg_transform fk -WHERE trffromsql != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.trffromsql); -SELECT ctid, trftosql -FROM pg_catalog.pg_transform fk -WHERE trftosql != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.trftosql); -SELECT ctid, tgrelid -FROM pg_catalog.pg_trigger fk -WHERE tgrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.tgrelid); -SELECT ctid, tgparentid -FROM pg_catalog.pg_trigger fk -WHERE tgparentid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_trigger pk WHERE pk.oid = fk.tgparentid); -SELECT ctid, tgfoid -FROM pg_catalog.pg_trigger fk -WHERE tgfoid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.tgfoid); -SELECT ctid, tgconstrrelid -FROM pg_catalog.pg_trigger fk -WHERE tgconstrrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.tgconstrrelid); -SELECT ctid, tgconstrindid -FROM pg_catalog.pg_trigger fk -WHERE tgconstrindid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.tgconstrindid); -SELECT ctid, tgconstraint -FROM pg_catalog.pg_trigger fk -WHERE tgconstraint != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_constraint pk WHERE pk.oid = fk.tgconstraint); -SELECT ctid, cfgnamespace -FROM pg_catalog.pg_ts_config fk -WHERE cfgnamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.cfgnamespace); -SELECT ctid, cfgowner -FROM pg_catalog.pg_ts_config fk -WHERE cfgowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.cfgowner); -SELECT ctid, cfgparser -FROM pg_catalog.pg_ts_config fk -WHERE cfgparser != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_ts_parser pk WHERE pk.oid = fk.cfgparser); -SELECT ctid, mapcfg -FROM pg_catalog.pg_ts_config_map fk -WHERE mapcfg != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_ts_config pk WHERE pk.oid = fk.mapcfg); -SELECT ctid, mapdict -FROM pg_catalog.pg_ts_config_map fk -WHERE mapdict != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_ts_dict pk WHERE pk.oid = fk.mapdict); -SELECT ctid, dictnamespace -FROM pg_catalog.pg_ts_dict fk -WHERE dictnamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.dictnamespace); -SELECT ctid, dictowner -FROM pg_catalog.pg_ts_dict fk -WHERE dictowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.dictowner); -SELECT ctid, dicttemplate -FROM pg_catalog.pg_ts_dict fk -WHERE dicttemplate != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_ts_template pk WHERE pk.oid = fk.dicttemplate); -SELECT ctid, prsnamespace -FROM pg_catalog.pg_ts_parser fk -WHERE prsnamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.prsnamespace); -SELECT ctid, prsstart -FROM pg_catalog.pg_ts_parser fk -WHERE prsstart != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prsstart); -SELECT ctid, prstoken -FROM pg_catalog.pg_ts_parser fk -WHERE prstoken != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prstoken); -SELECT ctid, prsend -FROM pg_catalog.pg_ts_parser fk -WHERE prsend != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prsend); -SELECT ctid, prsheadline -FROM pg_catalog.pg_ts_parser fk -WHERE prsheadline != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prsheadline); -SELECT ctid, prslextype -FROM pg_catalog.pg_ts_parser fk -WHERE prslextype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prslextype); -SELECT ctid, tmplnamespace -FROM pg_catalog.pg_ts_template fk -WHERE tmplnamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.tmplnamespace); -SELECT ctid, tmplinit -FROM pg_catalog.pg_ts_template fk -WHERE tmplinit != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.tmplinit); -SELECT ctid, tmpllexize -FROM pg_catalog.pg_ts_template fk -WHERE tmpllexize != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.tmpllexize); -SELECT ctid, typnamespace -FROM pg_catalog.pg_type fk -WHERE typnamespace != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.typnamespace); -SELECT ctid, typowner -FROM pg_catalog.pg_type fk -WHERE typowner != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.typowner); -SELECT ctid, typrelid -FROM pg_catalog.pg_type fk -WHERE typrelid != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.typrelid); -SELECT ctid, typelem -FROM pg_catalog.pg_type fk -WHERE typelem != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.typelem); -SELECT ctid, typarray -FROM pg_catalog.pg_type fk -WHERE typarray != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.typarray); -SELECT ctid, typinput -FROM pg_catalog.pg_type fk -WHERE typinput != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typinput); -SELECT ctid, typoutput -FROM pg_catalog.pg_type fk -WHERE typoutput != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typoutput); -SELECT ctid, typreceive -FROM pg_catalog.pg_type fk -WHERE typreceive != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typreceive); -SELECT ctid, typsend -FROM pg_catalog.pg_type fk -WHERE typsend != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typsend); -SELECT ctid, typmodin -FROM pg_catalog.pg_type fk -WHERE typmodin != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typmodin); -SELECT ctid, typmodout -FROM pg_catalog.pg_type fk -WHERE typmodout != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typmodout); -SELECT ctid, typanalyze -FROM pg_catalog.pg_type fk -WHERE typanalyze != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typanalyze); -SELECT ctid, typbasetype -FROM pg_catalog.pg_type fk -WHERE typbasetype != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.typbasetype); -SELECT ctid, typcollation -FROM pg_catalog.pg_type fk -WHERE typcollation != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.typcollation); -SELECT ctid, conpfeqop -FROM (SELECT ctid, unnest(conpfeqop) AS conpfeqop FROM pg_catalog.pg_constraint) fk -WHERE conpfeqop != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.conpfeqop); -SELECT ctid, conppeqop -FROM (SELECT ctid, unnest(conppeqop) AS conppeqop FROM pg_catalog.pg_constraint) fk -WHERE conppeqop != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.conppeqop); -SELECT ctid, conffeqop -FROM (SELECT ctid, unnest(conffeqop) AS conffeqop FROM pg_catalog.pg_constraint) fk -WHERE conffeqop != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.conffeqop); -SELECT ctid, conexclop -FROM (SELECT ctid, unnest(conexclop) AS conexclop FROM pg_catalog.pg_constraint) fk -WHERE conexclop != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.conexclop); -SELECT ctid, indcollation -FROM (SELECT ctid, unnest(indcollation) AS indcollation FROM pg_catalog.pg_index) fk -WHERE indcollation != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.indcollation); -SELECT ctid, indclass -FROM (SELECT ctid, unnest(indclass) AS indclass FROM pg_catalog.pg_index) fk -WHERE indclass != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.indclass); -SELECT ctid, partclass -FROM (SELECT ctid, unnest(partclass) AS partclass FROM pg_catalog.pg_partitioned_table) fk -WHERE partclass != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.partclass); -SELECT ctid, partcollation -FROM (SELECT ctid, unnest(partcollation) AS partcollation FROM pg_catalog.pg_partitioned_table) fk -WHERE partcollation != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.partcollation); -SELECT ctid, proargtypes -FROM (SELECT ctid, unnest(proargtypes) AS proargtypes FROM pg_catalog.pg_proc) fk -WHERE proargtypes != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.proargtypes); -SELECT ctid, proallargtypes -FROM (SELECT ctid, unnest(proallargtypes) AS proallargtypes FROM pg_catalog.pg_proc) fk -WHERE proallargtypes != 0 AND - NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.proallargtypes); +DO $doblock$ +declare + fk record; + nkeys integer; + cmd text; + err record; +begin + for fk in select * from pg_get_catalog_foreign_keys() + loop + raise notice 'checking % % => % %', + fk.fktable, fk.fkcols, fk.pktable, fk.pkcols; + nkeys := array_length(fk.fkcols, 1); + cmd := 'SELECT ctid'; + for i in 1 .. nkeys loop + cmd := cmd || ', ' || quote_ident(fk.fkcols[i]); + end loop; + if fk.is_array then + cmd := cmd || ' FROM (SELECT ctid'; + for i in 1 .. nkeys-1 loop + cmd := cmd || ', ' || quote_ident(fk.fkcols[i]); + end loop; + cmd := cmd || ', unnest(' || quote_ident(fk.fkcols[nkeys]); + cmd := cmd || ') as ' || quote_ident(fk.fkcols[nkeys]); + cmd := cmd || ' FROM ' || fk.fktable::text || ') fk WHERE '; + else + cmd := cmd || ' FROM ' || fk.fktable::text || ' fk WHERE '; + end if; + if fk.is_opt then + for i in 1 .. nkeys loop + cmd := cmd || quote_ident(fk.fkcols[i]) || ' != 0 AND '; + end loop; + end if; + cmd := cmd || 'NOT EXISTS(SELECT 1 FROM ' || fk.pktable::text || ' pk WHERE '; + for i in 1 .. nkeys loop + if i > 1 then cmd := cmd || ' AND '; end if; + cmd := cmd || 'pk.' || quote_ident(fk.pkcols[i]); + cmd := cmd || ' = fk.' || quote_ident(fk.fkcols[i]); + end loop; + cmd := cmd || ')'; + -- raise notice 'cmd = %', cmd; + for err in execute cmd loop + raise warning 'FK VIOLATION IN %(%): %', fk.fktable, fk.fkcols, err; + end loop; + end loop; +end +$doblock$; diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm index 1c0c92fcd2c2f..2aa062b2c9ecb 100644 --- a/src/tools/msvc/Solution.pm +++ b/src/tools/msvc/Solution.pm @@ -818,6 +818,9 @@ EOF copyFile( 'src/backend/catalog/schemapg.h', 'src/include/catalog/schemapg.h'); + copyFile( + 'src/backend/catalog/system_fk_info.h', + 'src/include/catalog/system_fk_info.h'); open(my $chs, '>', 'src/include/catalog/header-stamp') || confess "Could not touch header-stamp"; close($chs); diff --git a/src/tools/msvc/clean.bat b/src/tools/msvc/clean.bat index 4575e3f95f69c..d0d79a0932573 100755 --- a/src/tools/msvc/clean.bat +++ b/src/tools/msvc/clean.bat @@ -47,6 +47,7 @@ if exist src\include\utils\fmgrprotos.h del /q src\include\utils\fmgrprotos.h if exist src\include\storage\lwlocknames.h del /q src\include\storage\lwlocknames.h if exist src\include\utils\probes.h del /q src\include\utils\probes.h if exist src\include\catalog\schemapg.h del /q src\include\catalog\schemapg.h +if exist src\include\catalog\system_fk_info.h del /q src\include\catalog\system_fk_info.h if exist src\include\catalog\pg_*_d.h del /q src\include\catalog\pg_*_d.h if exist src\include\catalog\header-stamp del /q src\include\catalog\header-stamp if exist doc\src\sgml\version.sgml del /q doc\src\sgml\version.sgml @@ -73,6 +74,7 @@ if %DIST%==1 if exist src\interfaces\ecpg\preproc\preproc.y del /q src\interface if %DIST%==1 if exist src\backend\catalog\postgres.bki del /q src\backend\catalog\postgres.bki if %DIST%==1 if exist src\backend\catalog\system_constraints.sql del /q src\backend\catalog\system_constraints.sql if %DIST%==1 if exist src\backend\catalog\schemapg.h del /q src\backend\catalog\schemapg.h +if %DIST%==1 if exist src\backend\catalog\system_fk_info.h del /q src\backend\catalog\system_fk_info.h if %DIST%==1 if exist src\backend\catalog\pg_*_d.h del /q src\backend\catalog\pg_*_d.h if %DIST%==1 if exist src\backend\catalog\bki-stamp del /q src\backend\catalog\bki-stamp if %DIST%==1 if exist src\backend\parser\scan.c del /q src\backend\parser\scan.c From ef3d4613c0204ab2b87ffa7e8e9551d74f932816 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 2 Feb 2021 17:21:37 -0500 Subject: [PATCH 237/240] Retire findoidjoins. In the wake of commit 62f34097c, we no longer need this tool. Discussion: https://postgr.es/m/3240355.1612129197@sss.pgh.pa.us --- src/tools/RELEASE_CHANGES | 2 - src/tools/findoidjoins/.gitignore | 1 - src/tools/findoidjoins/Makefile | 27 --- src/tools/findoidjoins/README | 248 --------------------- src/tools/findoidjoins/findoidjoins.c | 243 -------------------- src/tools/findoidjoins/make_oidjoins_check | 80 ------- 6 files changed, 601 deletions(-) delete mode 100644 src/tools/findoidjoins/.gitignore delete mode 100644 src/tools/findoidjoins/Makefile delete mode 100644 src/tools/findoidjoins/README delete mode 100644 src/tools/findoidjoins/findoidjoins.c delete mode 100755 src/tools/findoidjoins/make_oidjoins_check diff --git a/src/tools/RELEASE_CHANGES b/src/tools/RELEASE_CHANGES index 5206640341d59..8f9ac00e94ac1 100644 --- a/src/tools/RELEASE_CHANGES +++ b/src/tools/RELEASE_CHANGES @@ -80,8 +80,6 @@ but there may be reasons to do them at other times as well. * Update Unicode data: Edit UNICODE_VERSION and CLDR_VERSION in src/Makefile.global.in, run make update-unicode, and commit. -* Update the oidjoins regression test (see src/tools/findoidjoins/). - Starting a New Development Cycle ================================ diff --git a/src/tools/findoidjoins/.gitignore b/src/tools/findoidjoins/.gitignore deleted file mode 100644 index 21ec074fd9de5..0000000000000 --- a/src/tools/findoidjoins/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/findoidjoins diff --git a/src/tools/findoidjoins/Makefile b/src/tools/findoidjoins/Makefile deleted file mode 100644 index 4de9d10c2ab04..0000000000000 --- a/src/tools/findoidjoins/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -#------------------------------------------------------------------------- -# -# Makefile for src/tools/findoidjoins -# -# Copyright (c) 2003-2021, PostgreSQL Global Development Group -# -# src/tools/findoidjoins/Makefile -# -#------------------------------------------------------------------------- - -subdir = src/tools/findoidjoins -top_builddir = ../../.. -include $(top_builddir)/src/Makefile.global - -override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS) -LDFLAGS_INTERNAL += $(libpq_pgport) - -OBJS = \ - findoidjoins.o - -all: findoidjoins - -findoidjoins: findoidjoins.o | submake-libpq submake-libpgport - $(CC) $(CFLAGS) findoidjoins.o $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) - -clean distclean maintainer-clean: - rm -f findoidjoins$(X) $(OBJS) diff --git a/src/tools/findoidjoins/README b/src/tools/findoidjoins/README deleted file mode 100644 index d0097101fdb5a..0000000000000 --- a/src/tools/findoidjoins/README +++ /dev/null @@ -1,248 +0,0 @@ -src/tools/findoidjoins/README - -findoidjoins -============ - -This program scans a database and prints oid fields (also reg* fields) -and the tables they join to. It is normally used to check the system -catalog join relationships (shown below for 11devel as of 2018-05-07). - -Historically this has been run against an empty database such as template1, -but there's a problem with that approach: some of the catalogs are empty -and so their joining columns won't show up in the output. Current practice -is to run it against the regression-test database, which populates the -catalogs in interesting ways. - -Note that unexpected matches may indicate bogus entries in system tables; -don't accept a peculiar match without question. In particular, a field -shown as joining to more than one target table is probably messed up. -Currently, the *only* fields that should join to more than one target -table are: -pg_description.objoid, pg_depend.objid, pg_depend.refobjid, -pg_shdescription.objoid, pg_shdepend.objid, pg_shdepend.refobjid, -and pg_init_privs.objoid. -(Running make_oidjoins_check is an easy way to spot fields joining to more -than one table, BTW.) - -The shell script make_oidjoins_check converts findoidjoins' output -into an SQL script that checks for dangling links (entries in an -OID or REG* column that don't match any row in the expected table). -Note that fields joining to more than one table are NOT processed, -just reported as linking to more than one table. - -The result of make_oidjoins_check should be installed as the "oidjoins" -regression test. The oidjoins test should be updated after any -revision in the patterns of cross-links between system tables. -(Typically we update it at the end of each development cycle.) - -NOTE: currently, make_oidjoins_check produces two bogus join checks: -Join pg_catalog.pg_class.relfilenode => pg_catalog.pg_class.oid -Join pg_catalog.pg_database.datlastsysoid => pg_catalog.pg_database.oid -These are artifacts and should not be added to the oidjoins regression test. -You might also get output for pg_shdepend.refobjid and pg_shdescription.objoid, -neither of which should be added to the regression test. - -In short, the procedure is: - -1. make installcheck in src/test/regress -2. cd here, make -3. ./findoidjoins regression >foj.out -4. ./make_oidjoins_check foj.out >oidjoins.sql -5. paste foj.out below, removing the entries reported as duplicative - by make_oidjoins_check or described as bogus above -6. remove bogus tests in oidjoins.sql as per above -7. copy oidjoins.sql to src/test/regress/sql/, - and update oidjoins.out to match. -8. Review diffs to ensure they correspond to new catalog relationships, - then commit. (Sometimes, a pre-existing catalog relationship might - become newly visible here as a result of the regression tests populating - a catalog they didn't before. That's OK too.) - ---------------------------------------------------------------------------- - -Join pg_catalog.pg_aggregate.aggfnoid => pg_catalog.pg_proc.oid -Join pg_catalog.pg_aggregate.aggtransfn => pg_catalog.pg_proc.oid -Join pg_catalog.pg_aggregate.aggfinalfn => pg_catalog.pg_proc.oid -Join pg_catalog.pg_aggregate.aggcombinefn => pg_catalog.pg_proc.oid -Join pg_catalog.pg_aggregate.aggserialfn => pg_catalog.pg_proc.oid -Join pg_catalog.pg_aggregate.aggdeserialfn => pg_catalog.pg_proc.oid -Join pg_catalog.pg_aggregate.aggmtransfn => pg_catalog.pg_proc.oid -Join pg_catalog.pg_aggregate.aggminvtransfn => pg_catalog.pg_proc.oid -Join pg_catalog.pg_aggregate.aggmfinalfn => pg_catalog.pg_proc.oid -Join pg_catalog.pg_aggregate.aggsortop => pg_catalog.pg_operator.oid -Join pg_catalog.pg_aggregate.aggtranstype => pg_catalog.pg_type.oid -Join pg_catalog.pg_aggregate.aggmtranstype => pg_catalog.pg_type.oid -Join pg_catalog.pg_am.amhandler => pg_catalog.pg_proc.oid -Join pg_catalog.pg_amop.amopfamily => pg_catalog.pg_opfamily.oid -Join pg_catalog.pg_amop.amoplefttype => pg_catalog.pg_type.oid -Join pg_catalog.pg_amop.amoprighttype => pg_catalog.pg_type.oid -Join pg_catalog.pg_amop.amopopr => pg_catalog.pg_operator.oid -Join pg_catalog.pg_amop.amopmethod => pg_catalog.pg_am.oid -Join pg_catalog.pg_amop.amopsortfamily => pg_catalog.pg_opfamily.oid -Join pg_catalog.pg_amproc.amprocfamily => pg_catalog.pg_opfamily.oid -Join pg_catalog.pg_amproc.amproclefttype => pg_catalog.pg_type.oid -Join pg_catalog.pg_amproc.amprocrighttype => pg_catalog.pg_type.oid -Join pg_catalog.pg_amproc.amproc => pg_catalog.pg_proc.oid -Join pg_catalog.pg_attrdef.adrelid => pg_catalog.pg_class.oid -Join pg_catalog.pg_attribute.attrelid => pg_catalog.pg_class.oid -Join pg_catalog.pg_attribute.atttypid => pg_catalog.pg_type.oid -Join pg_catalog.pg_attribute.attcollation => pg_catalog.pg_collation.oid -Join pg_catalog.pg_auth_members.roleid => pg_catalog.pg_authid.oid -Join pg_catalog.pg_auth_members.member => pg_catalog.pg_authid.oid -Join pg_catalog.pg_auth_members.grantor => pg_catalog.pg_authid.oid -Join pg_catalog.pg_cast.castsource => pg_catalog.pg_type.oid -Join pg_catalog.pg_cast.casttarget => pg_catalog.pg_type.oid -Join pg_catalog.pg_cast.castfunc => pg_catalog.pg_proc.oid -Join pg_catalog.pg_class.relnamespace => pg_catalog.pg_namespace.oid -Join pg_catalog.pg_class.reltype => pg_catalog.pg_type.oid -Join pg_catalog.pg_class.reloftype => pg_catalog.pg_type.oid -Join pg_catalog.pg_class.relowner => pg_catalog.pg_authid.oid -Join pg_catalog.pg_class.relam => pg_catalog.pg_am.oid -Join pg_catalog.pg_class.reltablespace => pg_catalog.pg_tablespace.oid -Join pg_catalog.pg_class.reltoastrelid => pg_catalog.pg_class.oid -Join pg_catalog.pg_collation.collnamespace => pg_catalog.pg_namespace.oid -Join pg_catalog.pg_collation.collowner => pg_catalog.pg_authid.oid -Join pg_catalog.pg_constraint.connamespace => pg_catalog.pg_namespace.oid -Join pg_catalog.pg_constraint.conrelid => pg_catalog.pg_class.oid -Join pg_catalog.pg_constraint.contypid => pg_catalog.pg_type.oid -Join pg_catalog.pg_constraint.conindid => pg_catalog.pg_class.oid -Join pg_catalog.pg_constraint.conparentid => pg_catalog.pg_constraint.oid -Join pg_catalog.pg_constraint.confrelid => pg_catalog.pg_class.oid -Join pg_catalog.pg_conversion.connamespace => pg_catalog.pg_namespace.oid -Join pg_catalog.pg_conversion.conowner => pg_catalog.pg_authid.oid -Join pg_catalog.pg_conversion.conproc => pg_catalog.pg_proc.oid -Join pg_catalog.pg_database.datdba => pg_catalog.pg_authid.oid -Join pg_catalog.pg_database.dattablespace => pg_catalog.pg_tablespace.oid -Join pg_catalog.pg_db_role_setting.setdatabase => pg_catalog.pg_database.oid -Join pg_catalog.pg_depend.classid => pg_catalog.pg_class.oid -Join pg_catalog.pg_depend.refclassid => pg_catalog.pg_class.oid -Join pg_catalog.pg_description.classoid => pg_catalog.pg_class.oid -Join pg_catalog.pg_enum.enumtypid => pg_catalog.pg_type.oid -Join pg_catalog.pg_extension.extowner => pg_catalog.pg_authid.oid -Join pg_catalog.pg_extension.extnamespace => pg_catalog.pg_namespace.oid -Join pg_catalog.pg_foreign_data_wrapper.fdwowner => pg_catalog.pg_authid.oid -Join pg_catalog.pg_foreign_server.srvowner => pg_catalog.pg_authid.oid -Join pg_catalog.pg_foreign_server.srvfdw => pg_catalog.pg_foreign_data_wrapper.oid -Join pg_catalog.pg_index.indexrelid => pg_catalog.pg_class.oid -Join pg_catalog.pg_index.indrelid => pg_catalog.pg_class.oid -Join pg_catalog.pg_inherits.inhrelid => pg_catalog.pg_class.oid -Join pg_catalog.pg_inherits.inhparent => pg_catalog.pg_class.oid -Join pg_catalog.pg_init_privs.classoid => pg_catalog.pg_class.oid -Join pg_catalog.pg_language.lanowner => pg_catalog.pg_authid.oid -Join pg_catalog.pg_language.lanplcallfoid => pg_catalog.pg_proc.oid -Join pg_catalog.pg_language.laninline => pg_catalog.pg_proc.oid -Join pg_catalog.pg_language.lanvalidator => pg_catalog.pg_proc.oid -Join pg_catalog.pg_largeobject.loid => pg_catalog.pg_largeobject_metadata.oid -Join pg_catalog.pg_largeobject_metadata.lomowner => pg_catalog.pg_authid.oid -Join pg_catalog.pg_namespace.nspowner => pg_catalog.pg_authid.oid -Join pg_catalog.pg_opclass.opcmethod => pg_catalog.pg_am.oid -Join pg_catalog.pg_opclass.opcnamespace => pg_catalog.pg_namespace.oid -Join pg_catalog.pg_opclass.opcowner => pg_catalog.pg_authid.oid -Join pg_catalog.pg_opclass.opcfamily => pg_catalog.pg_opfamily.oid -Join pg_catalog.pg_opclass.opcintype => pg_catalog.pg_type.oid -Join pg_catalog.pg_opclass.opckeytype => pg_catalog.pg_type.oid -Join pg_catalog.pg_operator.oprnamespace => pg_catalog.pg_namespace.oid -Join pg_catalog.pg_operator.oprowner => pg_catalog.pg_authid.oid -Join pg_catalog.pg_operator.oprleft => pg_catalog.pg_type.oid -Join pg_catalog.pg_operator.oprright => pg_catalog.pg_type.oid -Join pg_catalog.pg_operator.oprresult => pg_catalog.pg_type.oid -Join pg_catalog.pg_operator.oprcom => pg_catalog.pg_operator.oid -Join pg_catalog.pg_operator.oprnegate => pg_catalog.pg_operator.oid -Join pg_catalog.pg_operator.oprcode => pg_catalog.pg_proc.oid -Join pg_catalog.pg_operator.oprrest => pg_catalog.pg_proc.oid -Join pg_catalog.pg_operator.oprjoin => pg_catalog.pg_proc.oid -Join pg_catalog.pg_opfamily.opfmethod => pg_catalog.pg_am.oid -Join pg_catalog.pg_opfamily.opfnamespace => pg_catalog.pg_namespace.oid -Join pg_catalog.pg_opfamily.opfowner => pg_catalog.pg_authid.oid -Join pg_catalog.pg_partitioned_table.partrelid => pg_catalog.pg_class.oid -Join pg_catalog.pg_partitioned_table.partdefid => pg_catalog.pg_class.oid -Join pg_catalog.pg_policy.polrelid => pg_catalog.pg_class.oid -Join pg_catalog.pg_proc.pronamespace => pg_catalog.pg_namespace.oid -Join pg_catalog.pg_proc.proowner => pg_catalog.pg_authid.oid -Join pg_catalog.pg_proc.prolang => pg_catalog.pg_language.oid -Join pg_catalog.pg_proc.provariadic => pg_catalog.pg_type.oid -Join pg_catalog.pg_proc.prosupport => pg_catalog.pg_proc.oid -Join pg_catalog.pg_proc.prorettype => pg_catalog.pg_type.oid -Join pg_catalog.pg_range.rngtypid => pg_catalog.pg_type.oid -Join pg_catalog.pg_range.rngsubtype => pg_catalog.pg_type.oid -Join pg_catalog.pg_range.rngcollation => pg_catalog.pg_collation.oid -Join pg_catalog.pg_range.rngsubopc => pg_catalog.pg_opclass.oid -Join pg_catalog.pg_range.rngcanonical => pg_catalog.pg_proc.oid -Join pg_catalog.pg_range.rngsubdiff => pg_catalog.pg_proc.oid -Join pg_catalog.pg_rewrite.ev_class => pg_catalog.pg_class.oid -Join pg_catalog.pg_sequence.seqrelid => pg_catalog.pg_class.oid -Join pg_catalog.pg_sequence.seqtypid => pg_catalog.pg_type.oid -Join pg_catalog.pg_shdepend.refclassid => pg_catalog.pg_class.oid -Join pg_catalog.pg_shdescription.classoid => pg_catalog.pg_class.oid -Join pg_catalog.pg_statistic.starelid => pg_catalog.pg_class.oid -Join pg_catalog.pg_statistic.staop1 => pg_catalog.pg_operator.oid -Join pg_catalog.pg_statistic.staop2 => pg_catalog.pg_operator.oid -Join pg_catalog.pg_statistic.staop3 => pg_catalog.pg_operator.oid -Join pg_catalog.pg_statistic.staop4 => pg_catalog.pg_operator.oid -Join pg_catalog.pg_statistic.staop5 => pg_catalog.pg_operator.oid -Join pg_catalog.pg_statistic.stacoll1 => pg_catalog.pg_collation.oid -Join pg_catalog.pg_statistic.stacoll2 => pg_catalog.pg_collation.oid -Join pg_catalog.pg_statistic.stacoll3 => pg_catalog.pg_collation.oid -Join pg_catalog.pg_statistic.stacoll4 => pg_catalog.pg_collation.oid -Join pg_catalog.pg_statistic.stacoll5 => pg_catalog.pg_collation.oid -Join pg_catalog.pg_statistic_ext.stxrelid => pg_catalog.pg_class.oid -Join pg_catalog.pg_statistic_ext.stxnamespace => pg_catalog.pg_namespace.oid -Join pg_catalog.pg_statistic_ext.stxowner => pg_catalog.pg_authid.oid -Join pg_catalog.pg_statistic_ext_data.stxoid => pg_catalog.pg_statistic_ext.oid -Join pg_catalog.pg_tablespace.spcowner => pg_catalog.pg_authid.oid -Join pg_catalog.pg_transform.trftype => pg_catalog.pg_type.oid -Join pg_catalog.pg_transform.trflang => pg_catalog.pg_language.oid -Join pg_catalog.pg_transform.trffromsql => pg_catalog.pg_proc.oid -Join pg_catalog.pg_transform.trftosql => pg_catalog.pg_proc.oid -Join pg_catalog.pg_trigger.tgrelid => pg_catalog.pg_class.oid -Join pg_catalog.pg_trigger.tgparentid => pg_catalog.pg_trigger.oid -Join pg_catalog.pg_trigger.tgfoid => pg_catalog.pg_proc.oid -Join pg_catalog.pg_trigger.tgconstrrelid => pg_catalog.pg_class.oid -Join pg_catalog.pg_trigger.tgconstrindid => pg_catalog.pg_class.oid -Join pg_catalog.pg_trigger.tgconstraint => pg_catalog.pg_constraint.oid -Join pg_catalog.pg_ts_config.cfgnamespace => pg_catalog.pg_namespace.oid -Join pg_catalog.pg_ts_config.cfgowner => pg_catalog.pg_authid.oid -Join pg_catalog.pg_ts_config.cfgparser => pg_catalog.pg_ts_parser.oid -Join pg_catalog.pg_ts_config_map.mapcfg => pg_catalog.pg_ts_config.oid -Join pg_catalog.pg_ts_config_map.mapdict => pg_catalog.pg_ts_dict.oid -Join pg_catalog.pg_ts_dict.dictnamespace => pg_catalog.pg_namespace.oid -Join pg_catalog.pg_ts_dict.dictowner => pg_catalog.pg_authid.oid -Join pg_catalog.pg_ts_dict.dicttemplate => pg_catalog.pg_ts_template.oid -Join pg_catalog.pg_ts_parser.prsnamespace => pg_catalog.pg_namespace.oid -Join pg_catalog.pg_ts_parser.prsstart => pg_catalog.pg_proc.oid -Join pg_catalog.pg_ts_parser.prstoken => pg_catalog.pg_proc.oid -Join pg_catalog.pg_ts_parser.prsend => pg_catalog.pg_proc.oid -Join pg_catalog.pg_ts_parser.prsheadline => pg_catalog.pg_proc.oid -Join pg_catalog.pg_ts_parser.prslextype => pg_catalog.pg_proc.oid -Join pg_catalog.pg_ts_template.tmplnamespace => pg_catalog.pg_namespace.oid -Join pg_catalog.pg_ts_template.tmplinit => pg_catalog.pg_proc.oid -Join pg_catalog.pg_ts_template.tmpllexize => pg_catalog.pg_proc.oid -Join pg_catalog.pg_type.typnamespace => pg_catalog.pg_namespace.oid -Join pg_catalog.pg_type.typowner => pg_catalog.pg_authid.oid -Join pg_catalog.pg_type.typrelid => pg_catalog.pg_class.oid -Join pg_catalog.pg_type.typelem => pg_catalog.pg_type.oid -Join pg_catalog.pg_type.typarray => pg_catalog.pg_type.oid -Join pg_catalog.pg_type.typinput => pg_catalog.pg_proc.oid -Join pg_catalog.pg_type.typoutput => pg_catalog.pg_proc.oid -Join pg_catalog.pg_type.typreceive => pg_catalog.pg_proc.oid -Join pg_catalog.pg_type.typsend => pg_catalog.pg_proc.oid -Join pg_catalog.pg_type.typmodin => pg_catalog.pg_proc.oid -Join pg_catalog.pg_type.typmodout => pg_catalog.pg_proc.oid -Join pg_catalog.pg_type.typanalyze => pg_catalog.pg_proc.oid -Join pg_catalog.pg_type.typbasetype => pg_catalog.pg_type.oid -Join pg_catalog.pg_type.typcollation => pg_catalog.pg_collation.oid -Join pg_catalog.pg_constraint.conpfeqop []=> pg_catalog.pg_operator.oid -Join pg_catalog.pg_constraint.conppeqop []=> pg_catalog.pg_operator.oid -Join pg_catalog.pg_constraint.conffeqop []=> pg_catalog.pg_operator.oid -Join pg_catalog.pg_constraint.conexclop []=> pg_catalog.pg_operator.oid -Join pg_catalog.pg_index.indcollation []=> pg_catalog.pg_collation.oid -Join pg_catalog.pg_index.indclass []=> pg_catalog.pg_opclass.oid -Join pg_catalog.pg_partitioned_table.partclass []=> pg_catalog.pg_opclass.oid -Join pg_catalog.pg_partitioned_table.partcollation []=> pg_catalog.pg_collation.oid -Join pg_catalog.pg_proc.proargtypes []=> pg_catalog.pg_type.oid -Join pg_catalog.pg_proc.proallargtypes []=> pg_catalog.pg_type.oid - ---------------------------------------------------------------------------- - -Bruce Momjian (bruce@momjian.us) -Updated for 7.3 by Joe Conway (mail@joeconway.com) diff --git a/src/tools/findoidjoins/findoidjoins.c b/src/tools/findoidjoins/findoidjoins.c deleted file mode 100644 index f882c8b0ef244..0000000000000 --- a/src/tools/findoidjoins/findoidjoins.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * findoidjoins.c - * - * Copyright (c) 2002-2021, PostgreSQL Global Development Group - * - * src/tools/findoidjoins/findoidjoins.c - */ -#include "postgres_fe.h" - -#include "access/transam.h" -#include "catalog/pg_class_d.h" - -#include "common/connect.h" -#include "libpq-fe.h" -#include "pqexpbuffer.h" - - -int -main(int argc, char **argv) -{ - PGconn *conn; - PQExpBufferData sql; - PGresult *res; - PGresult *pkrel_res; - PGresult *fkrel_res; - char *fk_relname; - char *fk_nspname; - char *fk_attname; - char *pk_relname; - char *pk_nspname; - int fk, - pk; /* loop counters */ - - if (argc != 2) - { - fprintf(stderr, "Usage: %s database\n", argv[0]); - exit(EXIT_FAILURE); - } - - initPQExpBuffer(&sql); - - appendPQExpBuffer(&sql, "dbname=%s", argv[1]); - - conn = PQconnectdb(sql.data); - if (PQstatus(conn) == CONNECTION_BAD) - { - fprintf(stderr, "%s", PQerrorMessage(conn)); - exit(EXIT_FAILURE); - } - - res = PQexec(conn, ALWAYS_SECURE_SEARCH_PATH_SQL); - if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) - { - fprintf(stderr, "sql error: %s\n", PQerrorMessage(conn)); - exit(EXIT_FAILURE); - } - PQclear(res); - - /* Get a list of system relations that have OIDs */ - - printfPQExpBuffer(&sql, - "SELECT c.relname, (SELECT nspname FROM " - "pg_catalog.pg_namespace n WHERE n.oid = c.relnamespace) AS nspname " - "FROM pg_catalog.pg_class c " - "WHERE c.relkind = " CppAsString2(RELKIND_RELATION) - " AND c.oid < '%u'" - " AND EXISTS(SELECT * FROM pg_attribute a" - " WHERE a.attrelid = c.oid AND a.attname = 'oid' " - " AND a.atttypid = 'oid'::regtype)" - "ORDER BY nspname, c.relname", - FirstNormalObjectId - ); - - res = PQexec(conn, sql.data); - if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) - { - fprintf(stderr, "sql error: %s\n", PQerrorMessage(conn)); - exit(EXIT_FAILURE); - } - pkrel_res = res; - - /* Get a list of system columns of OID type (or any OID-alias type) */ - - printfPQExpBuffer(&sql, - "SELECT c.relname, " - "(SELECT nspname FROM pg_catalog.pg_namespace n WHERE n.oid = c.relnamespace) AS nspname, " - "a.attname " - "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a " - "WHERE a.attnum > 0" - " AND a.attname != 'oid'" - " AND c.relkind = " CppAsString2(RELKIND_RELATION) - " AND c.oid < '%u'" - " AND a.attrelid = c.oid" - " AND a.atttypid IN ('pg_catalog.oid'::regtype, " - " 'pg_catalog.regclass'::regtype, " - " 'pg_catalog.regoper'::regtype, " - " 'pg_catalog.regoperator'::regtype, " - " 'pg_catalog.regproc'::regtype, " - " 'pg_catalog.regprocedure'::regtype, " - " 'pg_catalog.regtype'::regtype, " - " 'pg_catalog.regconfig'::regtype, " - " 'pg_catalog.regdictionary'::regtype) " - "ORDER BY nspname, c.relname, a.attnum", - FirstNormalObjectId - ); - - res = PQexec(conn, sql.data); - if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) - { - fprintf(stderr, "sql error: %s\n", PQerrorMessage(conn)); - exit(EXIT_FAILURE); - } - fkrel_res = res; - - /* - * For each column and each relation-having-OIDs, look to see if the - * column contains any values matching entries in the relation. - */ - - for (fk = 0; fk < PQntuples(fkrel_res); fk++) - { - fk_relname = PQgetvalue(fkrel_res, fk, 0); - fk_nspname = PQgetvalue(fkrel_res, fk, 1); - fk_attname = PQgetvalue(fkrel_res, fk, 2); - - for (pk = 0; pk < PQntuples(pkrel_res); pk++) - { - pk_relname = PQgetvalue(pkrel_res, pk, 0); - pk_nspname = PQgetvalue(pkrel_res, pk, 1); - - printfPQExpBuffer(&sql, - "SELECT 1 " - "FROM \"%s\".\"%s\" t1, " - "\"%s\".\"%s\" t2 " - "WHERE t1.\"%s\"::pg_catalog.oid = t2.oid " - "LIMIT 1", - fk_nspname, fk_relname, - pk_nspname, pk_relname, - fk_attname); - - res = PQexec(conn, sql.data); - if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) - { - fprintf(stderr, "sql error: %s\n", PQerrorMessage(conn)); - exit(EXIT_FAILURE); - } - - if (PQntuples(res) != 0) - printf("Join %s.%s.%s => %s.%s.oid\n", - fk_nspname, fk_relname, fk_attname, - pk_nspname, pk_relname); - - PQclear(res); - } - } - - PQclear(fkrel_res); - - /* Now, do the same for referencing columns that are arrays */ - - /* Get a list of columns of OID-array type (or any OID-alias type) */ - - printfPQExpBuffer(&sql, "%s", - "SELECT c.relname, " - "(SELECT nspname FROM pg_catalog.pg_namespace n WHERE n.oid = c.relnamespace) AS nspname, " - "a.attname " - "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a " - "WHERE a.attnum > 0" - " AND c.relkind = " CppAsString2(RELKIND_RELATION) - " AND a.attrelid = c.oid" - " AND a.atttypid IN ('pg_catalog.oid[]'::regtype, " - " 'pg_catalog.oidvector'::regtype, " - " 'pg_catalog.regclass[]'::regtype, " - " 'pg_catalog.regoper[]'::regtype, " - " 'pg_catalog.regoperator[]'::regtype, " - " 'pg_catalog.regproc[]'::regtype, " - " 'pg_catalog.regprocedure[]'::regtype, " - " 'pg_catalog.regtype[]'::regtype, " - " 'pg_catalog.regconfig[]'::regtype, " - " 'pg_catalog.regdictionary[]'::regtype) " - "ORDER BY nspname, c.relname, a.attnum" - ); - - res = PQexec(conn, sql.data); - if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) - { - fprintf(stderr, "sql error: %s\n", PQerrorMessage(conn)); - exit(EXIT_FAILURE); - } - fkrel_res = res; - - /* - * For each column and each relation-having-OIDs, look to see if the - * column contains any values matching entries in the relation. - */ - - for (fk = 0; fk < PQntuples(fkrel_res); fk++) - { - fk_relname = PQgetvalue(fkrel_res, fk, 0); - fk_nspname = PQgetvalue(fkrel_res, fk, 1); - fk_attname = PQgetvalue(fkrel_res, fk, 2); - - for (pk = 0; pk < PQntuples(pkrel_res); pk++) - { - pk_relname = PQgetvalue(pkrel_res, pk, 0); - pk_nspname = PQgetvalue(pkrel_res, pk, 1); - - printfPQExpBuffer(&sql, - "SELECT 1 " - "FROM \"%s\".\"%s\" t1, " - "\"%s\".\"%s\" t2 " - "WHERE t2.oid = ANY(t1.\"%s\")" - "LIMIT 1", - fk_nspname, fk_relname, - pk_nspname, pk_relname, - fk_attname); - - res = PQexec(conn, sql.data); - if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) - { - fprintf(stderr, "sql error: %s\n", PQerrorMessage(conn)); - exit(EXIT_FAILURE); - } - - if (PQntuples(res) != 0) - printf("Join %s.%s.%s []=> %s.%s.oid\n", - fk_nspname, fk_relname, fk_attname, - pk_nspname, pk_relname); - - PQclear(res); - } - } - - PQclear(fkrel_res); - - PQclear(pkrel_res); - - PQfinish(conn); - - termPQExpBuffer(&sql); - - exit(EXIT_SUCCESS); -} diff --git a/src/tools/findoidjoins/make_oidjoins_check b/src/tools/findoidjoins/make_oidjoins_check deleted file mode 100755 index 09d283462c11c..0000000000000 --- a/src/tools/findoidjoins/make_oidjoins_check +++ /dev/null @@ -1,80 +0,0 @@ -#! /bin/sh - -# src/tools/findoidjoins/make_oidjoins_check - -# You first run findoidjoins on the regression database, then send that -# output into this script to generate a list of SQL statements. - -# NOTE: any field that findoidjoins thinks joins to more than one table -# will NOT be checked by the output of this script. You should be -# suspicious of multiple entries in findoidjoins' output. - -# Caution: you may need to use GNU awk. -AWK=${AWK:-awk} - -# Create a temporary directory with the proper permissions so no one can -# intercept our temporary files and cause a security breach. -TMP="${TMPDIR:-/tmp}/make_oidjoins_check.$$" -OMASK="`umask`" -umask 077 -if ! mkdir $TMP -then echo "Can't create temporary directory $TMP." 1>&2 - exit 1 -fi -trap "rm -rf $TMP" 0 1 2 3 15 -umask "$OMASK" -unset OMASK - -INPUTFILE="$TMP/a" -DUPSFILE="$TMP/b" -NONDUPSFILE="$TMP/c" - -# Read input -cat "$@" >$INPUTFILE - -# Look for fields with multiple references. -cat $INPUTFILE | cut -d' ' -f2 | sort | uniq -d >$DUPSFILE -if [ -s $DUPSFILE ] ; then - echo "Ignoring these fields that link to multiple tables:" 1>&2 - cat $DUPSFILE 1>&2 -fi - -# Get the fields without multiple references. -cat $INPUTFILE | while read LINE -do - set -- $LINE - grep "^$2\$" $DUPSFILE >/dev/null 2>&1 || echo $LINE -done >$NONDUPSFILE - -# Generate the output. -cat $NONDUPSFILE | -$AWK -F'[ .]' '\ - BEGIN \ - { - printf "\ ---\n\ --- This is created by pgsql/src/tools/findoidjoins/make_oidjoins_check\n\ ---\n"; - } - $5 == "=>" \ - { - printf "\ -SELECT ctid, %s\n\ -FROM %s.%s fk\n\ -WHERE %s != 0 AND\n\ - NOT EXISTS(SELECT 1 FROM %s.%s pk WHERE pk.oid = fk.%s);\n", - $4, $2, $3, $4, - $6, $7, $4; - } - $5 == "[]=>" \ - { - printf "\ -SELECT ctid, %s\n\ -FROM (SELECT ctid, unnest(%s) AS %s FROM %s.%s) fk\n\ -WHERE %s != 0 AND\n\ - NOT EXISTS(SELECT 1 FROM %s.%s pk WHERE pk.oid = fk.%s);\n", - $4, $4, $4, $2, $3, $4, - $6, $7, $4; - }' - -exit 0 From 0bf83648a52df96f7c8677edbbdf141bfa0cf32b Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Wed, 3 Feb 2021 11:27:13 +0100 Subject: [PATCH 238/240] pg_dump: Fix dumping of inherited generated columns Generation expressions of generated columns are always inherited, so there is no need to set them separately in child tables, and there is no syntax to do so either. The code previously used the code paths for the handling of default values, for which different rules apply; in particular it might want to set a default value explicitly for an inherited column. This resulted in unrestorable dumps. For generated columns, just skip them in inherited tables. Reviewed-by: Tom Lane Discussion: https://www.postgresql.org/message-id/flat/15830.1575468847%40sss.pgh.pa.us --- src/bin/pg_dump/common.c | 31 ++++++++++++++++----- src/bin/pg_dump/pg_dump.c | 37 +++++++++++++++++++++---- src/bin/pg_dump/t/002_pg_dump.pl | 46 ++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 12 deletions(-) diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c index b0f02bc1f6e51..1a261a5545668 100644 --- a/src/bin/pg_dump/common.c +++ b/src/bin/pg_dump/common.c @@ -467,12 +467,22 @@ flagInhIndexes(Archive *fout, TableInfo tblinfo[], int numTables) /* flagInhAttrs - * for each dumpable table in tblinfo, flag its inherited attributes * - * What we need to do here is detect child columns that inherit NOT NULL - * bits from their parents (so that we needn't specify that again for the - * child) and child columns that have DEFAULT NULL when their parents had - * some non-null default. In the latter case, we make up a dummy AttrDefInfo - * object so that we'll correctly emit the necessary DEFAULT NULL clause; - * otherwise the backend will apply an inherited default to the column. + * What we need to do here is: + * + * - Detect child columns that inherit NOT NULL bits from their parents, so + * that we needn't specify that again for the child. + * + * - Detect child columns that have DEFAULT NULL when their parents had some + * non-null default. In this case, we make up a dummy AttrDefInfo object so + * that we'll correctly emit the necessary DEFAULT NULL clause; otherwise + * the backend will apply an inherited default to the column. + * + * - Detect child columns that have a generation expression when their parents + * also have one. Generation expressions are always inherited, so there is + * no need to set them again in child tables, and there is no syntax for it + * either. (Exception: In binary upgrade mode we dump them because + * inherited tables are recreated standalone first and then reattached to + * the parent.) * * modifies tblinfo */ @@ -510,6 +520,7 @@ flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables) { bool foundNotNull; /* Attr was NOT NULL in a parent */ bool foundDefault; /* Found a default in a parent */ + bool foundGenerated; /* Found a generated in a parent */ /* no point in examining dropped columns */ if (tbinfo->attisdropped[j]) @@ -517,6 +528,7 @@ flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables) foundNotNull = false; foundDefault = false; + foundGenerated = false; for (k = 0; k < numParents; k++) { TableInfo *parent = parents[k]; @@ -528,7 +540,8 @@ flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables) if (inhAttrInd >= 0) { foundNotNull |= parent->notnull[inhAttrInd]; - foundDefault |= (parent->attrdefs[inhAttrInd] != NULL); + foundDefault |= (parent->attrdefs[inhAttrInd] != NULL && !parent->attgenerated[inhAttrInd]); + foundGenerated |= parent->attgenerated[inhAttrInd]; } } @@ -570,6 +583,10 @@ flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables) tbinfo->attrdefs[j] = attrDef; } + + /* Remove generation expression from child */ + if (foundGenerated && !dopt->binary_upgrade) + tbinfo->attrdefs[j] = NULL; } } } diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 39da742e32c60..d99b61e6215f1 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -8839,13 +8839,37 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables) attrdefs[j].dobj.dump = tbinfo->dobj.dump; /* - * Defaults on a VIEW must always be dumped as separate ALTER - * TABLE commands. Defaults on regular tables are dumped as - * part of the CREATE TABLE if possible, which it won't be if - * the column is not going to be emitted explicitly. + * Figure out whether the default/generation expression should + * be dumped as part of the main CREATE TABLE (or similar) + * command or as a separate ALTER TABLE (or similar) command. + * The preference is to put it into the CREATE command, but in + * some cases that's not possible. */ - if (tbinfo->relkind == RELKIND_VIEW) + if (tbinfo->attgenerated[adnum - 1]) { + /* + * Column generation expressions cannot be dumped + * separately, because there is no syntax for it. The + * !shouldPrintColumn case below will be tempted to set + * them to separate if they are attached to an inherited + * column without a local definition, but that would be + * wrong and unnecessary, because generation expressions + * are always inherited, so there is no need to set them + * again in child tables, and there is no syntax for it + * either. By setting separate to false here we prevent + * the "default" from being processed as its own dumpable + * object, and flagInhAttrs() will remove it from the + * table when it detects that it belongs to an inherited + * column. + */ + attrdefs[j].separate = false; + } + else if (tbinfo->relkind == RELKIND_VIEW) + { + /* + * Defaults on a VIEW must always be dumped as separate + * ALTER TABLE commands. + */ attrdefs[j].separate = true; } else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1)) @@ -8856,7 +8880,10 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables) else { attrdefs[j].separate = false; + } + if (!attrdefs[j].separate) + { /* * Mark the default as needing to appear before the table, * so that any dependencies it has must be emitted before diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl index 798884da36b12..737e46464ab7e 100644 --- a/src/bin/pg_dump/t/002_pg_dump.pl +++ b/src/bin/pg_dump/t/002_pg_dump.pl @@ -2493,6 +2493,52 @@ unlike => { exclude_dump_test_schema => 1, }, }, + 'CREATE TABLE test_table_generated_child1 (without local columns)' => { + create_order => 4, + create_sql => 'CREATE TABLE dump_test.test_table_generated_child1 () + INHERITS (dump_test.test_table_generated);', + regexp => qr/^ + \QCREATE TABLE dump_test.test_table_generated_child1 (\E\n + \)\n + \QINHERITS (dump_test.test_table_generated);\E\n + /xms, + like => + { %full_runs, %dump_test_schema_runs, section_pre_data => 1, }, + unlike => { + binary_upgrade => 1, + exclude_dump_test_schema => 1, + }, + }, + + 'ALTER TABLE test_table_generated_child1' => { + regexp => + qr/^\QALTER TABLE ONLY dump_test.test_table_generated_child1 ALTER COLUMN col2 \E/m, + + # should not get emitted + like => {}, + }, + + 'CREATE TABLE test_table_generated_child2 (with local columns)' => { + create_order => 4, + create_sql => 'CREATE TABLE dump_test.test_table_generated_child2 ( + col1 int, + col2 int + ) INHERITS (dump_test.test_table_generated);', + regexp => qr/^ + \QCREATE TABLE dump_test.test_table_generated_child2 (\E\n + \s+\Qcol1 integer,\E\n + \s+\Qcol2 integer\E\n + \)\n + \QINHERITS (dump_test.test_table_generated);\E\n + /xms, + like => + { %full_runs, %dump_test_schema_runs, section_pre_data => 1, }, + unlike => { + binary_upgrade => 1, + exclude_dump_test_schema => 1, + }, + }, + 'CREATE TABLE table_with_stats' => { create_order => 98, create_sql => 'CREATE TABLE dump_test.table_index_stats ( From ba0faf81c65ac99dd42ce192f3257d4d2231ea50 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 3 Feb 2021 12:01:48 -0500 Subject: [PATCH 239/240] Remove special BKI_LOOKUP magic for namespace and role OIDs. Now that commit 62f34097c attached BKI_LOOKUP annotation to all the namespace and role OID columns in the catalogs, there's no real reason to have the magic PGNSP and PGUID symbols. Get rid of them in favor of implementing those lookups according to genbki.pl's normal pattern. This means that in the catalog headers, BKI_DEFAULT(PGNSP) becomes BKI_DEFAULT(pg_catalog), which seems a lot more transparent. BKI_DEFAULT(PGUID) becomes BKI_DEFAULT(POSTGRES), which is perhaps less so; but you can look into pg_authid.dat to discover that POSTGRES is the nonce name for the bootstrap superuser. This change also means that if we ever need cross-references in the initial catalog data to any of the other built-in roles besides POSTGRES, or to some other built-in schema besides pg_catalog, we can just do it. No catversion bump here, as there's no actual change in the contents of postgres.bki. Discussion: https://postgr.es/m/3240355.1612129197@sss.pgh.pa.us --- doc/src/sgml/bki.sgml | 11 ----------- src/backend/catalog/genbki.pl | 24 ++++++++++-------------- src/include/catalog/pg_authid.dat | 4 ++++ src/include/catalog/pg_class.h | 4 ++-- src/include/catalog/pg_collation.h | 9 ++++++--- src/include/catalog/pg_conversion.h | 4 ++-- src/include/catalog/pg_database.h | 2 +- src/include/catalog/pg_language.h | 2 +- src/include/catalog/pg_namespace.h | 2 +- src/include/catalog/pg_opclass.h | 4 ++-- src/include/catalog/pg_operator.h | 4 ++-- src/include/catalog/pg_opfamily.h | 4 ++-- src/include/catalog/pg_proc.h | 4 ++-- src/include/catalog/pg_tablespace.h | 4 +++- src/include/catalog/pg_ts_config.h | 4 ++-- src/include/catalog/pg_ts_dict.h | 4 ++-- src/include/catalog/pg_ts_parser.h | 2 +- src/include/catalog/pg_ts_template.h | 2 +- src/include/catalog/pg_type.h | 4 ++-- 19 files changed, 46 insertions(+), 52 deletions(-) diff --git a/doc/src/sgml/bki.sgml b/doc/src/sgml/bki.sgml index 6d3c5be67f8d1..db1b3d5e9a028 100644 --- a/doc/src/sgml/bki.sgml +++ b/doc/src/sgml/bki.sgml @@ -540,17 +540,6 @@ expected to be in the pg_catalog schema. - - - - In addition to the generic lookup mechanisms, there is a special - convention that PGNSP is replaced by the OID of - the pg_catalog schema, - and PGUID is replaced by the OID of the bootstrap - superuser role. These usages are somewhat historical but so far - there hasn't been a need to generalize them. - - diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl index 5bdc7adc44022..b15995811234a 100644 --- a/src/backend/catalog/genbki.pl +++ b/src/backend/catalog/genbki.pl @@ -184,15 +184,9 @@ # within a given Postgres release, such as fixed OIDs. Do not substitute # anything that could depend on platform or configuration. (The right place # to handle those sorts of things is in initdb.c's bootstrap_template1().) -my $BOOTSTRAP_SUPERUSERID = - Catalog::FindDefinedSymbolFromData($catalog_data{pg_authid}, - 'BOOTSTRAP_SUPERUSERID'); my $C_COLLATION_OID = Catalog::FindDefinedSymbolFromData($catalog_data{pg_collation}, 'C_COLLATION_OID'); -my $PG_CATALOG_NAMESPACE = - Catalog::FindDefinedSymbolFromData($catalog_data{pg_namespace}, - 'PG_CATALOG_NAMESPACE'); # Fill in pg_class.relnatts by looking at the referenced catalog's schema. @@ -213,11 +207,12 @@ $amoids{ $row->{amname} } = $row->{oid}; } -# There is only one authid at bootstrap time, and we handle it specially: -# the usually-defaulted symbol PGUID becomes the bootstrap superuser's OID. -# (We could drop this in favor of writing out BKI_DEFAULT(POSTGRES) ...) +# role OID lookup my %authidoids; -$authidoids{'PGUID'} = $BOOTSTRAP_SUPERUSERID; +foreach my $row (@{ $catalog_data{pg_authid} }) +{ + $authidoids{ $row->{rolname} } = $row->{oid}; +} # class (relation) OID lookup (note this only covers bootstrap catalogs!) my %classoids; @@ -240,11 +235,12 @@ $langoids{ $row->{lanname} } = $row->{oid}; } -# There is only one namespace at bootstrap time, and we handle it specially: -# the usually-defaulted symbol PGNSP becomes the pg_catalog namespace's OID. -# (We could drop this in favor of writing out BKI_DEFAULT(pg_catalog) ...) +# namespace (schema) OID lookup my %namespaceoids; -$namespaceoids{'PGNSP'} = $PG_CATALOG_NAMESPACE; +foreach my $row (@{ $catalog_data{pg_namespace} }) +{ + $namespaceoids{ $row->{nspname} } = $row->{oid}; +} # opclass OID lookup my %opcoids; diff --git a/src/include/catalog/pg_authid.dat b/src/include/catalog/pg_authid.dat index a643a09588abd..87d917ffc3843 100644 --- a/src/include/catalog/pg_authid.dat +++ b/src/include/catalog/pg_authid.dat @@ -15,6 +15,10 @@ # The C code typically refers to these roles using the #define symbols, # so make sure every entry has an oid_symbol value. +# The bootstrap superuser is named POSTGRES according to this data and +# according to BKI_DEFAULT entries in other catalogs. However, initdb +# will replace that at database initialization time. + { oid => '10', oid_symbol => 'BOOTSTRAP_SUPERUSERID', rolname => 'POSTGRES', rolsuper => 't', rolinherit => 't', rolcreaterole => 't', rolcreatedb => 't', rolcanlogin => 't', diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h index bb6938caa23fd..3e377294361ca 100644 --- a/src/include/catalog/pg_class.h +++ b/src/include/catalog/pg_class.h @@ -38,7 +38,7 @@ CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,Relat NameData relname; /* OID of namespace containing this class */ - Oid relnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace); + Oid relnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace); /* OID of entry in pg_type for relation's implicit row type, if any */ Oid reltype BKI_LOOKUP_OPT(pg_type); @@ -47,7 +47,7 @@ CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,Relat Oid reloftype BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_type); /* class owner */ - Oid relowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); + Oid relowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); /* access method; 0 if not a table / index */ Oid relam BKI_DEFAULT(heap) BKI_LOOKUP_OPT(pg_am); diff --git a/src/include/catalog/pg_collation.h b/src/include/catalog/pg_collation.h index 3bd7873c6885f..c6394ca222165 100644 --- a/src/include/catalog/pg_collation.h +++ b/src/include/catalog/pg_collation.h @@ -30,9 +30,12 @@ CATALOG(pg_collation,3456,CollationRelationId) { Oid oid; /* oid */ NameData collname; /* collation name */ - Oid collnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace); /* OID of namespace - * containing collation */ - Oid collowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); /* owner of collation */ + + /* OID of namespace containing this collation */ + Oid collnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace); + + /* owner of collation */ + Oid collowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); char collprovider; /* see constants below */ bool collisdeterministic BKI_DEFAULT(t); int32 collencoding; /* encoding for this collation; -1 = "all" */ diff --git a/src/include/catalog/pg_conversion.h b/src/include/catalog/pg_conversion.h index 96bb92f251b1e..ca556f6030f0d 100644 --- a/src/include/catalog/pg_conversion.h +++ b/src/include/catalog/pg_conversion.h @@ -35,10 +35,10 @@ CATALOG(pg_conversion,2607,ConversionRelationId) NameData conname; /* namespace that the conversion belongs to */ - Oid connamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace); + Oid connamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace); /* owner of the conversion */ - Oid conowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); + Oid conowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); /* FOR encoding id */ int32 conforencoding BKI_LOOKUP(encoding); diff --git a/src/include/catalog/pg_database.h b/src/include/catalog/pg_database.h index f0240c58cf1a3..d3de45821c2f9 100644 --- a/src/include/catalog/pg_database.h +++ b/src/include/catalog/pg_database.h @@ -35,7 +35,7 @@ CATALOG(pg_database,1262,DatabaseRelationId) BKI_SHARED_RELATION BKI_ROWTYPE_OID NameData datname; /* owner of database */ - Oid datdba BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); + Oid datdba BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); /* character encoding */ int32 encoding; diff --git a/src/include/catalog/pg_language.h b/src/include/catalog/pg_language.h index e9df9dac09f30..3e56597ece7f1 100644 --- a/src/include/catalog/pg_language.h +++ b/src/include/catalog/pg_language.h @@ -34,7 +34,7 @@ CATALOG(pg_language,2612,LanguageRelationId) NameData lanname; /* Language's owner */ - Oid lanowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); + Oid lanowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); /* Is a procedural language */ bool lanispl BKI_DEFAULT(f); diff --git a/src/include/catalog/pg_namespace.h b/src/include/catalog/pg_namespace.h index d920c6cfc64a3..fe87a947ee792 100644 --- a/src/include/catalog/pg_namespace.h +++ b/src/include/catalog/pg_namespace.h @@ -37,7 +37,7 @@ CATALOG(pg_namespace,2615,NamespaceRelationId) Oid oid; /* oid */ NameData nspname; - Oid nspowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); + Oid nspowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); #ifdef CATALOG_VARLEN /* variable-length fields start here */ aclitem nspacl[1]; diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h index 9f321f2a85ce5..7b2cf259208ad 100644 --- a/src/include/catalog/pg_opclass.h +++ b/src/include/catalog/pg_opclass.h @@ -57,10 +57,10 @@ CATALOG(pg_opclass,2616,OperatorClassRelationId) NameData opcname; /* namespace of this opclass */ - Oid opcnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace); + Oid opcnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace); /* opclass owner */ - Oid opcowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); + Oid opcowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); /* containing operator family */ Oid opcfamily BKI_LOOKUP(pg_opfamily); diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h index 7f06abaeec1ef..d32fcdc64e6f9 100644 --- a/src/include/catalog/pg_operator.h +++ b/src/include/catalog/pg_operator.h @@ -36,10 +36,10 @@ CATALOG(pg_operator,2617,OperatorRelationId) NameData oprname; /* OID of namespace containing this oper */ - Oid oprnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace); + Oid oprnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace); /* operator owner */ - Oid oprowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); + Oid oprowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); /* 'l' for prefix or 'b' for infix */ char oprkind BKI_DEFAULT(b); diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h index 1a723b76f6392..129102b57679d 100644 --- a/src/include/catalog/pg_opfamily.h +++ b/src/include/catalog/pg_opfamily.h @@ -37,10 +37,10 @@ CATALOG(pg_opfamily,2753,OperatorFamilyRelationId) NameData opfname; /* namespace of this opfamily */ - Oid opfnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace); + Oid opfnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace); /* opfamily owner */ - Oid opfowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); + Oid opfowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); } FormData_pg_opfamily; /* ---------------- diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 2f54aa171edd2..78f230894bd33 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -35,10 +35,10 @@ CATALOG(pg_proc,1255,ProcedureRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(81,Proce NameData proname; /* OID of namespace containing this proc */ - Oid pronamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace); + Oid pronamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace); /* procedure owner */ - Oid proowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); + Oid proowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); /* OID of pg_language entry */ Oid prolang BKI_DEFAULT(internal) BKI_LOOKUP(pg_language); diff --git a/src/include/catalog/pg_tablespace.h b/src/include/catalog/pg_tablespace.h index ed38e6950ddcb..58bb1087a3e8e 100644 --- a/src/include/catalog/pg_tablespace.h +++ b/src/include/catalog/pg_tablespace.h @@ -30,7 +30,9 @@ CATALOG(pg_tablespace,1213,TableSpaceRelationId) BKI_SHARED_RELATION { Oid oid; /* oid */ NameData spcname; /* tablespace name */ - Oid spcowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); /* owner of tablespace */ + + /* owner of tablespace */ + Oid spcowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); #ifdef CATALOG_VARLEN /* variable-length fields start here */ aclitem spcacl[1]; /* access permissions */ diff --git a/src/include/catalog/pg_ts_config.h b/src/include/catalog/pg_ts_config.h index e705899b179e0..2e0263962df3b 100644 --- a/src/include/catalog/pg_ts_config.h +++ b/src/include/catalog/pg_ts_config.h @@ -36,10 +36,10 @@ CATALOG(pg_ts_config,3602,TSConfigRelationId) NameData cfgname; /* name space */ - Oid cfgnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace); + Oid cfgnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace); /* owner */ - Oid cfgowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); + Oid cfgowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); /* OID of parser */ Oid cfgparser BKI_LOOKUP(pg_ts_parser); diff --git a/src/include/catalog/pg_ts_dict.h b/src/include/catalog/pg_ts_dict.h index 57f626e7b592c..e53eead82901b 100644 --- a/src/include/catalog/pg_ts_dict.h +++ b/src/include/catalog/pg_ts_dict.h @@ -35,10 +35,10 @@ CATALOG(pg_ts_dict,3600,TSDictionaryRelationId) NameData dictname; /* name space */ - Oid dictnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace); + Oid dictnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace); /* owner */ - Oid dictowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); + Oid dictowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); /* dictionary's template */ Oid dicttemplate BKI_LOOKUP(pg_ts_template); diff --git a/src/include/catalog/pg_ts_parser.h b/src/include/catalog/pg_ts_parser.h index e0d705fd9ae57..0231051cee38f 100644 --- a/src/include/catalog/pg_ts_parser.h +++ b/src/include/catalog/pg_ts_parser.h @@ -34,7 +34,7 @@ CATALOG(pg_ts_parser,3601,TSParserRelationId) NameData prsname; /* name space */ - Oid prsnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace); + Oid prsnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace); /* init parsing session */ regproc prsstart BKI_LOOKUP(pg_proc); diff --git a/src/include/catalog/pg_ts_template.h b/src/include/catalog/pg_ts_template.h index 2ee1ae4e85f62..194b921136209 100644 --- a/src/include/catalog/pg_ts_template.h +++ b/src/include/catalog/pg_ts_template.h @@ -34,7 +34,7 @@ CATALOG(pg_ts_template,3764,TSTemplateRelationId) NameData tmplname; /* name space */ - Oid tmplnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace); + Oid tmplnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace); /* initialization method of dict (may be 0) */ regproc tmplinit BKI_LOOKUP_OPT(pg_proc); diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index 1ec8606703811..8ee5fa0507a37 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -41,10 +41,10 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati NameData typname; /* OID of namespace containing this type */ - Oid typnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace); + Oid typnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace); /* type owner */ - Oid typowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); + Oid typowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); /* * For a fixed-size type, typlen is the number of bytes we use to From 2c8726c4b0a496608919d1f78a5abc8c9b6e0868 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Wed, 3 Feb 2021 13:19:41 -0500 Subject: [PATCH 240/240] Factor pattern-construction logic out of processSQLNamePattern. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The logic for converting the shell-glob-like syntax supported by utilities like psql and pg_dump to regular expression is extracted into a new function patternToSQLRegex. The existing function processSQLNamePattern now uses this function as a subroutine. patternToSQLRegex is a little more general than what is required by processSQLNamePattern. That function is only interested in patterns that can have up to 2 parts, a schema and a relation; but patternToSQLRegex can limit the maximum number of parts to between 1 and 3, so that patterns can look like either "database.schema.relation", "schema.relation", or "relation" depending on how it's invoked and what the user specifies. processSQLNamePattern only passes two buffers, so works exactly the same as before, always interpreting the pattern as either a "schema.relation" pattern or a "relation" pattern. But, future callers can use this function in other ways. Mark Dilger, reviewed by me. The larger patch series of which this is a part has also had review from Peter Geoghegan, Andres Freund, Álvaro Herrera, Michael Paquier, and Amul Sul, but I don't know whether any of them have reviewed this bit specifically. Discussion: http://postgr.es/m/12ED3DA8-25F0-4B68-937D-D907CFBF08E7@enterprisedb.com Discussion: http://postgr.es/m/5F743835-3399-419C-8324-2D424237E999@enterprisedb.com Discussion: http://postgr.es/m/70655DF3-33CE-4527-9A4D-DDEB582B6BA0@enterprisedb.com --- src/fe_utils/string_utils.c | 260 +++++++++++++++++----------- src/include/fe_utils/string_utils.h | 4 + 2 files changed, 167 insertions(+), 97 deletions(-) diff --git a/src/fe_utils/string_utils.c b/src/fe_utils/string_utils.c index a1a9d691d5b27..9a1ea9ab98b0b 100644 --- a/src/fe_utils/string_utils.c +++ b/src/fe_utils/string_utils.c @@ -831,10 +831,6 @@ processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, { PQExpBufferData schemabuf; PQExpBufferData namebuf; - int encoding = PQclientEncoding(conn); - bool inquotes; - const char *cp; - int i; bool added_clause = false; #define WHEREAND() \ @@ -856,98 +852,12 @@ processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, initPQExpBuffer(&namebuf); /* - * Parse the pattern, converting quotes and lower-casing unquoted letters. - * Also, adjust shell-style wildcard characters into regexp notation. - * - * We surround the pattern with "^(...)$" to force it to match the whole - * string, as per SQL practice. We have to have parens in case the string - * contains "|", else the "^" and "$" will be bound into the first and - * last alternatives which is not what we want. - * - * Note: the result of this pass is the actual regexp pattern(s) we want - * to execute. Quoting/escaping into SQL literal format will be done - * below using appendStringLiteralConn(). + * Convert shell-style 'pattern' into the regular expression(s) we want to + * execute. Quoting/escaping into SQL literal format will be done below + * using appendStringLiteralConn(). */ - appendPQExpBufferStr(&namebuf, "^("); - - inquotes = false; - cp = pattern; - - while (*cp) - { - char ch = *cp; - - if (ch == '"') - { - if (inquotes && cp[1] == '"') - { - /* emit one quote, stay in inquotes mode */ - appendPQExpBufferChar(&namebuf, '"'); - cp++; - } - else - inquotes = !inquotes; - cp++; - } - else if (!inquotes && isupper((unsigned char) ch)) - { - appendPQExpBufferChar(&namebuf, - pg_tolower((unsigned char) ch)); - cp++; - } - else if (!inquotes && ch == '*') - { - appendPQExpBufferStr(&namebuf, ".*"); - cp++; - } - else if (!inquotes && ch == '?') - { - appendPQExpBufferChar(&namebuf, '.'); - cp++; - } - else if (!inquotes && ch == '.') - { - /* Found schema/name separator, move current pattern to schema */ - resetPQExpBuffer(&schemabuf); - appendPQExpBufferStr(&schemabuf, namebuf.data); - resetPQExpBuffer(&namebuf); - appendPQExpBufferStr(&namebuf, "^("); - cp++; - } - else if (ch == '$') - { - /* - * Dollar is always quoted, whether inside quotes or not. The - * reason is that it's allowed in SQL identifiers, so there's a - * significant use-case for treating it literally, while because - * we anchor the pattern automatically there is no use-case for - * having it possess its regexp meaning. - */ - appendPQExpBufferStr(&namebuf, "\\$"); - cp++; - } - else - { - /* - * Ordinary data character, transfer to pattern - * - * Inside double quotes, or at all times if force_escape is true, - * quote regexp special characters with a backslash to avoid - * regexp errors. Outside quotes, however, let them pass through - * as-is; this lets knowledgeable users build regexp expressions - * that are more powerful than shell-style patterns. - */ - if ((inquotes || force_escape) && - strchr("|*+?()[]{}.^$\\", ch)) - appendPQExpBufferChar(&namebuf, '\\'); - i = PQmblen(cp, encoding); - while (i-- && *cp) - { - appendPQExpBufferChar(&namebuf, *cp); - cp++; - } - } - } + patternToSQLRegex(PQclientEncoding(conn), NULL, &schemabuf, &namebuf, + pattern, force_escape); /* * Now decide what we need to emit. We may run under a hostile @@ -964,7 +874,6 @@ processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, { /* We have a name pattern, so constrain the namevar(s) */ - appendPQExpBufferStr(&namebuf, ")$"); /* Optimize away a "*" pattern */ if (strcmp(namebuf.data, "^(.*)$") != 0) { @@ -999,7 +908,6 @@ processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, { /* We have a schema pattern, so constrain the schemavar */ - appendPQExpBufferStr(&schemabuf, ")$"); /* Optimize away a "*" pattern */ if (strcmp(schemabuf.data, "^(.*)$") != 0 && schemavar) { @@ -1027,3 +935,161 @@ processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, return added_clause; #undef WHEREAND } + +/* + * Transform a possibly qualified shell-style object name pattern into up to + * three SQL-style regular expressions, converting quotes, lower-casing + * unquoted letters, and adjusting shell-style wildcard characters into regexp + * notation. + * + * If the dbnamebuf and schemabuf arguments are non-NULL, and the pattern + * contains two or more dbname/schema/name separators, we parse the portions of + * the pattern prior to the first and second separators into dbnamebuf and + * schemabuf, and the rest into namebuf. (Additional dots in the name portion + * are not treated as special.) + * + * If dbnamebuf is NULL and schemabuf is non-NULL, and the pattern contains at + * least one separator, we parse the first portion into schemabuf and the rest + * into namebuf. + * + * Otherwise, we parse all the pattern into namebuf. + * + * We surround the regexps with "^(...)$" to force them to match whole strings, + * as per SQL practice. We have to have parens in case strings contain "|", + * else the "^" and "$" will be bound into the first and last alternatives + * which is not what we want. + * + * The regexps we parse into the buffers are appended to the data (if any) + * already present. If we parse fewer fields than the number of buffers we + * were given, the extra buffers are unaltered. + */ +void +patternToSQLRegex(int encoding, PQExpBuffer dbnamebuf, PQExpBuffer schemabuf, + PQExpBuffer namebuf, const char *pattern, bool force_escape) +{ + PQExpBufferData buf[3]; + PQExpBuffer curbuf; + PQExpBuffer maxbuf; + int i; + bool inquotes; + const char *cp; + + Assert(pattern != NULL); + Assert(namebuf != NULL); + + /* callers should never expect "dbname.relname" format */ + Assert(dbnamebuf == NULL || schemabuf != NULL); + + inquotes = false; + cp = pattern; + + if (dbnamebuf != NULL) + maxbuf = &buf[2]; + else if (schemabuf != NULL) + maxbuf = &buf[1]; + else + maxbuf = &buf[0]; + + curbuf = &buf[0]; + initPQExpBuffer(curbuf); + appendPQExpBufferStr(curbuf, "^("); + while (*cp) + { + char ch = *cp; + + if (ch == '"') + { + if (inquotes && cp[1] == '"') + { + /* emit one quote, stay in inquotes mode */ + appendPQExpBufferChar(curbuf, '"'); + cp++; + } + else + inquotes = !inquotes; + cp++; + } + else if (!inquotes && isupper((unsigned char) ch)) + { + appendPQExpBufferChar(curbuf, + pg_tolower((unsigned char) ch)); + cp++; + } + else if (!inquotes && ch == '*') + { + appendPQExpBufferStr(curbuf, ".*"); + cp++; + } + else if (!inquotes && ch == '?') + { + appendPQExpBufferChar(curbuf, '.'); + cp++; + } + + /* + * When we find a dbname/schema/name separator, we treat it specially + * only if the caller requested more patterns to be parsed than we + * have already parsed from the pattern. Otherwise, dot characters + * are not special. + */ + else if (!inquotes && ch == '.' && curbuf < maxbuf) + { + appendPQExpBufferStr(curbuf, ")$"); + curbuf++; + initPQExpBuffer(curbuf); + appendPQExpBufferStr(curbuf, "^("); + cp++; + } + else if (ch == '$') + { + /* + * Dollar is always quoted, whether inside quotes or not. The + * reason is that it's allowed in SQL identifiers, so there's a + * significant use-case for treating it literally, while because + * we anchor the pattern automatically there is no use-case for + * having it possess its regexp meaning. + */ + appendPQExpBufferStr(curbuf, "\\$"); + cp++; + } + else + { + /* + * Ordinary data character, transfer to pattern + * + * Inside double quotes, or at all times if force_escape is true, + * quote regexp special characters with a backslash to avoid + * regexp errors. Outside quotes, however, let them pass through + * as-is; this lets knowledgeable users build regexp expressions + * that are more powerful than shell-style patterns. + */ + if ((inquotes || force_escape) && + strchr("|*+?()[]{}.^$\\", ch)) + appendPQExpBufferChar(curbuf, '\\'); + i = PQmblen(cp, encoding); + while (i-- && *cp) + { + appendPQExpBufferChar(curbuf, *cp); + cp++; + } + } + } + appendPQExpBufferStr(curbuf, ")$"); + + appendPQExpBufferStr(namebuf, curbuf->data); + termPQExpBuffer(curbuf); + + if (curbuf > buf) + { + curbuf--; + appendPQExpBufferStr(schemabuf, curbuf->data); + termPQExpBuffer(curbuf); + + if (curbuf > buf) + { + curbuf--; + appendPQExpBufferStr(dbnamebuf, curbuf->data); + termPQExpBuffer(curbuf); + } + } +} diff --git a/src/include/fe_utils/string_utils.h b/src/include/fe_utils/string_utils.h index c290c302f572e..caafb97d2937e 100644 --- a/src/include/fe_utils/string_utils.h +++ b/src/include/fe_utils/string_utils.h @@ -56,4 +56,8 @@ extern bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule); +extern void patternToSQLRegex(int encoding, PQExpBuffer dbnamebuf, + PQExpBuffer schemabuf, PQExpBuffer namebuf, + const char *pattern, bool force_escape); + #endif /* STRING_UTILS_H */