diff --git a/config/general.m4 b/config/general.m4 index 95d65ceb093d..140b9737bfbc 100644 --- a/config/general.m4 +++ b/config/general.m4 @@ -8,7 +8,7 @@ # argument (other than "yes/no"), etc. # # The point of this implementation is to reduce code size and -# redundancy in configure.in and to improve robustness and consistency +# redundancy in configure.ac and to improve robustness and consistency # in the option evaluation code. diff --git a/configure b/configure index 2c00961de0ba..81c38886d1df 100755 --- a/configure +++ b/configure @@ -5771,6 +5771,97 @@ if test x"$pgac_cv_prog_CXX_cxxflags__Wimplicit_fallthrough_3" = x"yes"; then fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC} supports -Wcast-function-type, for CFLAGS" >&5 +$as_echo_n "checking whether ${CC} supports -Wcast-function-type, for CFLAGS... " >&6; } +if ${pgac_cv_prog_CC_cflags__Wcast_function_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + pgac_save_CFLAGS=$CFLAGS +pgac_save_CC=$CC +CC=${CC} +CFLAGS="${CFLAGS} -Wcast-function-type" +ac_save_c_werror_flag=$ac_c_werror_flag +ac_c_werror_flag=yes +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + pgac_cv_prog_CC_cflags__Wcast_function_type=yes +else + pgac_cv_prog_CC_cflags__Wcast_function_type=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_c_werror_flag=$ac_save_c_werror_flag +CFLAGS="$pgac_save_CFLAGS" +CC="$pgac_save_CC" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_prog_CC_cflags__Wcast_function_type" >&5 +$as_echo "$pgac_cv_prog_CC_cflags__Wcast_function_type" >&6; } +if test x"$pgac_cv_prog_CC_cflags__Wcast_function_type" = x"yes"; then + CFLAGS="${CFLAGS} -Wcast-function-type" +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CXX} supports -Wcast-function-type, for CXXFLAGS" >&5 +$as_echo_n "checking whether ${CXX} supports -Wcast-function-type, for CXXFLAGS... " >&6; } +if ${pgac_cv_prog_CXX_cxxflags__Wcast_function_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + pgac_save_CXXFLAGS=$CXXFLAGS +pgac_save_CXX=$CXX +CXX=${CXX} +CXXFLAGS="${CXXFLAGS} -Wcast-function-type" +ac_save_cxx_werror_flag=$ac_cxx_werror_flag +ac_cxx_werror_flag=yes +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + pgac_cv_prog_CXX_cxxflags__Wcast_function_type=yes +else + pgac_cv_prog_CXX_cxxflags__Wcast_function_type=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_cxx_werror_flag=$ac_save_cxx_werror_flag +CXXFLAGS="$pgac_save_CXXFLAGS" +CXX="$pgac_save_CXX" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_prog_CXX_cxxflags__Wcast_function_type" >&5 +$as_echo "$pgac_cv_prog_CXX_cxxflags__Wcast_function_type" >&6; } +if test x"$pgac_cv_prog_CXX_cxxflags__Wcast_function_type" = x"yes"; then + CXXFLAGS="${CXXFLAGS} -Wcast-function-type" +fi + + # This was included in -Wall/-Wformat in older GCC versions { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC} supports -Wformat-security, for CFLAGS" >&5 @@ -13786,7 +13877,11 @@ fi fi if test "$with_openssl" = yes ; then - if test "$PORTNAME" != "win32"; then + # Minimum required OpenSSL version is 1.0.1 + +$as_echo "#define OPENSSL_API_COMPAT 0x10001000L" >>confdefs.h + + if test "$PORTNAME" != "win32"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CRYPTO_new_ex_data in -lcrypto" >&5 $as_echo_n "checking for CRYPTO_new_ex_data in -lcrypto... " >&6; } if ${ac_cv_lib_crypto_CRYPTO_new_ex_data+:} false; then : diff --git a/configure.in b/configure.ac similarity index 99% rename from configure.in rename to configure.ac index f7a216b15ccb..c545328648ac 100644 --- a/configure.in +++ b/configure.ac @@ -1,5 +1,5 @@ dnl Process this file with autoconf to produce a configure script. -dnl configure.in +dnl configure.ac dnl dnl Developers, please strive to achieve this order: dnl @@ -26,7 +26,7 @@ AC_SUBST(PG_PACKAGE_VERSION) dnl m4_if(m4_defn([m4_PACKAGE_VERSION]), [2.69], [], [m4_fatal([Autoconf version 2.69 is required. dnl Untested combinations of 'autoconf' and PostgreSQL versions are not -dnl recommended. You can remove the check from 'configure.in' but it is then +dnl recommended. You can remove the check from 'configure.ac' but it is then dnl your responsibility whether the result works or not.])]) AC_COPYRIGHT([Copyright (c) 1996-2020, PostgreSQL Global Development Group]) AC_CONFIG_SRCDIR([src/backend/access/common/heaptuple.c]) @@ -541,6 +541,8 @@ if test "$GCC" = yes -a "$ICC" = no; then PGAC_PROG_CXX_CFLAGS_OPT([-Wmissing-format-attribute]) PGAC_PROG_CC_CFLAGS_OPT([-Wimplicit-fallthrough=3]) PGAC_PROG_CXX_CFLAGS_OPT([-Wimplicit-fallthrough=3]) + PGAC_PROG_CC_CFLAGS_OPT([-Wcast-function-type]) + PGAC_PROG_CXX_CFLAGS_OPT([-Wcast-function-type]) # This was included in -Wall/-Wformat in older GCC versions PGAC_PROG_CC_CFLAGS_OPT([-Wformat-security]) PGAC_PROG_CXX_CFLAGS_OPT([-Wformat-security]) @@ -1437,6 +1439,9 @@ fi if test "$with_openssl" = yes ; then dnl Order matters! + # Minimum required OpenSSL version is 1.0.1 + AC_DEFINE(OPENSSL_API_COMPAT, [0x10001000L], + [Define to the OpenSSL API version in use. This avoids deprecation warnings from newer OpenSSL versions.]) if test "$PORTNAME" != "win32"; then AC_CHECK_LIB(crypto, CRYPTO_new_ex_data, [], [AC_MSG_ERROR([library 'crypto' is required for OpenSSL])]) AC_CHECK_LIB(ssl, SSL_new, [], [AC_MSG_ERROR([library 'ssl' is required for OpenSSL])]) diff --git a/contrib/adminpack/expected/adminpack.out b/contrib/adminpack/expected/adminpack.out index 5738b0f6c4dd..edf3ebfcba3d 100644 --- a/contrib/adminpack/expected/adminpack.out +++ b/contrib/adminpack/expected/adminpack.out @@ -79,7 +79,7 @@ SELECT pg_file_rename('test_file1', 'test_file2'); (1 row) SELECT pg_read_file('test_file1'); -- not there -ERROR: could not stat file "test_file1": No such file or directory +ERROR: could not open file "test_file1" for reading: No such file or directory SELECT pg_read_file('test_file2'); pg_read_file -------------- @@ -108,7 +108,7 @@ SELECT pg_file_rename('test_file2', 'test_file3', 'test_file3_archive'); (1 row) SELECT pg_read_file('test_file2'); -- not there -ERROR: could not stat file "test_file2": No such file or directory +ERROR: could not open file "test_file2" for reading: No such file or directory SELECT pg_read_file('test_file3'); pg_read_file -------------- diff --git a/contrib/amcheck/expected/check_btree.out b/contrib/amcheck/expected/check_btree.out index f82f48d23b78..13848b7449b7 100644 --- a/contrib/amcheck/expected/check_btree.out +++ b/contrib/amcheck/expected/check_btree.out @@ -155,11 +155,19 @@ SELECT bt_index_parent_check('delete_test_table_pkey', true); -- tuple. Bloom filter must fingerprint normalized index tuple representation. -- CREATE TABLE toast_bug(buggy text); -ALTER TABLE toast_bug ALTER COLUMN buggy SET STORAGE plain; --- pg_attribute entry for toasty.buggy will have plain storage: -CREATE INDEX toasty ON toast_bug(buggy); --- Whereas pg_attribute entry for toast_bug.buggy now has extended storage: ALTER TABLE toast_bug ALTER COLUMN buggy SET STORAGE extended; +CREATE INDEX toasty ON toast_bug(buggy); +-- pg_attribute entry for toasty.buggy (the index) will have plain storage: +UPDATE pg_attribute SET attstorage = 'p' +WHERE attrelid = 'toasty'::regclass AND attname = 'buggy'; +-- Whereas pg_attribute entry for toast_bug.buggy (the table) still has extended storage: +SELECT attstorage FROM pg_attribute +WHERE attrelid = 'toast_bug'::regclass AND attname = 'buggy'; + attstorage +------------ + x +(1 row) + -- Insert compressible heap tuple (comfortably exceeds TOAST_TUPLE_THRESHOLD): INSERT INTO toast_bug SELECT repeat('a', 2200); -- Should not get false positive report of corruption: diff --git a/contrib/amcheck/sql/check_btree.sql b/contrib/amcheck/sql/check_btree.sql index a1fef644cb08..97a3e1a20d50 100644 --- a/contrib/amcheck/sql/check_btree.sql +++ b/contrib/amcheck/sql/check_btree.sql @@ -99,11 +99,17 @@ SELECT bt_index_parent_check('delete_test_table_pkey', true); -- tuple. Bloom filter must fingerprint normalized index tuple representation. -- CREATE TABLE toast_bug(buggy text); -ALTER TABLE toast_bug ALTER COLUMN buggy SET STORAGE plain; --- pg_attribute entry for toasty.buggy will have plain storage: -CREATE INDEX toasty ON toast_bug(buggy); --- Whereas pg_attribute entry for toast_bug.buggy now has extended storage: ALTER TABLE toast_bug ALTER COLUMN buggy SET STORAGE extended; +CREATE INDEX toasty ON toast_bug(buggy); + +-- pg_attribute entry for toasty.buggy (the index) will have plain storage: +UPDATE pg_attribute SET attstorage = 'p' +WHERE attrelid = 'toasty'::regclass AND attname = 'buggy'; + +-- Whereas pg_attribute entry for toast_bug.buggy (the table) still has extended storage: +SELECT attstorage FROM pg_attribute +WHERE attrelid = 'toast_bug'::regclass AND attname = 'buggy'; + -- Insert compressible heap tuple (comfortably exceeds TOAST_TUPLE_THRESHOLD): INSERT INTO toast_bug SELECT repeat('a', 2200); -- Should not get false positive report of corruption: diff --git a/contrib/amcheck/verify_nbtree.c b/contrib/amcheck/verify_nbtree.c index e4d501a85d1f..5f3de3c0b7f6 100644 --- a/contrib/amcheck/verify_nbtree.c +++ b/contrib/amcheck/verify_nbtree.c @@ -145,6 +145,9 @@ static void bt_check_every_level(Relation rel, Relation heaprel, bool rootdescend); static BtreeLevel bt_check_level_from_leftmost(BtreeCheckState *state, BtreeLevel level); +static void bt_recheck_sibling_links(BtreeCheckState *state, + BlockNumber btpo_prev_from_target, + BlockNumber leftcurrent); static void bt_target_page_check(BtreeCheckState *state); static BTScanInsert bt_right_page_check_scankey(BtreeCheckState *state); static void bt_child_check(BtreeCheckState *state, BTScanInsert targetkey, @@ -305,8 +308,20 @@ bt_index_check_internal(Oid indrelid, bool parentcheck, bool heapallindexed, errmsg("index \"%s\" lacks a main relation fork", RelationGetRelationName(indrel)))); - /* Check index, possibly against table it is an index on */ + /* Extract metadata from metapage, and sanitize it in passing */ _bt_metaversion(indrel, &heapkeyspace, &allequalimage); + if (allequalimage && !heapkeyspace) + ereport(ERROR, + (errcode(ERRCODE_INDEX_CORRUPTED), + errmsg("index \"%s\" metapage has equalimage field set on unsupported nbtree version", + RelationGetRelationName(indrel)))); + if (allequalimage && !_bt_allequalimage(indrel, false)) + ereport(ERROR, + (errcode(ERRCODE_INDEX_CORRUPTED), + errmsg("index \"%s\" metapage incorrectly indicates that deduplication is safe", + RelationGetRelationName(indrel)))); + + /* Check index, possibly against table it is an index on */ bt_check_every_level(indrel, heaprel, heapkeyspace, parentcheck, heapallindexed, rootdescend); } @@ -419,10 +434,10 @@ bt_check_every_level(Relation rel, Relation heaprel, bool heapkeyspace, RelationGetRelationName(rel)); /* - * RecentGlobalXmin assertion matches index_getnext_tid(). See note on - * RecentGlobalXmin/B-Tree page deletion. + * This assertion matches the one in index_getnext_tid(). See page + * recycling/"visible to everyone" notes in nbtree README. */ - Assert(TransactionIdIsValid(RecentGlobalXmin)); + Assert(TransactionIdIsValid(RecentXmin)); /* * Initialize state for entire verification operation @@ -775,17 +790,9 @@ bt_check_level_from_leftmost(BtreeCheckState *state, BtreeLevel level) */ } - /* - * readonly mode can only ever land on live pages and half-dead pages, - * so sibling pointers should always be in mutual agreement - */ - if (state->readonly && opaque->btpo_prev != leftcurrent) - ereport(ERROR, - (errcode(ERRCODE_INDEX_CORRUPTED), - errmsg("left link/right link pair in index \"%s\" not in agreement", - RelationGetRelationName(state->rel)), - errdetail_internal("Block=%u left block=%u left link from block=%u.", - current, leftcurrent, opaque->btpo_prev))); + /* Sibling links should be in mutual agreement */ + if (opaque->btpo_prev != leftcurrent) + bt_recheck_sibling_links(state, opaque->btpo_prev, leftcurrent); /* Check level, which must be valid for non-ignorable page */ if (level.level != opaque->btpo.level) @@ -865,6 +872,140 @@ bt_check_level_from_leftmost(BtreeCheckState *state, BtreeLevel level) return nextleveldown; } +/* + * Raise an error when target page's left link does not point back to the + * previous target page, called leftcurrent here. The leftcurrent page's + * right link was followed to get to the current target page, and we expect + * mutual agreement among leftcurrent and the current target page. Make sure + * that this condition has definitely been violated in the !readonly case, + * where concurrent page splits are something that we need to deal with. + * + * Cross-page inconsistencies involving pages that don't agree about being + * siblings are known to be a particularly good indicator of corruption + * involving partial writes/lost updates. The bt_right_page_check_scankey + * check also provides a way of detecting cross-page inconsistencies for + * !readonly callers, but it can only detect sibling pages that have an + * out-of-order keyspace, which can't catch many of the problems that we + * expect to catch here. + * + * The classic example of the kind of inconsistency that we can only catch + * with this check (when in !readonly mode) involves three sibling pages that + * were affected by a faulty page split at some point in the past. The + * effects of the split are reflected in the original page and its new right + * sibling page, with a lack of any accompanying changes for the _original_ + * right sibling page. The original right sibling page's left link fails to + * point to the new right sibling page (its left link still points to the + * original page), even though the first phase of a page split is supposed to + * work as a single atomic action. This subtle inconsistency will probably + * only break backwards scans in practice. + * + * Note that this is the only place where amcheck will "couple" buffer locks + * (and only for !readonly callers). In general we prefer to avoid more + * thorough cross-page checks in !readonly mode, but it seems worth the + * complexity here. Also, the performance overhead of performing lock + * coupling here is negligible in practice. Control only reaches here with a + * non-corrupt index when there is a concurrent page split at the instant + * caller crossed over to target page from leftcurrent page. + */ +static void +bt_recheck_sibling_links(BtreeCheckState *state, + BlockNumber btpo_prev_from_target, + BlockNumber leftcurrent) +{ + if (!state->readonly) + { + Buffer lbuf; + Buffer newtargetbuf; + Page page; + BTPageOpaque opaque; + BlockNumber newtargetblock; + + /* Couple locks in the usual order for nbtree: Left to right */ + lbuf = ReadBufferExtended(state->rel, MAIN_FORKNUM, leftcurrent, + RBM_NORMAL, state->checkstrategy); + LockBuffer(lbuf, BT_READ); + _bt_checkpage(state->rel, lbuf); + page = BufferGetPage(lbuf); + opaque = (BTPageOpaque) PageGetSpecialPointer(page); + if (P_ISDELETED(opaque)) + { + /* + * Cannot reason about concurrently deleted page -- the left link + * in the page to the right is expected to point to some other + * page to the left (not leftcurrent page). + * + * Note that we deliberately don't give up with a half-dead page. + */ + UnlockReleaseBuffer(lbuf); + return; + } + + newtargetblock = opaque->btpo_next; + /* Avoid self-deadlock when newtargetblock == leftcurrent */ + if (newtargetblock != leftcurrent) + { + newtargetbuf = ReadBufferExtended(state->rel, MAIN_FORKNUM, + newtargetblock, RBM_NORMAL, + state->checkstrategy); + LockBuffer(newtargetbuf, BT_READ); + _bt_checkpage(state->rel, newtargetbuf); + page = BufferGetPage(newtargetbuf); + opaque = (BTPageOpaque) PageGetSpecialPointer(page); + /* btpo_prev_from_target may have changed; update it */ + btpo_prev_from_target = opaque->btpo_prev; + } + else + { + /* + * leftcurrent right sibling points back to leftcurrent block. + * Index is corrupt. Easiest way to handle this is to pretend + * that we actually read from a distinct page that has an invalid + * block number in its btpo_prev. + */ + newtargetbuf = InvalidBuffer; + btpo_prev_from_target = InvalidBlockNumber; + } + + /* + * No need to check P_ISDELETED here, since new target block cannot be + * marked deleted as long as we hold a lock on lbuf + */ + if (BufferIsValid(newtargetbuf)) + UnlockReleaseBuffer(newtargetbuf); + UnlockReleaseBuffer(lbuf); + + if (btpo_prev_from_target == leftcurrent) + { + /* Report split in left sibling, not target (or new target) */ + ereport(DEBUG1, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("harmless concurrent page split detected in index \"%s\"", + RelationGetRelationName(state->rel)), + errdetail_internal("Block=%u new right sibling=%u original right sibling=%u.", + leftcurrent, newtargetblock, + state->targetblock))); + return; + } + + /* + * Index is corrupt. Make sure that we report correct target page. + * + * This could have changed in cases where there was a concurrent page + * split, as well as index corruption (at least in theory). Note that + * btpo_prev_from_target was already updated above. + */ + state->targetblock = newtargetblock; + } + + ereport(ERROR, + (errcode(ERRCODE_INDEX_CORRUPTED), + errmsg("left link/right link pair in index \"%s\" not in agreement", + RelationGetRelationName(state->rel)), + errdetail_internal("Block=%u left block=%u left link from block=%u.", + state->targetblock, leftcurrent, + btpo_prev_from_target))); +} + /* * Function performs the following checks on target page, or pages ancillary to * target page: @@ -891,7 +1032,6 @@ bt_check_level_from_leftmost(BtreeCheckState *state, BtreeLevel level) * tuple. * * - That downlink to block was encountered in parent where that's expected. - * (Limited to readonly callers.) * * - That high keys of child pages matches corresponding pivot keys in parent. * @@ -1441,7 +1581,7 @@ bt_right_page_check_scankey(BtreeCheckState *state) * does not occur until no possible index scan could land on the page. * Index scans can follow links with nothing more than their snapshot as * an interlock and be sure of at least that much. (See page - * recycling/RecentGlobalXmin notes in nbtree README.) + * recycling/"visible to everyone" notes in nbtree README.) * * Furthermore, it's okay if we follow a rightlink and find a half-dead or * dead (ignorable) page one or more times. There will either be a @@ -1954,18 +2094,14 @@ bt_child_check(BtreeCheckState *state, BTScanInsert targetkey, * downlink, which was concurrently physically removed in target/parent as * part of deletion's first phase.) * - * Note that while the cross-page-same-level last item check uses a trick - * that allows it to perform verification for !readonly callers, a similar - * trick seems difficult here. The trick that that other check uses is, - * in essence, to lock down race conditions to those that occur due to - * concurrent page deletion of the target; that's a race that can be - * reliably detected before actually reporting corruption. - * - * On the other hand, we'd need to lock down race conditions involving - * deletion of child's left page, for long enough to read the child page - * into memory (in other words, a scheme with concurrently held buffer - * locks on both child and left-of-child pages). That's unacceptable for - * amcheck functions on general principle, though. + * While we use various techniques elsewhere to perform cross-page + * verification for !readonly callers, a similar trick seems difficult + * here. The tricks used by bt_recheck_sibling_links and by + * bt_right_page_check_scankey both involve verification of a same-level, + * cross-sibling invariant. Cross-level invariants are far more squishy, + * though. The nbtree REDO routines do not actually couple buffer locks + * across levels during page splits, so making any cross-level check work + * reliably in !readonly mode may be impossible. */ Assert(state->readonly); @@ -2774,6 +2910,8 @@ invariant_l_nontarget_offset(BtreeCheckState *state, BTScanInsert key, * There is never an attempt to get a consistent view of multiple pages using * multiple concurrent buffer locks; in general, we only acquire a single pin * and buffer lock at a time, which is often all that the nbtree code requires. + * (Actually, bt_recheck_sibling_links couples buffer locks, which is the only + * exception to this general rule.) * * Operating on a copy of the page is useful because it prevents control * getting stuck in an uninterruptible state when an underlying operator class @@ -2864,11 +3002,8 @@ palloc_btree_page(BtreeCheckState *state, BlockNumber blocknum) * As noted at the beginning of _bt_binsrch(), an internal page must have * children, since there must always be a negative infinity downlink * (there may also be a highkey). In the case of non-rightmost leaf - * pages, there must be at least a highkey. Deleted pages on replica - * might contain no items, because page unlink re-initializes - * page-to-be-deleted. Deleted pages with no items might be on primary - * too due to preceding recovery, but on primary new deletions can't - * happen concurrently to amcheck. + * pages, there must be at least a highkey. The exceptions are deleted + * pages, which contain no items. * * This is correct when pages are half-dead, since internal pages are * never half-dead, and leaf pages must have a high key when half-dead diff --git a/contrib/bloom/blutils.c b/contrib/bloom/blutils.c index d3bf8665df1f..26b9927c3aaf 100644 --- a/contrib/bloom/blutils.c +++ b/contrib/bloom/blutils.c @@ -139,6 +139,7 @@ blhandler(PG_FUNCTION_ARGS) amroutine->amproperty = NULL; amroutine->ambuildphasename = NULL; amroutine->amvalidate = blvalidate; + amroutine->amadjustmembers = NULL; amroutine->ambeginscan = blbeginscan; amroutine->amrescan = blrescan; amroutine->amgettuple = NULL; diff --git a/contrib/bloom/t/001_wal.pl b/contrib/bloom/t/001_wal.pl index 0f2628b5575f..7f6398f57129 100644 --- a/contrib/bloom/t/001_wal.pl +++ b/contrib/bloom/t/001_wal.pl @@ -5,10 +5,10 @@ use TestLib; use Test::More tests => 31; -my $node_master; +my $node_primary; my $node_standby; -# Run few queries on both master and standby and check their results match. +# Run few queries on both primary and standby and check their results match. sub test_index_replay { my ($test_name) = @_; @@ -17,7 +17,7 @@ sub test_index_replay my $applname = $node_standby->name; my $caughtup_query = "SELECT pg_current_wal_lsn() <= write_lsn FROM pg_stat_replication WHERE application_name = '$applname';"; - $node_master->poll_query_until('postgres', $caughtup_query) + $node_primary->poll_query_until('postgres', $caughtup_query) or die "Timed out while waiting for standby 1 to catch up"; my $queries = qq(SET enable_seqscan=off; @@ -32,35 +32,35 @@ sub test_index_replay ); # Run test queries and compare their result - my $master_result = $node_master->safe_psql("postgres", $queries); + my $primary_result = $node_primary->safe_psql("postgres", $queries); my $standby_result = $node_standby->safe_psql("postgres", $queries); - is($master_result, $standby_result, "$test_name: query result matches"); + is($primary_result, $standby_result, "$test_name: query result matches"); return; } -# Initialize master node -$node_master = get_new_node('master'); -$node_master->init(allows_streaming => 1); -$node_master->start; +# Initialize primary node +$node_primary = get_new_node('primary'); +$node_primary->init(allows_streaming => 1); +$node_primary->start; my $backup_name = 'my_backup'; # Take backup -$node_master->backup($backup_name); +$node_primary->backup($backup_name); -# Create streaming standby linking to master +# Create streaming standby linking to primary $node_standby = get_new_node('standby'); -$node_standby->init_from_backup($node_master, $backup_name, +$node_standby->init_from_backup($node_primary, $backup_name, has_streaming => 1); $node_standby->start; -# Create some bloom index on master -$node_master->safe_psql("postgres", "CREATE EXTENSION bloom;"); -$node_master->safe_psql("postgres", "CREATE TABLE tst (i int4, t text);"); -$node_master->safe_psql("postgres", +# Create some bloom index on primary +$node_primary->safe_psql("postgres", "CREATE EXTENSION bloom;"); +$node_primary->safe_psql("postgres", "CREATE TABLE tst (i int4, t text);"); +$node_primary->safe_psql("postgres", "INSERT INTO tst SELECT i%10, substr(md5(i::text), 1, 1) FROM generate_series(1,100000) i;" ); -$node_master->safe_psql("postgres", +$node_primary->safe_psql("postgres", "CREATE INDEX bloomidx ON tst USING bloom (i, t) WITH (col1 = 3);"); # Test that queries give same result @@ -69,12 +69,12 @@ sub test_index_replay # Run 10 cycles of table modification. Run test queries after each modification. for my $i (1 .. 10) { - $node_master->safe_psql("postgres", "DELETE FROM tst WHERE i = $i;"); + $node_primary->safe_psql("postgres", "DELETE FROM tst WHERE i = $i;"); test_index_replay("delete $i"); - $node_master->safe_psql("postgres", "VACUUM tst;"); + $node_primary->safe_psql("postgres", "VACUUM tst;"); test_index_replay("vacuum $i"); my ($start, $end) = (100001 + ($i - 1) * 10000, 100000 + $i * 10000); - $node_master->safe_psql("postgres", + $node_primary->safe_psql("postgres", "INSERT INTO tst SELECT i%10, substr(md5(i::text), 1, 1) FROM generate_series($start,$end) i;" ); test_index_replay("insert $i"); diff --git a/contrib/btree_gist/Makefile b/contrib/btree_gist/Makefile index 1774230bbec6..21538e6002e5 100644 --- a/contrib/btree_gist/Makefile +++ b/contrib/btree_gist/Makefile @@ -31,7 +31,8 @@ OBJS = \ EXTENSION = btree_gist DATA = btree_gist--1.0--1.1.sql \ btree_gist--1.1--1.2.sql btree_gist--1.2.sql btree_gist--1.2--1.3.sql \ - btree_gist--1.3--1.4.sql btree_gist--1.4--1.5.sql + btree_gist--1.3--1.4.sql btree_gist--1.4--1.5.sql \ + btree_gist--1.5--1.6.sql PGFILEDESC = "btree_gist - B-tree equivalent GiST operator classes" REGRESS = init int2 int4 int8 float4 float8 cash oid timestamp timestamptz \ diff --git a/contrib/btree_gist/btree_gist--1.1--1.2.sql b/contrib/btree_gist/btree_gist--1.1--1.2.sql index 8487f9bfc88a..d5a8c6cf90e9 100644 --- a/contrib/btree_gist/btree_gist--1.1--1.2.sql +++ b/contrib/btree_gist/btree_gist--1.1--1.2.sql @@ -8,56 +8,72 @@ -- wherein the signatures have been updated already. In that case to_regprocedure() will -- return NULL and no updates will happen. +DO LANGUAGE plpgsql +$$ +DECLARE + my_schema pg_catalog.text := pg_catalog.quote_ident(pg_catalog.current_schema()); + old_path pg_catalog.text := pg_catalog.current_setting('search_path'); +BEGIN +-- for safety, transiently set search_path to just pg_catalog+pg_temp +PERFORM pg_catalog.set_config('search_path', 'pg_catalog, pg_temp', true); + UPDATE pg_catalog.pg_proc SET proargtypes = pg_catalog.array_to_string(newtypes::pg_catalog.oid[], ' ')::pg_catalog.oidvector, pronargs = pg_catalog.array_length(newtypes, 1) FROM (VALUES -(NULL::pg_catalog.text, NULL::pg_catalog.regtype[]), -- establish column types +(NULL::pg_catalog.text, NULL::pg_catalog.text[]), -- establish column types ('gbt_oid_distance(internal,oid,int2,oid)', '{internal,oid,int2,oid,internal}'), ('gbt_oid_union(bytea,internal)', '{internal,internal}'), -('gbt_oid_same(internal,internal,internal)', '{gbtreekey8,gbtreekey8,internal}'), +('gbt_oid_same(internal,internal,internal)', '{SCH.gbtreekey8,SCH.gbtreekey8,internal}'), ('gbt_int2_distance(internal,int2,int2,oid)', '{internal,int2,int2,oid,internal}'), ('gbt_int2_union(bytea,internal)', '{internal,internal}'), -('gbt_int2_same(internal,internal,internal)', '{gbtreekey4,gbtreekey4,internal}'), +('gbt_int2_same(internal,internal,internal)', '{SCH.gbtreekey4,SCH.gbtreekey4,internal}'), ('gbt_int4_distance(internal,int4,int2,oid)', '{internal,int4,int2,oid,internal}'), ('gbt_int4_union(bytea,internal)', '{internal,internal}'), -('gbt_int4_same(internal,internal,internal)', '{gbtreekey8,gbtreekey8,internal}'), +('gbt_int4_same(internal,internal,internal)', '{SCH.gbtreekey8,SCH.gbtreekey8,internal}'), ('gbt_int8_distance(internal,int8,int2,oid)', '{internal,int8,int2,oid,internal}'), ('gbt_int8_union(bytea,internal)', '{internal,internal}'), -('gbt_int8_same(internal,internal,internal)', '{gbtreekey16,gbtreekey16,internal}'), +('gbt_int8_same(internal,internal,internal)', '{SCH.gbtreekey16,SCH.gbtreekey16,internal}'), ('gbt_float4_distance(internal,float4,int2,oid)', '{internal,float4,int2,oid,internal}'), ('gbt_float4_union(bytea,internal)', '{internal,internal}'), -('gbt_float4_same(internal,internal,internal)', '{gbtreekey8,gbtreekey8,internal}'), +('gbt_float4_same(internal,internal,internal)', '{SCH.gbtreekey8,SCH.gbtreekey8,internal}'), ('gbt_float8_distance(internal,float8,int2,oid)', '{internal,float8,int2,oid,internal}'), ('gbt_float8_union(bytea,internal)', '{internal,internal}'), -('gbt_float8_same(internal,internal,internal)', '{gbtreekey16,gbtreekey16,internal}'), +('gbt_float8_same(internal,internal,internal)', '{SCH.gbtreekey16,SCH.gbtreekey16,internal}'), ('gbt_ts_distance(internal,timestamp,int2,oid)', '{internal,timestamp,int2,oid,internal}'), ('gbt_tstz_distance(internal,timestamptz,int2,oid)', '{internal,timestamptz,int2,oid,internal}'), ('gbt_ts_union(bytea,internal)', '{internal,internal}'), -('gbt_ts_same(internal,internal,internal)', '{gbtreekey16,gbtreekey16,internal}'), +('gbt_ts_same(internal,internal,internal)', '{SCH.gbtreekey16,SCH.gbtreekey16,internal}'), ('gbt_time_distance(internal,time,int2,oid)', '{internal,time,int2,oid,internal}'), ('gbt_time_union(bytea,internal)', '{internal,internal}'), -('gbt_time_same(internal,internal,internal)', '{gbtreekey16,gbtreekey16,internal}'), +('gbt_time_same(internal,internal,internal)', '{SCH.gbtreekey16,SCH.gbtreekey16,internal}'), ('gbt_date_distance(internal,date,int2,oid)', '{internal,date,int2,oid,internal}'), ('gbt_date_union(bytea,internal)', '{internal,internal}'), -('gbt_date_same(internal,internal,internal)', '{gbtreekey8,gbtreekey8,internal}'), +('gbt_date_same(internal,internal,internal)', '{SCH.gbtreekey8,SCH.gbtreekey8,internal}'), ('gbt_intv_distance(internal,interval,int2,oid)', '{internal,interval,int2,oid,internal}'), ('gbt_intv_union(bytea,internal)', '{internal,internal}'), -('gbt_intv_same(internal,internal,internal)', '{gbtreekey32,gbtreekey32,internal}'), +('gbt_intv_same(internal,internal,internal)', '{SCH.gbtreekey32,SCH.gbtreekey32,internal}'), ('gbt_cash_distance(internal,money,int2,oid)', '{internal,money,int2,oid,internal}'), ('gbt_cash_union(bytea,internal)', '{internal,internal}'), -('gbt_cash_same(internal,internal,internal)', '{gbtreekey16,gbtreekey16,internal}'), +('gbt_cash_same(internal,internal,internal)', '{SCH.gbtreekey16,SCH.gbtreekey16,internal}'), ('gbt_macad_union(bytea,internal)', '{internal,internal}'), -('gbt_macad_same(internal,internal,internal)', '{gbtreekey16,gbtreekey16,internal}'), +('gbt_macad_same(internal,internal,internal)', '{SCH.gbtreekey16,SCH.gbtreekey16,internal}'), ('gbt_text_union(bytea,internal)', '{internal,internal}'), -('gbt_text_same(internal,internal,internal)', '{gbtreekey_var,gbtreekey_var,internal}'), +('gbt_text_same(internal,internal,internal)', '{SCH.gbtreekey_var,SCH.gbtreekey_var,internal}'), ('gbt_bytea_union(bytea,internal)', '{internal,internal}'), -('gbt_bytea_same(internal,internal,internal)', '{gbtreekey_var,gbtreekey_var,internal}'), +('gbt_bytea_same(internal,internal,internal)', '{SCH.gbtreekey_var,SCH.gbtreekey_var,internal}'), ('gbt_numeric_union(bytea,internal)', '{internal,internal}'), -('gbt_numeric_same(internal,internal,internal)', '{gbtreekey_var,gbtreekey_var,internal}'), +('gbt_numeric_same(internal,internal,internal)', '{SCH.gbtreekey_var,SCH.gbtreekey_var,internal}'), ('gbt_bit_union(bytea,internal)', '{internal,internal}'), -('gbt_bit_same(internal,internal,internal)', '{gbtreekey_var,gbtreekey_var,internal}'), +('gbt_bit_same(internal,internal,internal)', '{SCH.gbtreekey_var,SCH.gbtreekey_var,internal}'), ('gbt_inet_union(bytea,internal)', '{internal,internal}'), -('gbt_inet_same(internal,internal,internal)', '{gbtreekey16,gbtreekey16,internal}') -) AS update_data (oldproc, newtypes) -WHERE oid = pg_catalog.to_regprocedure(oldproc); +('gbt_inet_same(internal,internal,internal)', '{SCH.gbtreekey16,SCH.gbtreekey16,internal}') +) AS update_data (oldproc, newtypestext), +LATERAL ( + SELECT array_agg(replace(typ, 'SCH', my_schema)::regtype) as newtypes FROM unnest(newtypestext) typ +) ls +WHERE oid = to_regprocedure(my_schema || '.' || replace(oldproc, 'SCH', my_schema)); + +PERFORM pg_catalog.set_config('search_path', old_path, true); +END +$$; diff --git a/contrib/btree_gist/btree_gist--1.5--1.6.sql b/contrib/btree_gist/btree_gist--1.5--1.6.sql new file mode 100644 index 000000000000..5e1fcb47bdea --- /dev/null +++ b/contrib/btree_gist/btree_gist--1.5--1.6.sql @@ -0,0 +1,191 @@ +/* contrib/btree_gist/btree_gist--1.5--1.6.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "ALTER EXTENSION btree_gist UPDATE TO '1.6'" to load this file. \quit + +-- This upgrade script marks all btree_gist functions as parallel safe. + +-- Input/output functions for GiST key types (gbtreekey*) +ALTER FUNCTION gbtreekey4_in(cstring) PARALLEL SAFE; +ALTER FUNCTION gbtreekey4_out(gbtreekey4) PARALLEL SAFE; +ALTER FUNCTION gbtreekey8_in(cstring) PARALLEL SAFE; +ALTER FUNCTION gbtreekey8_out(gbtreekey8) PARALLEL SAFE; +ALTER FUNCTION gbtreekey16_in(cstring) PARALLEL SAFE; +ALTER FUNCTION gbtreekey16_out(gbtreekey16) PARALLEL SAFE; +ALTER FUNCTION gbtreekey32_in(cstring) PARALLEL SAFE; +ALTER FUNCTION gbtreekey32_out(gbtreekey32) PARALLEL SAFE; +ALTER FUNCTION gbtreekey_var_in(cstring) PARALLEL SAFE; +ALTER FUNCTION gbtreekey_var_out(gbtreekey_var) PARALLEL SAFE; + +-- Functions, which implement distance operators (<->) +ALTER FUNCTION cash_dist(money, money) PARALLEL SAFE; +ALTER FUNCTION date_dist(date, date) PARALLEL SAFE; +ALTER FUNCTION float4_dist(real, real) PARALLEL SAFE; +ALTER FUNCTION float8_dist(double precision, double precision) PARALLEL SAFE; +ALTER FUNCTION int2_dist(smallint, smallint) PARALLEL SAFE; +ALTER FUNCTION int4_dist(integer, integer) PARALLEL SAFE; +ALTER FUNCTION int8_dist(bigint, bigint) PARALLEL SAFE; +ALTER FUNCTION interval_dist(interval, interval) PARALLEL SAFE; +ALTER FUNCTION oid_dist(oid, oid) PARALLEL SAFE; +ALTER FUNCTION time_dist(time without time zone, time without time zone) PARALLEL SAFE; +ALTER FUNCTION ts_dist(timestamp without time zone, timestamp without time zone) PARALLEL SAFE; +ALTER FUNCTION tstz_dist(timestamp with time zone, timestamp with time zone) PARALLEL SAFE; + +-- GiST support methods +ALTER FUNCTION gbt_oid_consistent(internal, oid, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_oid_distance(internal, oid, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_oid_fetch(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_oid_compress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_decompress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_var_decompress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_var_fetch(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_oid_penalty(internal, internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_oid_picksplit(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_oid_union(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_oid_same(gbtreekey8, gbtreekey8, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_int2_consistent(internal, smallint, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_int2_distance(internal, smallint, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_int2_compress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_int2_fetch(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_int2_penalty(internal, internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_int2_picksplit(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_int2_union(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_int2_same(gbtreekey4, gbtreekey4, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_int4_consistent(internal, integer, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_int4_distance(internal, integer, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_int4_compress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_int4_fetch(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_int4_penalty(internal, internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_int4_picksplit(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_int4_union(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_int4_same(gbtreekey8, gbtreekey8, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_int8_consistent(internal, bigint, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_int8_distance(internal, bigint, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_int8_compress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_int8_fetch(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_int8_penalty(internal, internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_int8_picksplit(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_int8_union(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_int8_same(gbtreekey16, gbtreekey16, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_float4_consistent(internal, real, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_float4_distance(internal, real, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_float4_compress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_float4_fetch(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_float4_penalty(internal, internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_float4_picksplit(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_float4_union(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_float4_same(gbtreekey8, gbtreekey8, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_float8_consistent(internal, double precision, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_float8_distance(internal, double precision, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_float8_compress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_float8_fetch(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_float8_penalty(internal, internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_float8_picksplit(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_float8_union(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_float8_same(gbtreekey16, gbtreekey16, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_ts_consistent(internal, timestamp without time zone, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_ts_distance(internal, timestamp without time zone, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_tstz_consistent(internal, timestamp with time zone, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_tstz_distance(internal, timestamp with time zone, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_ts_compress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_tstz_compress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_ts_fetch(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_ts_penalty(internal, internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_ts_picksplit(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_ts_union(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_ts_same(gbtreekey16, gbtreekey16, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_time_consistent(internal, time without time zone, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_time_distance(internal, time without time zone, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_timetz_consistent(internal, time with time zone, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_time_compress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_timetz_compress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_time_fetch(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_time_penalty(internal, internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_time_picksplit(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_time_union(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_time_same(gbtreekey16, gbtreekey16, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_date_consistent(internal, date, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_date_distance(internal, date, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_date_compress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_date_fetch(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_date_penalty(internal, internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_date_picksplit(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_date_union(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_date_same(gbtreekey8, gbtreekey8, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_intv_consistent(internal, interval, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_intv_distance(internal, interval, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_intv_compress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_intv_decompress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_intv_fetch(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_intv_penalty(internal, internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_intv_picksplit(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_intv_union(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_intv_same(gbtreekey32, gbtreekey32, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_cash_consistent(internal, money, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_cash_distance(internal, money, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_cash_compress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_cash_fetch(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_cash_penalty(internal, internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_cash_picksplit(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_cash_union(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_cash_same(gbtreekey16, gbtreekey16, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_macad_consistent(internal, macaddr, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_macad_compress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_macad_fetch(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_macad_penalty(internal, internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_macad_picksplit(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_macad_union(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_macad_same(gbtreekey16, gbtreekey16, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_text_consistent(internal, text, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_bpchar_consistent(internal, character, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_text_compress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_bpchar_compress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_text_penalty(internal, internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_text_picksplit(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_text_union(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_text_same(gbtreekey_var, gbtreekey_var, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_bytea_consistent(internal, bytea, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_bytea_compress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_bytea_penalty(internal, internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_bytea_picksplit(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_bytea_union(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_bytea_same(gbtreekey_var, gbtreekey_var, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_numeric_consistent(internal, numeric, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_numeric_compress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_numeric_penalty(internal, internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_numeric_picksplit(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_numeric_union(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_numeric_same(gbtreekey_var, gbtreekey_var, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_bit_consistent(internal, bit, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_bit_compress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_bit_penalty(internal, internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_bit_picksplit(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_bit_union(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_bit_same(gbtreekey_var, gbtreekey_var, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_inet_consistent(internal, inet, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_inet_compress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_inet_penalty(internal, internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_inet_picksplit(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_inet_union(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_inet_same(gbtreekey16, gbtreekey16, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_uuid_consistent(internal, uuid, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_uuid_fetch(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_uuid_compress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_uuid_penalty(internal, internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_uuid_picksplit(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_uuid_union(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_uuid_same(gbtreekey32, gbtreekey32, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_macad8_consistent(internal, macaddr8, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_macad8_compress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_macad8_fetch(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_macad8_penalty(internal, internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_macad8_picksplit(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_macad8_union(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_macad8_same(gbtreekey16, gbtreekey16, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_enum_consistent(internal, anyenum, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_enum_compress(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_enum_fetch(internal) PARALLEL SAFE; +ALTER FUNCTION gbt_enum_penalty(internal, internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_enum_picksplit(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_enum_union(internal, internal) PARALLEL SAFE; +ALTER FUNCTION gbt_enum_same(gbtreekey8, gbtreekey8, internal) PARALLEL SAFE; diff --git a/contrib/btree_gist/btree_gist.control b/contrib/btree_gist/btree_gist.control index cd2d7eb4abbc..e5c41fe8f397 100644 --- a/contrib/btree_gist/btree_gist.control +++ b/contrib/btree_gist/btree_gist.control @@ -1,6 +1,6 @@ # btree_gist extension comment = 'support for indexing common datatypes in GiST' -default_version = '1.5' +default_version = '1.6' module_pathname = '$libdir/btree_gist' relocatable = true trusted = true diff --git a/contrib/citext/citext--1.1--1.2.sql b/contrib/citext/citext--1.1--1.2.sql index 4f0e4bc7195b..a8bba860a1d4 100644 --- a/contrib/citext/citext--1.1--1.2.sql +++ b/contrib/citext/citext--1.1--1.2.sql @@ -41,14 +41,28 @@ ALTER FUNCTION replace(citext, citext, citext) PARALLEL SAFE; ALTER FUNCTION split_part(citext, citext, int) PARALLEL SAFE; ALTER FUNCTION translate(citext, citext, text) PARALLEL SAFE; +-- We have to update aggregates the hard way for lack of ALTER support +DO LANGUAGE plpgsql +$$ +DECLARE + my_schema pg_catalog.text := pg_catalog.quote_ident(pg_catalog.current_schema()); + old_path pg_catalog.text := pg_catalog.current_setting('search_path'); +BEGIN +-- for safety, transiently set search_path to just pg_catalog+pg_temp +PERFORM pg_catalog.set_config('search_path', 'pg_catalog, pg_temp', true); + UPDATE pg_proc SET proparallel = 's' -WHERE oid = 'min(citext)'::pg_catalog.regprocedure; +WHERE oid = (my_schema || '.min(' || my_schema || '.citext)')::pg_catalog.regprocedure; UPDATE pg_proc SET proparallel = 's' -WHERE oid = 'max(citext)'::pg_catalog.regprocedure; +WHERE oid = (my_schema || '.max(' || my_schema || '.citext)')::pg_catalog.regprocedure; + +UPDATE pg_aggregate SET aggcombinefn = (my_schema || '.citext_smaller')::regproc +WHERE aggfnoid = (my_schema || '.max(' || my_schema || '.citext)')::pg_catalog.regprocedure; -UPDATE pg_aggregate SET aggcombinefn = 'citext_smaller' -WHERE aggfnoid = 'max(citext)'::pg_catalog.regprocedure; +UPDATE pg_aggregate SET aggcombinefn = (my_schema || '.citext_larger')::regproc +WHERE aggfnoid = (my_schema || '.max(' || my_schema || '.citext)')::pg_catalog.regprocedure; -UPDATE pg_aggregate SET aggcombinefn = 'citext_larger' -WHERE aggfnoid = 'max(citext)'::pg_catalog.regprocedure; +PERFORM pg_catalog.set_config('search_path', old_path, true); +END +$$; diff --git a/contrib/citext/citext--1.2--1.3.sql b/contrib/citext/citext--1.2--1.3.sql index 4ab867915c73..24a71452c624 100644 --- a/contrib/citext/citext--1.2--1.3.sql +++ b/contrib/citext/citext--1.2--1.3.sql @@ -3,5 +3,19 @@ -- complain if script is sourced in psql, rather than via ALTER EXTENSION \echo Use "ALTER EXTENSION citext UPDATE TO '1.3'" to load this file. \quit -UPDATE pg_aggregate SET aggcombinefn = 'citext_smaller' -WHERE aggfnoid = 'min(citext)'::pg_catalog.regprocedure; +-- We have to update aggregates the hard way for lack of ALTER support +DO LANGUAGE plpgsql +$$ +DECLARE + my_schema pg_catalog.text := pg_catalog.quote_ident(pg_catalog.current_schema()); + old_path pg_catalog.text := pg_catalog.current_setting('search_path'); +BEGIN +-- for safety, transiently set search_path to just pg_catalog+pg_temp +PERFORM pg_catalog.set_config('search_path', 'pg_catalog, pg_temp', true); + +UPDATE pg_aggregate SET aggcombinefn = (my_schema || '.citext_smaller')::regproc +WHERE aggfnoid = (my_schema || '.min(' || my_schema || '.citext)')::pg_catalog.regprocedure; + +PERFORM pg_catalog.set_config('search_path', old_path, true); +END +$$; diff --git a/contrib/citext/expected/citext.out b/contrib/citext/expected/citext.out index fa3abf309825..936cb06f3006 100644 --- a/contrib/citext/expected/citext.out +++ b/contrib/citext/expected/citext.out @@ -1602,7 +1602,7 @@ SELECT substring('Thomas'::citext from '...$') = 'mas' AS t; t (1 row) -SELECT substring('Thomas'::citext from '%#"o_a#"_' for '#') = 'oma' AS t; +SELECT substring('Thomas'::citext similar '%#"o_a#"_' escape '#') = 'oma' AS t; t --- t diff --git a/contrib/citext/expected/citext_1.out b/contrib/citext/expected/citext_1.out index 18da32a7861b..d5bd0b969467 100644 --- a/contrib/citext/expected/citext_1.out +++ b/contrib/citext/expected/citext_1.out @@ -1602,7 +1602,7 @@ SELECT substring('Thomas'::citext from '...$') = 'mas' AS t; t (1 row) -SELECT substring('Thomas'::citext from '%#"o_a#"_' for '#') = 'oma' AS t; +SELECT substring('Thomas'::citext similar '%#"o_a#"_' escape '#') = 'oma' AS t; t --- t diff --git a/contrib/citext/sql/citext.sql b/contrib/citext/sql/citext.sql index 100f91e2b73f..cec93d55e795 100644 --- a/contrib/citext/sql/citext.sql +++ b/contrib/citext/sql/citext.sql @@ -564,7 +564,7 @@ SELECT substring('alphabet'::citext, 3, 2) = 'ph' AS t; SELECT substring('Thomas'::citext from 2 for 3) = 'hom' AS t; SELECT substring('Thomas'::citext from 2) = 'homas' AS t; SELECT substring('Thomas'::citext from '...$') = 'mas' AS t; -SELECT substring('Thomas'::citext from '%#"o_a#"_' for '#') = 'oma' AS t; +SELECT substring('Thomas'::citext similar '%#"o_a#"_' escape '#') = 'oma' AS t; SELECT trim(' trim '::citext) = 'trim' AS t; SELECT trim('xxxxxtrimxxxx'::citext, 'x'::citext) = 'trim' AS t; diff --git a/contrib/cube/cube--1.1--1.2.sql b/contrib/cube/cube--1.1--1.2.sql index 64a531e8b433..76aba239e5bc 100644 --- a/contrib/cube/cube--1.1--1.2.sql +++ b/contrib/cube/cube--1.1--1.2.sql @@ -7,16 +7,31 @@ -- We use to_regprocedure() so that query doesn't fail if run against 9.6beta1 definitions, -- wherein the signatures have been updated already. In that case to_regprocedure() will -- return NULL and no updates will happen. +DO LANGUAGE plpgsql +$$ +DECLARE + my_schema pg_catalog.text := pg_catalog.quote_ident(pg_catalog.current_schema()); + old_path pg_catalog.text := pg_catalog.current_setting('search_path'); +BEGIN +-- for safety, transiently set search_path to just pg_catalog+pg_temp +PERFORM pg_catalog.set_config('search_path', 'pg_catalog, pg_temp', true); UPDATE pg_catalog.pg_proc SET proargtypes = pg_catalog.array_to_string(newtypes::pg_catalog.oid[], ' ')::pg_catalog.oidvector, pronargs = pg_catalog.array_length(newtypes, 1) FROM (VALUES -(NULL::pg_catalog.text, NULL::pg_catalog.regtype[]), -- establish column types -('g_cube_consistent(internal,cube,int4,oid,internal)', '{internal,cube,int2,oid,internal}'), -('g_cube_distance(internal,cube,smallint,oid)', '{internal,cube,smallint,oid,internal}') -) AS update_data (oldproc, newtypes) -WHERE oid = pg_catalog.to_regprocedure(oldproc); +(NULL::pg_catalog.text, NULL::pg_catalog.text[]), -- establish column types +('g_cube_consistent(internal,SCH.cube,int4,oid,internal)', '{internal,SCH.cube,int2,oid,internal}'), +('g_cube_distance(internal,SCH.cube,smallint,oid)', '{internal,SCH.cube,smallint,oid,internal}') +) AS update_data (oldproc, newtypestext), +LATERAL ( + SELECT array_agg(replace(typ, 'SCH', my_schema)::regtype) as newtypes FROM unnest(newtypestext) typ +) ls +WHERE oid = to_regprocedure(my_schema || '.' || replace(oldproc, 'SCH', my_schema)); + +PERFORM pg_catalog.set_config('search_path', old_path, true); +END +$$; ALTER FUNCTION cube_in(cstring) PARALLEL SAFE; ALTER FUNCTION cube(float8[], float8[]) PARALLEL SAFE; diff --git a/contrib/cube/cube--1.3--1.4.sql b/contrib/cube/cube--1.3--1.4.sql index 4140079a1e7f..f557a1cbe745 100644 --- a/contrib/cube/cube--1.3--1.4.sql +++ b/contrib/cube/cube--1.3--1.4.sql @@ -12,6 +12,15 @@ -- bound into a particular opclass. There's no SQL command for that, -- so fake it with a manual update on pg_depend. -- +DO LANGUAGE plpgsql +$$ +DECLARE + my_schema pg_catalog.text := pg_catalog.quote_ident(pg_catalog.current_schema()); + old_path pg_catalog.text := pg_catalog.current_setting('search_path'); +BEGIN +-- for safety, transiently set search_path to just pg_catalog+pg_temp +PERFORM pg_catalog.set_config('search_path', 'pg_catalog, pg_temp', true); + UPDATE pg_catalog.pg_depend SET deptype = 'a' WHERE classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass @@ -20,14 +29,10 @@ WHERE classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass FROM pg_catalog.pg_depend WHERE classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass AND refclassid = 'pg_catalog.pg_proc'::pg_catalog.regclass - AND (refobjid = 'g_cube_compress(pg_catalog.internal)'::pg_catalog.regprocedure)) + AND (refobjid = (my_schema || '.g_cube_compress(pg_catalog.internal)')::pg_catalog.regprocedure)) AND refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass AND deptype = 'i'; -ALTER OPERATOR FAMILY gist_cube_ops USING gist drop function 3 (cube); -ALTER EXTENSION cube DROP function g_cube_compress(pg_catalog.internal); -DROP FUNCTION g_cube_compress(pg_catalog.internal); - UPDATE pg_catalog.pg_depend SET deptype = 'a' WHERE classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass @@ -36,10 +41,18 @@ WHERE classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass FROM pg_catalog.pg_depend WHERE classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass AND refclassid = 'pg_catalog.pg_proc'::pg_catalog.regclass - AND (refobjid = 'g_cube_decompress(pg_catalog.internal)'::pg_catalog.regprocedure)) + AND (refobjid = (my_schema || '.g_cube_decompress(pg_catalog.internal)')::pg_catalog.regprocedure)) AND refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass AND deptype = 'i'; +PERFORM pg_catalog.set_config('search_path', old_path, true); +END +$$; + +ALTER OPERATOR FAMILY gist_cube_ops USING gist drop function 3 (cube); +ALTER EXTENSION cube DROP function g_cube_compress(pg_catalog.internal); +DROP FUNCTION g_cube_compress(pg_catalog.internal); + ALTER OPERATOR FAMILY gist_cube_ops USING gist drop function 4 (cube); ALTER EXTENSION cube DROP function g_cube_decompress(pg_catalog.internal); DROP FUNCTION g_cube_decompress(pg_catalog.internal); diff --git a/contrib/earthdistance/earthdistance--1.1.sql b/contrib/earthdistance/earthdistance--1.1.sql index 9136a54a7b34..9ef20ab848c5 100644 --- a/contrib/earthdistance/earthdistance--1.1.sql +++ b/contrib/earthdistance/earthdistance--1.1.sql @@ -31,7 +31,7 @@ CREATE DOMAIN earth AS cube CONSTRAINT not_point check(cube_is_point(value)) CONSTRAINT not_3d check(cube_dim(value) <= 3) CONSTRAINT on_surface check(abs(cube_distance(value, '(0)'::cube) / - earth() - 1) < '10e-7'::float8); + earth() - '1'::float8) < '10e-7'::float8); CREATE FUNCTION sec_to_gc(float8) RETURNS float8 diff --git a/contrib/earthdistance/earthdistance.control b/contrib/earthdistance/earthdistance.control index 3df666dfc1bb..5816d22cdd98 100644 --- a/contrib/earthdistance/earthdistance.control +++ b/contrib/earthdistance/earthdistance.control @@ -3,5 +3,4 @@ comment = 'calculate great-circle distances on the surface of the Earth' default_version = '1.1' module_pathname = '$libdir/earthdistance' relocatable = true -trusted = true requires = 'cube' diff --git a/contrib/hstore/Makefile b/contrib/hstore/Makefile index 872ca03cd1fb..72376d900763 100644 --- a/contrib/hstore/Makefile +++ b/contrib/hstore/Makefile @@ -15,7 +15,7 @@ DATA = hstore--1.4.sql \ hstore--1.5--1.6.sql \ hstore--1.4--1.5.sql \ hstore--1.3--1.4.sql hstore--1.2--1.3.sql \ - hstore--1.1--1.2.sql hstore--1.0--1.1.sql + hstore--1.1--1.2.sql PGFILEDESC = "hstore - key/value pair data type" HEADERS = hstore.h diff --git a/contrib/hstore/hstore--1.0--1.1.sql b/contrib/hstore/hstore--1.0--1.1.sql deleted file mode 100644 index 4e32a575c5f6..000000000000 --- a/contrib/hstore/hstore--1.0--1.1.sql +++ /dev/null @@ -1,7 +0,0 @@ -/* contrib/hstore/hstore--1.0--1.1.sql */ - --- complain if script is sourced in psql, rather than via ALTER EXTENSION -\echo Use "ALTER EXTENSION hstore UPDATE TO '1.1'" to load this file. \quit - -ALTER EXTENSION hstore DROP OPERATOR => (text, text); -DROP OPERATOR => (text, text); diff --git a/contrib/hstore/hstore--1.1--1.2.sql b/contrib/hstore/hstore--1.1--1.2.sql index a868ffe48e1a..cc69fc7f802e 100644 --- a/contrib/hstore/hstore--1.1--1.2.sql +++ b/contrib/hstore/hstore--1.1--1.2.sql @@ -9,10 +9,13 @@ -- dependent on the extension. DO LANGUAGE plpgsql - $$ - +DECLARE + my_schema pg_catalog.text := pg_catalog.quote_ident(pg_catalog.current_schema()); + old_path pg_catalog.text := pg_catalog.current_setting('search_path'); BEGIN +-- for safety, transiently set search_path to just pg_catalog+pg_temp +PERFORM pg_catalog.set_config('search_path', 'pg_catalog, pg_temp', true); PERFORM 1 FROM pg_proc p @@ -27,6 +30,7 @@ BEGIN IF NOT FOUND THEN + PERFORM pg_catalog.set_config('search_path', old_path, true); CREATE FUNCTION hstore_to_json(hstore) RETURNS json @@ -43,6 +47,7 @@ BEGIN END IF; +PERFORM pg_catalog.set_config('search_path', old_path, true); END; $$; diff --git a/contrib/hstore/hstore--1.3--1.4.sql b/contrib/hstore/hstore--1.3--1.4.sql index d68956bb9495..53f26f9fb847 100644 --- a/contrib/hstore/hstore--1.3--1.4.sql +++ b/contrib/hstore/hstore--1.3--1.4.sql @@ -7,23 +7,38 @@ -- We use to_regprocedure() so that query doesn't fail if run against 9.6beta1 definitions, -- wherein the signatures have been updated already. In that case to_regprocedure() will -- return NULL and no updates will happen. +DO LANGUAGE plpgsql +$$ +DECLARE + my_schema pg_catalog.text := pg_catalog.quote_ident(pg_catalog.current_schema()); + old_path pg_catalog.text := pg_catalog.current_setting('search_path'); +BEGIN +-- for safety, transiently set search_path to just pg_catalog+pg_temp +PERFORM pg_catalog.set_config('search_path', 'pg_catalog, pg_temp', true); UPDATE pg_catalog.pg_proc SET proargtypes = pg_catalog.array_to_string(newtypes::pg_catalog.oid[], ' ')::pg_catalog.oidvector, pronargs = pg_catalog.array_length(newtypes, 1) FROM (VALUES -(NULL::pg_catalog.text, NULL::pg_catalog.regtype[]), -- establish column types -('ghstore_same(internal,internal,internal)', '{ghstore,ghstore,internal}'), -('ghstore_consistent(internal,internal,int4,oid,internal)', '{internal,hstore,int2,oid,internal}'), -('gin_extract_hstore(internal,internal)', '{hstore,internal}'), -('gin_extract_hstore_query(internal,internal,int2,internal,internal)', '{hstore,internal,int2,internal,internal}'), -('gin_consistent_hstore(internal,int2,internal,int4,internal,internal)', '{internal,int2,hstore,int4,internal,internal}') -) AS update_data (oldproc, newtypes) -WHERE oid = pg_catalog.to_regprocedure(oldproc); +(NULL::pg_catalog.text, NULL::pg_catalog.text[]), -- establish column types +('ghstore_same(internal,internal,internal)', '{SCH.ghstore,SCH.ghstore,internal}'), +('ghstore_consistent(internal,internal,int4,oid,internal)', '{internal,SCH.hstore,int2,oid,internal}'), +('gin_extract_hstore(internal,internal)', '{SCH.hstore,internal}'), +('gin_extract_hstore_query(internal,internal,int2,internal,internal)', '{SCH.hstore,internal,int2,internal,internal}'), +('gin_consistent_hstore(internal,int2,internal,int4,internal,internal)', '{internal,int2,SCH.hstore,int4,internal,internal}') +) AS update_data (oldproc, newtypestext), +LATERAL ( + SELECT array_agg(replace(typ, 'SCH', my_schema)::regtype) as newtypes FROM unnest(newtypestext) typ +) ls +WHERE oid = to_regprocedure(my_schema || '.' || replace(oldproc, 'SCH', my_schema)); UPDATE pg_catalog.pg_proc SET - prorettype = 'ghstore'::pg_catalog.regtype -WHERE oid = pg_catalog.to_regprocedure('ghstore_union(internal,internal)'); + prorettype = (my_schema || '.ghstore')::pg_catalog.regtype +WHERE oid = pg_catalog.to_regprocedure((my_schema || '.ghstore_union(internal,internal)')); + +PERFORM pg_catalog.set_config('search_path', old_path, true); +END +$$; ALTER FUNCTION hstore_in(cstring) PARALLEL SAFE; ALTER FUNCTION hstore_out(hstore) PARALLEL SAFE; diff --git a/contrib/hstore_plperl/hstore_plperl.control b/contrib/hstore_plperl/hstore_plperl.control index 4b9fd13d04fc..16277f68c1cc 100644 --- a/contrib/hstore_plperl/hstore_plperl.control +++ b/contrib/hstore_plperl/hstore_plperl.control @@ -3,5 +3,4 @@ comment = 'transform between hstore and plperl' default_version = '1.0' module_pathname = '$libdir/hstore_plperl' relocatable = true -trusted = true requires = 'hstore,plperl' diff --git a/contrib/intagg/intagg--1.0--1.1.sql b/contrib/intagg/intagg--1.0--1.1.sql index b2a2820b0cac..c0cc17a033bd 100644 --- a/contrib/intagg/intagg--1.0--1.1.sql +++ b/contrib/intagg/intagg--1.0--1.1.sql @@ -6,6 +6,18 @@ ALTER FUNCTION int_agg_state(internal, int4) PARALLEL SAFE; ALTER FUNCTION int_agg_final_array(internal) PARALLEL SAFE; ALTER FUNCTION int_array_enum(int4[]) PARALLEL SAFE; +DO LANGUAGE plpgsql +$$ +DECLARE + my_schema pg_catalog.text := pg_catalog.quote_ident(pg_catalog.current_schema()); + old_path pg_catalog.text := pg_catalog.current_setting('search_path'); +BEGIN +-- for safety, transiently set search_path to just pg_catalog+pg_temp +PERFORM pg_catalog.set_config('search_path', 'pg_catalog, pg_temp', true); UPDATE pg_proc SET proparallel = 's' -WHERE oid = 'int_array_aggregate(int4)'::pg_catalog.regprocedure; +WHERE oid = (my_schema || '.int_array_aggregate(int4)')::pg_catalog.regprocedure; + +PERFORM pg_catalog.set_config('search_path', old_path, true); +END +$$; diff --git a/contrib/intarray/Makefile b/contrib/intarray/Makefile index b68959ebd64d..01faa36b1073 100644 --- a/contrib/intarray/Makefile +++ b/contrib/intarray/Makefile @@ -12,7 +12,8 @@ OBJS = \ _intbig_gist.o EXTENSION = intarray -DATA = intarray--1.2--1.3.sql intarray--1.2.sql intarray--1.1--1.2.sql \ +DATA = intarray--1.3--1.4.sql intarray--1.2--1.3.sql \ + intarray--1.2.sql intarray--1.1--1.2.sql \ intarray--1.0--1.1.sql PGFILEDESC = "intarray - functions and operators for arrays of integers" diff --git a/contrib/intarray/_int_gist.c b/contrib/intarray/_int_gist.c index fb05b06af9eb..f1817a6cce3b 100644 --- a/contrib/intarray/_int_gist.c +++ b/contrib/intarray/_int_gist.c @@ -93,6 +93,12 @@ g_int_consistent(PG_FUNCTION_ARGS) break; case RTContainedByStrategyNumber: case RTOldContainedByStrategyNumber: + + /* + * This code is unreachable as of intarray 1.4, because the <@ + * operator has been removed from the opclass. We keep it for now + * to support older versions of the SQL definitions. + */ if (GIST_LEAF(entry)) retval = inner_int_contains(query, (ArrayType *) DatumGetPointer(entry->key)); diff --git a/contrib/intarray/_intbig_gist.c b/contrib/intarray/_intbig_gist.c index 67c44e99a9a7..18ecd8cda6b1 100644 --- a/contrib/intarray/_intbig_gist.c +++ b/contrib/intarray/_intbig_gist.c @@ -533,6 +533,12 @@ g_intbig_consistent(PG_FUNCTION_ARGS) break; case RTContainedByStrategyNumber: case RTOldContainedByStrategyNumber: + + /* + * This code is unreachable as of intarray 1.4, because the <@ + * operator has been removed from the opclass. We keep it for now + * to support older versions of the SQL definitions. + */ if (GIST_LEAF(entry)) { int i, diff --git a/contrib/intarray/intarray--1.1--1.2.sql b/contrib/intarray/intarray--1.1--1.2.sql index 468f245ecec9..919340ef01ef 100644 --- a/contrib/intarray/intarray--1.1--1.2.sql +++ b/contrib/intarray/intarray--1.1--1.2.sql @@ -7,23 +7,38 @@ -- We use to_regprocedure() so that query doesn't fail if run against 9.6beta1 definitions, -- wherein the signatures have been updated already. In that case to_regprocedure() will -- return NULL and no updates will happen. +DO LANGUAGE plpgsql +$$ +DECLARE + my_schema pg_catalog.text := pg_catalog.quote_ident(pg_catalog.current_schema()); + old_path pg_catalog.text := pg_catalog.current_setting('search_path'); +BEGIN +-- for safety, transiently set search_path to just pg_catalog+pg_temp +PERFORM pg_catalog.set_config('search_path', 'pg_catalog, pg_temp', true); UPDATE pg_catalog.pg_proc SET proargtypes = pg_catalog.array_to_string(newtypes::pg_catalog.oid[], ' ')::pg_catalog.oidvector, pronargs = pg_catalog.array_length(newtypes, 1) FROM (VALUES -(NULL::pg_catalog.text, NULL::pg_catalog.regtype[]), -- establish column types +(NULL::pg_catalog.text, NULL::pg_catalog.text[]), -- establish column types ('g_int_consistent(internal,_int4,int4,oid,internal)', '{internal,_int4,int2,oid,internal}'), ('g_intbig_consistent(internal,internal,int4,oid,internal)', '{internal,_int4,int2,oid,internal}'), -('g_intbig_same(internal,internal,internal)', '{intbig_gkey,intbig_gkey,internal}'), +('g_intbig_same(internal,internal,internal)', '{SCH.intbig_gkey,SCH.intbig_gkey,internal}'), ('ginint4_queryextract(internal,internal,int2,internal,internal,internal,internal)', '{_int4,internal,int2,internal,internal,internal,internal}'), ('ginint4_consistent(internal,int2,internal,int4,internal,internal,internal,internal)', '{internal,int2,_int4,int4,internal,internal,internal,internal}') -) AS update_data (oldproc, newtypes) -WHERE oid = pg_catalog.to_regprocedure(oldproc); +) AS update_data (oldproc, newtypestext), +LATERAL ( + SELECT array_agg(replace(typ, 'SCH', my_schema)::regtype) as newtypes FROM unnest(newtypestext) typ +) ls +WHERE oid = to_regprocedure(my_schema || '.' || replace(oldproc, 'SCH', my_schema)); UPDATE pg_catalog.pg_proc SET - prorettype = 'intbig_gkey'::pg_catalog.regtype -WHERE oid = pg_catalog.to_regprocedure('g_intbig_union(internal,internal)'); + prorettype = (my_schema || '.intbig_gkey')::pg_catalog.regtype +WHERE oid = pg_catalog.to_regprocedure(my_schema || '.g_intbig_union(internal,internal)'); + +PERFORM pg_catalog.set_config('search_path', old_path, true); +END +$$; ALTER FUNCTION bqarr_in(cstring) PARALLEL SAFE; ALTER FUNCTION bqarr_out(query_int) PARALLEL SAFE; diff --git a/contrib/intarray/intarray--1.3--1.4.sql b/contrib/intarray/intarray--1.3--1.4.sql new file mode 100644 index 000000000000..3fbebb541737 --- /dev/null +++ b/contrib/intarray/intarray--1.3--1.4.sql @@ -0,0 +1,21 @@ +/* contrib/intarray/intarray--1.3--1.4.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION intarray UPDATE TO '1.4'" to load this file. \quit + +-- Remove <@ from the GiST opclasses, as it's not usefully indexable +-- due to mishandling of empty arrays. (It's OK in GIN.) + +ALTER OPERATOR FAMILY gist__int_ops USING gist +DROP OPERATOR 8 (_int4, _int4); + +ALTER OPERATOR FAMILY gist__intbig_ops USING gist +DROP OPERATOR 8 (_int4, _int4); + +-- Likewise for the old spelling ~. + +ALTER OPERATOR FAMILY gist__int_ops USING gist +DROP OPERATOR 14 (_int4, _int4); + +ALTER OPERATOR FAMILY gist__intbig_ops USING gist +DROP OPERATOR 14 (_int4, _int4); diff --git a/contrib/intarray/intarray.control b/contrib/intarray/intarray.control index db7746b6c7a0..bbc837c5732e 100644 --- a/contrib/intarray/intarray.control +++ b/contrib/intarray/intarray.control @@ -1,6 +1,6 @@ # intarray extension comment = 'functions, operators, and index support for 1-D arrays of integers' -default_version = '1.3' +default_version = '1.4' module_pathname = '$libdir/_int' relocatable = true trusted = true diff --git a/contrib/jsonb_plperl/jsonb_plperl.c b/contrib/jsonb_plperl/jsonb_plperl.c index ed361efbe202..b81ba54b809d 100644 --- a/contrib/jsonb_plperl/jsonb_plperl.c +++ b/contrib/jsonb_plperl/jsonb_plperl.c @@ -227,10 +227,8 @@ SV_to_JsonbValue(SV *in, JsonbParseState **jsonb_state, bool is_elem) /* * jsonb doesn't allow infinity or NaN (per JSON * specification), but the numeric type that is used for the - * storage accepts NaN, so we have to prevent it here - * explicitly. We don't really have to check for isinf() - * here, as numeric doesn't allow it and it would be caught - * later, but it makes for a nicer error message. + * storage accepts those, so we have to reject them here + * explicitly. */ if (isinf(nval)) ereport(ERROR, diff --git a/contrib/jsonb_plpython/jsonb_plpython.c b/contrib/jsonb_plpython/jsonb_plpython.c index e09308daf07f..836c17877065 100644 --- a/contrib/jsonb_plpython/jsonb_plpython.c +++ b/contrib/jsonb_plpython/jsonb_plpython.c @@ -387,14 +387,17 @@ PLyNumber_ToJsonbValue(PyObject *obj, JsonbValue *jbvNum) pfree(str); /* - * jsonb doesn't allow NaN (per JSON specification), so we have to prevent - * it here explicitly. (Infinity is also not allowed in jsonb, but - * numeric_in above already catches that.) + * jsonb doesn't allow NaN or infinity (per JSON specification), so we + * have to reject those here explicitly. */ if (numeric_is_nan(num)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("cannot convert NaN to jsonb"))); + if (numeric_is_inf(num)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("cannot convert infinity to jsonb"))); jbvNum->type = jbvNumeric; jbvNum->val.numeric = num; diff --git a/contrib/ltree/ltree--1.0--1.1.sql b/contrib/ltree/ltree--1.0--1.1.sql index a6485e8e0238..5fd6f499e6c6 100644 --- a/contrib/ltree/ltree--1.0--1.1.sql +++ b/contrib/ltree/ltree--1.0--1.1.sql @@ -7,26 +7,41 @@ -- We use to_regprocedure() so that query doesn't fail if run against 9.6beta1 definitions, -- wherein the signatures have been updated already. In that case to_regprocedure() will -- return NULL and no updates will happen. +DO LANGUAGE plpgsql +$$ +DECLARE + my_schema pg_catalog.text := pg_catalog.quote_ident(pg_catalog.current_schema()); + old_path pg_catalog.text := pg_catalog.current_setting('search_path'); +BEGIN +-- for safety, transiently set search_path to just pg_catalog+pg_temp +PERFORM pg_catalog.set_config('search_path', 'pg_catalog, pg_temp', true); UPDATE pg_catalog.pg_proc SET proargtypes = pg_catalog.array_to_string(newtypes::pg_catalog.oid[], ' ')::pg_catalog.oidvector, pronargs = pg_catalog.array_length(newtypes, 1) FROM (VALUES -(NULL::pg_catalog.text, NULL::pg_catalog.regtype[]), -- establish column types -('ltree_consistent(internal,internal,int2,oid,internal)', '{internal,ltree,int2,oid,internal}'), -('ltree_same(internal,internal,internal)', '{ltree_gist,ltree_gist,internal}'), -('_ltree_consistent(internal,internal,int2,oid,internal)', '{internal,_ltree,int2,oid,internal}'), -('_ltree_same(internal,internal,internal)', '{ltree_gist,ltree_gist,internal}') -) AS update_data (oldproc, newtypes) -WHERE oid = pg_catalog.to_regprocedure(oldproc); +(NULL::pg_catalog.text, NULL::pg_catalog.text[]), -- establish column types +('ltree_consistent(internal,internal,int2,oid,internal)', '{internal,SCH.ltree,int2,oid,internal}'), +('ltree_same(internal,internal,internal)', '{SCH.ltree_gist,SCH.ltree_gist,internal}'), +('_ltree_consistent(internal,internal,int2,oid,internal)', '{internal,SCH._ltree,int2,oid,internal}'), +('_ltree_same(internal,internal,internal)', '{SCH.ltree_gist,SCH.ltree_gist,internal}') +) AS update_data (oldproc, newtypestext), +LATERAL ( + SELECT array_agg(replace(typ, 'SCH', my_schema)::regtype) as newtypes FROM unnest(newtypestext) typ +) ls +WHERE oid = to_regprocedure(my_schema || '.' || replace(oldproc, 'SCH', my_schema)); UPDATE pg_catalog.pg_proc SET - prorettype = 'ltree_gist'::pg_catalog.regtype -WHERE oid = pg_catalog.to_regprocedure('ltree_union(internal,internal)'); + prorettype = (my_schema || '.ltree_gist')::pg_catalog.regtype +WHERE oid = pg_catalog.to_regprocedure(my_schema || '.ltree_union(internal,internal)'); UPDATE pg_catalog.pg_proc SET - prorettype = 'ltree_gist'::pg_catalog.regtype -WHERE oid = pg_catalog.to_regprocedure('_ltree_union(internal,internal)'); + prorettype = (my_schema || '.ltree_gist')::pg_catalog.regtype +WHERE oid = pg_catalog.to_regprocedure(my_schema || '._ltree_union(internal,internal)'); + +PERFORM pg_catalog.set_config('search_path', old_path, true); +END +$$; ALTER FUNCTION ltree_in(cstring) PARALLEL SAFE; ALTER FUNCTION ltree_out(ltree) PARALLEL SAFE; diff --git a/contrib/oid2name/oid2name.c b/contrib/oid2name/oid2name.c index c7d0f9025a43..91b7958c48ef 100644 --- a/contrib/oid2name/oid2name.c +++ b/contrib/oid2name/oid2name.c @@ -10,8 +10,8 @@ #include "postgres_fe.h" #include "catalog/pg_class_d.h" +#include "common/connect.h" #include "common/logging.h" -#include "fe_utils/connect.h" #include "getopt_long.h" #include "libpq-fe.h" #include "pg_getopt.h" diff --git a/contrib/pg_prewarm/autoprewarm.c b/contrib/pg_prewarm/autoprewarm.c index be3787eca82f..c202756d2f6a 100644 --- a/contrib/pg_prewarm/autoprewarm.c +++ b/contrib/pg_prewarm/autoprewarm.c @@ -11,7 +11,7 @@ * pages from a relation that is in the process of being dropped. * * While prewarming, autoprewarm will use two workers. There's a - * master worker that reads and sorts the list of blocks to be + * leader worker that reads and sorts the list of blocks to be * prewarmed and then launches a per-database worker for each * relevant database in turn. The former keeps running after the * initial prewarm is complete to update the dump file periodically. @@ -46,6 +46,7 @@ #include "storage/smgr.h" #include "tcop/tcopprot.h" #include "utils/acl.h" +#include "utils/datetime.h" #include "utils/guc.h" #include "utils/memutils.h" #include "utils/rel.h" @@ -88,7 +89,7 @@ PG_FUNCTION_INFO_V1(autoprewarm_dump_now); static void apw_load_buffers(void); static int apw_dump_now(bool is_bgworker, bool dump_unlogged); -static void apw_start_master_worker(void); +static void apw_start_leader_worker(void); static void apw_start_database_worker(void); static bool apw_init_shmem(void); static void apw_detach_shmem(int code, Datum arg); @@ -146,11 +147,11 @@ _PG_init(void) /* Register autoprewarm worker, if enabled. */ if (autoprewarm) - apw_start_master_worker(); + apw_start_leader_worker(); } /* - * Main entry point for the master autoprewarm process. Per-database workers + * Main entry point for the leader autoprewarm process. Per-database workers * have a separate entry point. */ void @@ -716,7 +717,7 @@ autoprewarm_start_worker(PG_FUNCTION_ARGS) errmsg("autoprewarm worker is already running under PID %lu", (unsigned long) pid))); - apw_start_master_worker(); + apw_start_leader_worker(); PG_RETURN_VOID(); } @@ -786,10 +787,10 @@ apw_detach_shmem(int code, Datum arg) } /* - * Start autoprewarm master worker process. + * Start autoprewarm leader worker process. */ static void -apw_start_master_worker(void) +apw_start_leader_worker(void) { BackgroundWorker worker; BackgroundWorkerHandle *handle; @@ -801,8 +802,8 @@ apw_start_master_worker(void) worker.bgw_start_time = BgWorkerStart_ConsistentState; strcpy(worker.bgw_library_name, "pg_prewarm"); strcpy(worker.bgw_function_name, "autoprewarm_main"); - strcpy(worker.bgw_name, "autoprewarm master"); - strcpy(worker.bgw_type, "autoprewarm master"); + strcpy(worker.bgw_name, "autoprewarm leader"); + strcpy(worker.bgw_type, "autoprewarm leader"); if (process_shared_preload_libraries_in_progress) { diff --git a/contrib/pg_stat_statements/expected/pg_stat_statements.out b/contrib/pg_stat_statements/expected/pg_stat_statements.out index f615f8c2bfd4..e0edb134f3dc 100644 --- a/contrib/pg_stat_statements/expected/pg_stat_statements.out +++ b/contrib/pg_stat_statements/expected/pg_stat_statements.out @@ -3,6 +3,7 @@ CREATE EXTENSION pg_stat_statements; -- simple and compound statements -- SET pg_stat_statements.track_utility = FALSE; +SET pg_stat_statements.track_planning = TRUE; SELECT pg_stat_statements_reset(); pg_stat_statements_reset -------------------------- @@ -527,6 +528,69 @@ SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C"; SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C" | 0 | 0 (9 rows) +-- +-- Track the total number of rows retrieved or affected by the utility +-- commands of COPY, FETCH, CREATE TABLE AS, CREATE MATERIALIZED VIEW +-- and SELECT INTO +-- +SELECT pg_stat_statements_reset(); + pg_stat_statements_reset +-------------------------- + +(1 row) + +CREATE TABLE pgss_ctas AS SELECT a, 'ctas' b FROM generate_series(1, 10) a; +SELECT generate_series(1, 10) c INTO pgss_select_into; +COPY pgss_ctas (a, b) FROM STDIN; +CREATE MATERIALIZED VIEW pgss_matv AS SELECT * FROM pgss_ctas; +BEGIN; +DECLARE pgss_cursor CURSOR FOR SELECT * FROM pgss_matv; +FETCH NEXT pgss_cursor; + a | b +---+------ + 1 | ctas +(1 row) + +FETCH FORWARD 5 pgss_cursor; + a | b +---+------ + 2 | ctas + 3 | ctas + 4 | ctas + 5 | ctas + 6 | ctas +(5 rows) + +FETCH FORWARD ALL pgss_cursor; + a | b +----+------ + 7 | ctas + 8 | ctas + 9 | ctas + 10 | ctas + 11 | copy + 12 | copy + 13 | copy +(7 rows) + +COMMIT; +SELECT query, plans, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C"; + query | plans | calls | rows +-------------------------------------------------------------------------------------+-------+-------+------ + BEGIN | 0 | 1 | 0 + COMMIT | 0 | 1 | 0 + COPY pgss_ctas (a, b) FROM STDIN | 0 | 1 | 3 + CREATE MATERIALIZED VIEW pgss_matv AS SELECT * FROM pgss_ctas | 0 | 1 | 13 + CREATE TABLE pgss_ctas AS SELECT a, 'ctas' b FROM generate_series(1, 10) a | 0 | 1 | 10 + DECLARE pgss_cursor CURSOR FOR SELECT * FROM pgss_matv | 0 | 1 | 0 + FETCH FORWARD 5 pgss_cursor | 0 | 1 | 5 + FETCH FORWARD ALL pgss_cursor | 0 | 1 | 7 + FETCH NEXT pgss_cursor | 0 | 1 | 1 + SELECT generate_series(1, 10) c INTO pgss_select_into | 0 | 1 | 10 + SELECT pg_stat_statements_reset() | 0 | 1 | 1 + SELECT query, plans, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C" | 1 | 0 | 0 +(12 rows) + -- -- Track user activity and reset them -- @@ -727,6 +791,9 @@ SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C"; -- DROP ROLE regress_stats_user1; DROP ROLE regress_stats_user2; +DROP MATERIALIZED VIEW pgss_matv; +DROP TABLE pgss_ctas; +DROP TABLE pgss_select_into; -- -- [re]plan counting -- diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c index cef8bb5a49a2..6b91c62c31a8 100644 --- a/contrib/pg_stat_statements/pg_stat_statements.c +++ b/contrib/pg_stat_statements/pg_stat_statements.c @@ -4,7 +4,7 @@ * Track statement planning and execution times as well as resource * usage across a whole database cluster. * - * Execution costs are totalled for each distinct source query, and kept in + * Execution costs are totaled for each distinct source query, and kept in * a shared hashtable. (We track only as many distinct queries as will fit * in the designated amount of shared memory.) * @@ -442,7 +442,7 @@ _PG_init(void) "Selects whether planning duration is tracked by pg_stat_statements.", NULL, &pgss_track_planning, - true, + false, PGC_SUSET, 0, NULL, @@ -1170,7 +1170,15 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString, INSTR_TIME_SET_CURRENT(duration); INSTR_TIME_SUBTRACT(duration, start); - rows = (qc && qc->commandTag == CMDTAG_COPY) ? qc->nprocessed : 0; + /* + * Track the total number of rows retrieved or affected by + * the utility statements of COPY, FETCH, CREATE TABLE AS, + * CREATE MATERIALIZED VIEW and SELECT INTO. + */ + rows = (qc && (qc->commandTag == CMDTAG_COPY || + qc->commandTag == CMDTAG_FETCH || + qc->commandTag == CMDTAG_SELECT)) ? + qc->nprocessed : 0; /* calc differences of buffer counters. */ memset(&bufusage, 0, sizeof(BufferUsage)); diff --git a/contrib/pg_stat_statements/sql/pg_stat_statements.sql b/contrib/pg_stat_statements/sql/pg_stat_statements.sql index 75c10554a891..996a24a293c5 100644 --- a/contrib/pg_stat_statements/sql/pg_stat_statements.sql +++ b/contrib/pg_stat_statements/sql/pg_stat_statements.sql @@ -4,6 +4,7 @@ CREATE EXTENSION pg_stat_statements; -- simple and compound statements -- SET pg_stat_statements.track_utility = FALSE; +SET pg_stat_statements.track_planning = TRUE; SELECT pg_stat_statements_reset(); SELECT 1 AS "int"; @@ -249,6 +250,30 @@ DROP FUNCTION PLUS_TWO(INTEGER); SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C"; +-- +-- Track the total number of rows retrieved or affected by the utility +-- commands of COPY, FETCH, CREATE TABLE AS, CREATE MATERIALIZED VIEW +-- and SELECT INTO +-- +SELECT pg_stat_statements_reset(); + +CREATE TABLE pgss_ctas AS SELECT a, 'ctas' b FROM generate_series(1, 10) a; +SELECT generate_series(1, 10) c INTO pgss_select_into; +COPY pgss_ctas (a, b) FROM STDIN; +11 copy +12 copy +13 copy +\. +CREATE MATERIALIZED VIEW pgss_matv AS SELECT * FROM pgss_ctas; +BEGIN; +DECLARE pgss_cursor CURSOR FOR SELECT * FROM pgss_matv; +FETCH NEXT pgss_cursor; +FETCH FORWARD 5 pgss_cursor; +FETCH FORWARD ALL pgss_cursor; +COMMIT; + +SELECT query, plans, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C"; + -- -- Track user activity and reset them -- @@ -312,6 +337,9 @@ SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C"; -- DROP ROLE regress_stats_user1; DROP ROLE regress_stats_user2; +DROP MATERIALIZED VIEW pgss_matv; +DROP TABLE pgss_ctas; +DROP TABLE pgss_select_into; -- -- [re]plan counting diff --git a/contrib/pg_trgm/pg_trgm--1.2--1.3.sql b/contrib/pg_trgm/pg_trgm--1.2--1.3.sql index b082dcd8d841..8dc772c40727 100644 --- a/contrib/pg_trgm/pg_trgm--1.2--1.3.sql +++ b/contrib/pg_trgm/pg_trgm--1.2--1.3.sql @@ -7,21 +7,36 @@ -- We use to_regprocedure() so that query doesn't fail if run against 9.6beta1 definitions, -- wherein the signatures have been updated already. In that case to_regprocedure() will -- return NULL and no updates will happen. +DO LANGUAGE plpgsql +$$ +DECLARE + my_schema pg_catalog.text := pg_catalog.quote_ident(pg_catalog.current_schema()); + old_path pg_catalog.text := pg_catalog.current_setting('search_path'); +BEGIN +-- for safety, transiently set search_path to just pg_catalog+pg_temp +PERFORM pg_catalog.set_config('search_path', 'pg_catalog, pg_temp', true); UPDATE pg_catalog.pg_proc SET proargtypes = pg_catalog.array_to_string(newtypes::pg_catalog.oid[], ' ')::pg_catalog.oidvector, pronargs = pg_catalog.array_length(newtypes, 1) FROM (VALUES -(NULL::pg_catalog.text, NULL::pg_catalog.regtype[]), -- establish column types +(NULL::pg_catalog.text, NULL::pg_catalog.text[]), -- establish column types ('gtrgm_consistent(internal,text,int4,oid,internal)', '{internal,text,int2,oid,internal}'), ('gtrgm_distance(internal,text,int4,oid)', '{internal,text,int2,oid,internal}'), ('gtrgm_union(bytea,internal)', '{internal,internal}') -) AS update_data (oldproc, newtypes) -WHERE oid = pg_catalog.to_regprocedure(oldproc); +) AS update_data (oldproc, newtypestext), +LATERAL ( + SELECT array_agg(replace(typ, 'SCH', my_schema)::regtype) as newtypes FROM unnest(newtypestext) typ +) ls +WHERE oid = to_regprocedure(my_schema || '.' || replace(oldproc, 'SCH', my_schema)); UPDATE pg_catalog.pg_proc SET - prorettype = 'gtrgm'::pg_catalog.regtype -WHERE oid = pg_catalog.to_regprocedure('gtrgm_union(internal,internal)'); + prorettype = (my_schema || '.gtrgm')::pg_catalog.regtype +WHERE oid = pg_catalog.to_regprocedure(my_schema || '.gtrgm_union(internal,internal)'); + +PERFORM pg_catalog.set_config('search_path', old_path, true); +END +$$; ALTER FUNCTION set_limit(float4) PARALLEL UNSAFE; ALTER FUNCTION show_limit() PARALLEL SAFE; diff --git a/contrib/pg_visibility/expected/pg_visibility.out b/contrib/pg_visibility/expected/pg_visibility.out index 2abc1b5107a0..ca4b6e186bca 100644 --- a/contrib/pg_visibility/expected/pg_visibility.out +++ b/contrib/pg_visibility/expected/pg_visibility.out @@ -102,8 +102,9 @@ ERROR: "test_foreign_table" is not a table, materialized view, or TOAST table select pg_truncate_visibility_map('test_foreign_table'); ERROR: "test_foreign_table" is not a table, materialized view, or TOAST table -- check some of the allowed relkinds -create table regular_table (a int); -insert into regular_table values (1), (2); +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; select count(*) > 0 from pg_visibility('regular_table'); ?column? @@ -111,6 +112,12 @@ select count(*) > 0 from pg_visibility('regular_table'); t (1 row) +select count(*) > 0 from pg_visibility((select reltoastrelid from pg_class where relname = 'regular_table')); + ?column? +---------- + t +(1 row) + truncate regular_table; select count(*) > 0 from pg_visibility('regular_table'); ?column? @@ -118,6 +125,12 @@ select count(*) > 0 from pg_visibility('regular_table'); f (1 row) +select count(*) > 0 from pg_visibility((select reltoastrelid from pg_class where relname = 'regular_table')); + ?column? +---------- + f +(1 row) + create materialized view matview_visibility_test as select * from regular_table; vacuum matview_visibility_test; select count(*) > 0 from pg_visibility('matview_visibility_test'); diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c index c98bc61eca47..a56d446d0e27 100644 --- a/contrib/pg_visibility/pg_visibility.c +++ b/contrib/pg_visibility/pg_visibility.c @@ -392,7 +392,7 @@ pg_truncate_visibility_map(PG_FUNCTION_ARGS) check_relation_relkind(rel); RelationOpenSmgr(rel); - rel->rd_smgr->smgr_vm_nblocks = InvalidBlockNumber; + rel->rd_smgr->smgr_cached_nblocks[VISIBILITYMAP_FORKNUM] = InvalidBlockNumber; block = visibilitymap_prepare_truncate(rel, 0); if (BlockNumberIsValid(block)) @@ -563,17 +563,14 @@ collect_corrupt_items(Oid relid, bool all_visible, bool all_frozen) BufferAccessStrategy bstrategy = GetAccessStrategy(BAS_BULKREAD); TransactionId OldestXmin = InvalidTransactionId; - if (all_visible) - { - /* Don't pass rel; that will fail in recovery. */ - OldestXmin = GetOldestXmin(NULL, PROCARRAY_FLAGS_VACUUM); - } - rel = relation_open(relid, AccessShareLock); /* Only some relkinds have a visibility map */ check_relation_relkind(rel); + if (all_visible) + OldestXmin = GetOldestNonRemovableTransactionId(rel); + nblocks = RelationGetNumberOfBlocks(rel); /* @@ -679,11 +676,12 @@ collect_corrupt_items(Oid relid, bool all_visible, bool all_frozen) * From a concurrency point of view, it sort of sucks to * retake ProcArrayLock here while we're holding the buffer * exclusively locked, but it should be safe against - * deadlocks, because surely GetOldestXmin() should never take - * a buffer lock. And this shouldn't happen often, so it's - * worth being careful so as to avoid false positives. + * deadlocks, because surely + * GetOldestNonRemovableTransactionId() should never take a + * buffer lock. And this shouldn't happen often, so it's worth + * being careful so as to avoid false positives. */ - RecomputedOldestXmin = GetOldestXmin(NULL, PROCARRAY_FLAGS_VACUUM); + RecomputedOldestXmin = GetOldestNonRemovableTransactionId(rel); if (!TransactionIdPrecedes(OldestXmin, RecomputedOldestXmin)) record_corrupt_item(items, &tuple.t_self); diff --git a/contrib/pg_visibility/sql/pg_visibility.sql b/contrib/pg_visibility/sql/pg_visibility.sql index c78b90521bfe..f79b54480b70 100644 --- a/contrib/pg_visibility/sql/pg_visibility.sql +++ b/contrib/pg_visibility/sql/pg_visibility.sql @@ -68,12 +68,15 @@ select pg_check_frozen('test_foreign_table'); select pg_truncate_visibility_map('test_foreign_table'); -- check some of the allowed relkinds -create table regular_table (a int); -insert into regular_table values (1), (2); +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; 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; 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; diff --git a/contrib/pgcrypto/crypt-des.c b/contrib/pgcrypto/crypt-des.c index 6efaa609c9d1..98c30ea122e3 100644 --- a/contrib/pgcrypto/crypt-des.c +++ b/contrib/pgcrypto/crypt-des.c @@ -720,7 +720,7 @@ px_crypt_des(const char *key, const char *setting) if (des_setkey((char *) keybuf)) return NULL; } - StrNCpy(output, setting, 10); + strlcpy(output, setting, 10); /* * Double check that we weren't given a short setting. If we were, the diff --git a/contrib/pgcrypto/expected/pgp-compression.out b/contrib/pgcrypto/expected/pgp-compression.out index 32b350b8fe05..d4c57feba30b 100644 --- a/contrib/pgcrypto/expected/pgp-compression.out +++ b/contrib/pgcrypto/expected/pgp-compression.out @@ -48,3 +48,33 @@ select pgp_sym_decrypt( Secret message (1 row) +-- check corner case involving an input string of 16kB, as per bug #16476. +SELECT setseed(0); + setseed +--------- + +(1 row) + +WITH random_string AS +( + -- This generates a random string of 16366 bytes. This is chosen + -- as random so that it does not get compressed, and the decompression + -- would work on a string with the same length as the origin, making the + -- test behavior more predictible. lpad() ensures that the generated + -- hexadecimal value is completed by extra zero characters if random() + -- has generated a value strictly lower than 16. + SELECT string_agg(decode(lpad(to_hex((random()*256)::int), 2, '0'), 'hex'), '') as bytes + FROM generate_series(0, 16365) +) +SELECT bytes = + pgp_sym_decrypt_bytea( + pgp_sym_encrypt_bytea(bytes, 'key', + 'compress-algo=1,compress-level=1'), + 'key', 'expect-compress-algo=1') + AS is_same + FROM random_string; + is_same +--------- + t +(1 row) + diff --git a/contrib/pgcrypto/pgp-compress.c b/contrib/pgcrypto/pgp-compress.c index 0505bdee9237..3636a662b076 100644 --- a/contrib/pgcrypto/pgp-compress.c +++ b/contrib/pgcrypto/pgp-compress.c @@ -114,13 +114,13 @@ compress_process(PushFilter *next, void *priv, const uint8 *data, int len) /* * process data */ - while (len > 0) + st->stream.next_in = unconstify(uint8 *, data); + st->stream.avail_in = len; + while (st->stream.avail_in > 0) { - st->stream.next_in = unconstify(uint8 *, data); - st->stream.avail_in = len; st->stream.next_out = st->buf; st->stream.avail_out = st->buf_len; - res = deflate(&st->stream, 0); + res = deflate(&st->stream, Z_NO_FLUSH); if (res != Z_OK) return PXE_PGP_COMPRESSION_ERROR; @@ -131,7 +131,6 @@ compress_process(PushFilter *next, void *priv, const uint8 *data, int len) if (res < 0) return res; } - len = st->stream.avail_in; } return 0; @@ -154,6 +153,7 @@ compress_flush(PushFilter *next, void *priv) zres = deflate(&st->stream, Z_FINISH); if (zres != Z_STREAM_END && zres != Z_OK) return PXE_PGP_COMPRESSION_ERROR; + n_out = st->buf_len - st->stream.avail_out; if (n_out > 0) { @@ -286,7 +286,28 @@ decompress_read(void *priv, PullFilter *src, int len, dec->buf_data = dec->buf_len - dec->stream.avail_out; if (res == Z_STREAM_END) + { + uint8 *tmp; + + /* + * A stream must be terminated by a normal packet. If the last stream + * packet in the source stream is a full packet, a normal empty packet + * must follow. Since the underlying packet reader doesn't know that + * the compressed stream has been ended, we need to to consume the + * terminating packet here. This read does not harm even if the + * stream has already ended. + */ + res = pullf_read(src, 1, &tmp); + + if (res < 0) + return res; + else if (res > 0) + { + px_debug("decompress_read: extra bytes after end of stream"); + return PXE_PGP_CORRUPT_DATA; + } dec->eof = 1; + } goto restart; } diff --git a/contrib/pgcrypto/sql/pgp-compression.sql b/contrib/pgcrypto/sql/pgp-compression.sql index ca9ee1fc0088..87c59c6cabc4 100644 --- a/contrib/pgcrypto/sql/pgp-compression.sql +++ b/contrib/pgcrypto/sql/pgp-compression.sql @@ -28,3 +28,24 @@ select pgp_sym_decrypt( pgp_sym_encrypt('Secret message', 'key', 'compress-algo=2, compress-level=0'), 'key', 'expect-compress-algo=0'); + +-- check corner case involving an input string of 16kB, as per bug #16476. +SELECT setseed(0); +WITH random_string AS +( + -- This generates a random string of 16366 bytes. This is chosen + -- as random so that it does not get compressed, and the decompression + -- would work on a string with the same length as the origin, making the + -- test behavior more predictible. lpad() ensures that the generated + -- hexadecimal value is completed by extra zero characters if random() + -- has generated a value strictly lower than 16. + SELECT string_agg(decode(lpad(to_hex((random()*256)::int), 2, '0'), 'hex'), '') as bytes + FROM generate_series(0, 16365) +) +SELECT bytes = + pgp_sym_decrypt_bytea( + pgp_sym_encrypt_bytea(bytes, 'key', + 'compress-algo=1,compress-level=1'), + 'key', 'expect-compress-algo=1') + AS is_same + FROM random_string; diff --git a/contrib/pgstattuple/expected/pgstattuple.out b/contrib/pgstattuple/expected/pgstattuple.out index 1a12483b34bb..4542d692b55a 100644 --- a/contrib/pgstattuple/expected/pgstattuple.out +++ b/contrib/pgstattuple/expected/pgstattuple.out @@ -159,7 +159,7 @@ ERROR: "test_partitioned" (partitioned table) is not supported select pgstattuple('test_partitioned_index'); ERROR: "test_partitioned_index" (partitioned index) is not supported select pgstattuple_approx('test_partitioned'); -ERROR: "test_partitioned" is not a table or materialized view +ERROR: "test_partitioned" is not a table, materialized view, or TOAST table select pg_relpages('test_partitioned'); ERROR: "test_partitioned" is not a table, index, materialized view, sequence, or TOAST table select pgstatindex('test_partitioned'); @@ -173,7 +173,7 @@ create view test_view as select 1; select pgstattuple('test_view'); ERROR: "test_view" (view) is not supported select pgstattuple_approx('test_view'); -ERROR: "test_view" is not a table or materialized view +ERROR: "test_view" is not a table, materialized view, or TOAST table select pg_relpages('test_view'); ERROR: "test_view" is not a table, index, materialized view, sequence, or TOAST table select pgstatindex('test_view'); @@ -189,7 +189,7 @@ create foreign table test_foreign_table () server dummy_server; select pgstattuple('test_foreign_table'); ERROR: "test_foreign_table" (foreign table) is not supported select pgstattuple_approx('test_foreign_table'); -ERROR: "test_foreign_table" is not a table or materialized view +ERROR: "test_foreign_table" is not a table, materialized view, or TOAST table select pg_relpages('test_foreign_table'); ERROR: "test_foreign_table" is not a table, index, materialized view, sequence, or TOAST table select pgstatindex('test_foreign_table'); @@ -218,6 +218,25 @@ select pg_relpages('test_partition'); 0 (1 row) +-- toast tables should work +select pgstattuple((select reltoastrelid from pg_class where relname = 'test')); + pgstattuple +--------------------- + (0,0,0,0,0,0,0,0,0) +(1 row) + +select pgstattuple_approx((select reltoastrelid from pg_class where relname = 'test')); + pgstattuple_approx +----------------------- + (0,0,0,0,0,0,0,0,0,0) +(1 row) + +select pg_relpages((select reltoastrelid from pg_class where relname = 'test')); + pg_relpages +------------- + 0 +(1 row) + -- not for the index calls though, of course select pgstatindex('test_partition'); ERROR: relation "test_partition" is not a btree index diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c index 870ec7c17efc..a04a24c3ca9d 100644 --- a/contrib/pgstattuple/pgstatapprox.c +++ b/contrib/pgstattuple/pgstatapprox.c @@ -71,7 +71,7 @@ statapprox_heap(Relation rel, output_type *stat) BufferAccessStrategy bstrategy; TransactionId OldestXmin; - OldestXmin = GetOldestXmin(rel, PROCARRAY_FLAGS_VACUUM); + OldestXmin = GetOldestNonRemovableTransactionId(rel); bstrategy = GetAccessStrategy(BAS_BULKREAD); nblocks = RelationGetNumberOfBlocks(rel); @@ -278,18 +278,22 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo) errmsg("cannot access temporary tables of other sessions"))); /* - * We support only ordinary relations and materialised views, because we - * depend on the visibility map and free space map for our estimates about - * unscanned pages. + * We support only relation kinds with a visibility map and a free space + * map. */ if (!(rel->rd_rel->relkind == RELKIND_RELATION || +<<<<<<< HEAD rel->rd_rel->relkind == RELKIND_AOSEGMENTS || rel->rd_rel->relkind == RELKIND_AOBLOCKDIR || rel->rd_rel->relkind == RELKIND_AOVISIMAP || rel->rd_rel->relkind == RELKIND_MATVIEW)) +======= + rel->rd_rel->relkind == RELKIND_MATVIEW || + rel->rd_rel->relkind == RELKIND_TOASTVALUE)) +>>>>>>> d259afa7365165760004c2fdbe2520a94ddf2600 ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("\"%s\" is not a table or materialized view", + errmsg("\"%s\" is not a table, materialized view, or TOAST table", RelationGetRelationName(rel)))); if (rel->rd_rel->relam != HEAP_TABLE_AM_OID) diff --git a/contrib/pgstattuple/sql/pgstattuple.sql b/contrib/pgstattuple/sql/pgstattuple.sql index 0cef062ac711..e08b9febc590 100644 --- a/contrib/pgstattuple/sql/pgstattuple.sql +++ b/contrib/pgstattuple/sql/pgstattuple.sql @@ -100,6 +100,11 @@ select pgstattuple('test_partition'); select pgstattuple_approx('test_partition'); select pg_relpages('test_partition'); +-- toast tables should work +select pgstattuple((select reltoastrelid from pg_class where relname = 'test')); +select pgstattuple_approx((select reltoastrelid from pg_class where relname = 'test')); +select pg_relpages((select reltoastrelid from pg_class where relname = 'test')); + -- not for the index calls though, of course select pgstatindex('test_partition'); select pgstatginindex('test_partition'); diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c index cda0e2469efc..ce6e07fb565f 100644 --- a/contrib/postgres_fdw/connection.c +++ b/contrib/postgres_fdw/connection.c @@ -22,6 +22,7 @@ #include "postgres_fdw.h" #include "storage/fd.h" #include "storage/latch.h" +#include "utils/datetime.h" #include "utils/hsearch.h" #include "utils/inval.h" #include "utils/memutils.h" diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index 0e0086596a53..84bc0ee38171 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -2715,7 +2715,7 @@ select sum(c1) from ft1 group by c2 having avg(c1 * (random() <= 1)::int) > 100 Group Key: ft1.c2 Filter: (avg((ft1.c1 * ((random() <= '1'::double precision))::integer)) > '100'::numeric) -> Foreign Scan on public.ft1 - Output: c2, c1 + Output: c1, c2 Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" (10 rows) @@ -2964,7 +2964,7 @@ select sum(c1) filter (where (c1 / c1) * random() <= 1) from ft1 group by c2 ord Output: sum(c1) FILTER (WHERE ((((c1 / c1))::double precision * random()) <= '1'::double precision)), c2 Group Key: ft1.c2 -> Foreign Scan on public.ft1 - Output: c2, c1 + Output: c1, c2 Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" (9 rows) diff --git a/contrib/seg/seg--1.0--1.1.sql b/contrib/seg/seg--1.0--1.1.sql index 2dcd4d428003..ae6cb2fba889 100644 --- a/contrib/seg/seg--1.0--1.1.sql +++ b/contrib/seg/seg--1.0--1.1.sql @@ -7,15 +7,30 @@ -- We use to_regprocedure() so that query doesn't fail if run against 9.6beta1 definitions, -- wherein the signatures have been updated already. In that case to_regprocedure() will -- return NULL and no updates will happen. +DO LANGUAGE plpgsql +$$ +DECLARE + my_schema pg_catalog.text := pg_catalog.quote_ident(pg_catalog.current_schema()); + old_path pg_catalog.text := pg_catalog.current_setting('search_path'); +BEGIN +-- for safety, transiently set search_path to just pg_catalog+pg_temp +PERFORM pg_catalog.set_config('search_path', 'pg_catalog, pg_temp', true); UPDATE pg_catalog.pg_proc SET proargtypes = pg_catalog.array_to_string(newtypes::pg_catalog.oid[], ' ')::pg_catalog.oidvector, pronargs = pg_catalog.array_length(newtypes, 1) FROM (VALUES -(NULL::pg_catalog.text, NULL::pg_catalog.regtype[]), -- establish column types -('gseg_consistent(internal,seg,int4,oid,internal)', '{internal,seg,int2,oid,internal}') -) AS update_data (oldproc, newtypes) -WHERE oid = pg_catalog.to_regprocedure(oldproc); +(NULL::pg_catalog.text, NULL::pg_catalog.text[]), -- establish column types +('gseg_consistent(internal,SCH.seg,int4,oid,internal)', '{internal,SCH.seg,int2,oid,internal}') +) AS update_data (oldproc, newtypestext), +LATERAL ( + SELECT array_agg(replace(typ, 'SCH', my_schema)::regtype) as newtypes FROM unnest(newtypestext) typ +) ls +WHERE oid = to_regprocedure(my_schema || '.' || replace(oldproc, 'SCH', my_schema)); + +PERFORM pg_catalog.set_config('search_path', old_path, true); +END +$$; ALTER FUNCTION seg_in(cstring) PARALLEL SAFE; ALTER FUNCTION seg_out(seg) PARALLEL SAFE; diff --git a/contrib/seg/seg--1.2--1.3.sql b/contrib/seg/seg--1.2--1.3.sql index 5b36b5374d4e..dbe2b5e55b22 100644 --- a/contrib/seg/seg--1.2--1.3.sql +++ b/contrib/seg/seg--1.2--1.3.sql @@ -12,6 +12,15 @@ -- bound into a particular opclass. There's no SQL command for that, -- so fake it with a manual update on pg_depend. -- +DO LANGUAGE plpgsql +$$ +DECLARE + my_schema pg_catalog.text := pg_catalog.quote_ident(pg_catalog.current_schema()); + old_path pg_catalog.text := pg_catalog.current_setting('search_path'); +BEGIN +-- for safety, transiently set search_path to just pg_catalog+pg_temp +PERFORM pg_catalog.set_config('search_path', 'pg_catalog, pg_temp', true); + UPDATE pg_catalog.pg_depend SET deptype = 'a' WHERE classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass @@ -20,14 +29,10 @@ WHERE classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass FROM pg_catalog.pg_depend WHERE classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass AND refclassid = 'pg_catalog.pg_proc'::pg_catalog.regclass - AND (refobjid = 'gseg_compress(pg_catalog.internal)'::pg_catalog.regprocedure)) + AND (refobjid = (my_schema || '.gseg_compress(internal)')::pg_catalog.regprocedure)) AND refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass AND deptype = 'i'; -ALTER OPERATOR FAMILY gist_seg_ops USING gist drop function 3 (seg); -ALTER EXTENSION seg DROP function gseg_compress(pg_catalog.internal); -DROP function gseg_compress(pg_catalog.internal); - UPDATE pg_catalog.pg_depend SET deptype = 'a' WHERE classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass @@ -36,10 +41,18 @@ WHERE classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass FROM pg_catalog.pg_depend WHERE classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass AND refclassid = 'pg_catalog.pg_proc'::pg_catalog.regclass - AND (refobjid = 'gseg_decompress(pg_catalog.internal)'::pg_catalog.regprocedure)) + AND (refobjid = (my_schema || '.gseg_decompress(internal)')::pg_catalog.regprocedure)) AND refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass AND deptype = 'i'; +PERFORM pg_catalog.set_config('search_path', old_path, true); +END +$$; + +ALTER OPERATOR FAMILY gist_seg_ops USING gist drop function 3 (seg); +ALTER EXTENSION seg DROP function gseg_compress(pg_catalog.internal); +DROP function gseg_compress(pg_catalog.internal); + ALTER OPERATOR FAMILY gist_seg_ops USING gist drop function 4 (seg); ALTER EXTENSION seg DROP function gseg_decompress(pg_catalog.internal); DROP function gseg_decompress(pg_catalog.internal); diff --git a/contrib/sepgsql/database.c b/contrib/sepgsql/database.c index 4e83b7bfa8c0..ec2037859379 100644 --- a/contrib/sepgsql/database.c +++ b/contrib/sepgsql/database.c @@ -142,7 +142,7 @@ sepgsql_database_drop(Oid databaseId) object.classId = DatabaseRelationId; object.objectId = databaseId; object.objectSubId = 0; - audit_name = getObjectIdentity(&object); + audit_name = getObjectIdentity(&object, false); sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_DATABASE, @@ -169,7 +169,7 @@ sepgsql_database_setattr(Oid databaseId) object.classId = DatabaseRelationId; object.objectId = databaseId; object.objectSubId = 0; - audit_name = getObjectIdentity(&object); + audit_name = getObjectIdentity(&object, false); sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_DATABASE, @@ -193,7 +193,7 @@ sepgsql_database_relabel(Oid databaseId, const char *seclabel) object.classId = DatabaseRelationId; object.objectId = databaseId; object.objectSubId = 0; - audit_name = getObjectIdentity(&object); + audit_name = getObjectIdentity(&object, false); /* * check db_database:{setattr relabelfrom} permission diff --git a/contrib/sepgsql/dml.c b/contrib/sepgsql/dml.c index 53f6f41c5c41..75ee612bcdae 100644 --- a/contrib/sepgsql/dml.c +++ b/contrib/sepgsql/dml.c @@ -179,7 +179,7 @@ check_relation_privileges(Oid relOid, object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = 0; - audit_name = getObjectIdentity(&object); + audit_name = getObjectIdentity(&object, false); switch (relkind) { case RELKIND_RELATION: @@ -256,7 +256,7 @@ check_relation_privileges(Oid relOid, object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = attnum; - audit_name = getObjectDescription(&object); + audit_name = getObjectDescription(&object, false); result = sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_COLUMN, diff --git a/contrib/sepgsql/label.c b/contrib/sepgsql/label.c index 147ab67f3220..b00b91df5aa3 100644 --- a/contrib/sepgsql/label.c +++ b/contrib/sepgsql/label.c @@ -120,7 +120,7 @@ sepgsql_set_client_label(const char *new_label) tcontext = client_label_peer; else { - if (security_check_context_raw((security_context_t) new_label) < 0) + if (security_check_context_raw(new_label) < 0) ereport(ERROR, (errcode(ERRCODE_INVALID_NAME), errmsg("SELinux: invalid security label: \"%s\"", @@ -355,7 +355,7 @@ sepgsql_fmgr_hook(FmgrHookEventType event, sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_PROCEDURE, SEPG_DB_PROCEDURE__ENTRYPOINT, - getObjectDescription(&object), + getObjectDescription(&object, false), true); sepgsql_avc_check_perms_label(stack->new_label, @@ -453,9 +453,9 @@ sepgsql_get_label(Oid classId, Oid objectId, int32 subId) object.objectSubId = subId; label = GetSecurityLabel(&object, SEPGSQL_LABEL_TAG); - if (!label || security_check_context_raw((security_context_t) label)) + if (!label || security_check_context_raw(label)) { - security_context_t unlabeled; + char *unlabeled; if (security_get_initial_context_raw("unlabeled", &unlabeled) < 0) ereport(ERROR, @@ -487,7 +487,7 @@ sepgsql_object_relabel(const ObjectAddress *object, const char *seclabel) * context of selinux. */ if (seclabel && - security_check_context_raw((security_context_t) seclabel) < 0) + security_check_context_raw(seclabel) < 0) ereport(ERROR, (errcode(ERRCODE_INVALID_NAME), errmsg("SELinux: invalid security label: \"%s\"", seclabel))); @@ -523,7 +523,7 @@ sepgsql_object_relabel(const ObjectAddress *object, const char *seclabel) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("sepgsql provider does not support labels on %s", - getObjectTypeDescription(object)))); + getObjectTypeDescription(object, false)))); break; } } @@ -725,7 +725,7 @@ exec_object_restorecon(struct selabel_handle *sehnd, Oid catalogId) char *objname; int objtype = 1234; ObjectAddress object; - security_context_t context; + char *context; /* * The way to determine object name depends on object classes. So, any diff --git a/contrib/sepgsql/proc.c b/contrib/sepgsql/proc.c index 2c244a90033d..d5d7dbe103ba 100644 --- a/contrib/sepgsql/proc.c +++ b/contrib/sepgsql/proc.c @@ -80,7 +80,7 @@ sepgsql_proc_post_create(Oid functionId) sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_SCHEMA, SEPG_DB_SCHEMA__ADD_NAME, - getObjectIdentity(&object), + getObjectIdentity(&object, false), true); /* @@ -114,7 +114,7 @@ sepgsql_proc_post_create(Oid functionId) object.classId = TypeRelationId; object.objectId = proForm->proargtypes.values[i]; object.objectSubId = 0; - appendStringInfoString(&audit_name, getObjectIdentity(&object)); + appendStringInfoString(&audit_name, getObjectIdentity(&object, false)); } appendStringInfoChar(&audit_name, ')'); @@ -164,7 +164,7 @@ sepgsql_proc_drop(Oid functionId) object.classId = NamespaceRelationId; object.objectId = get_func_namespace(functionId); object.objectSubId = 0; - audit_name = getObjectIdentity(&object); + audit_name = getObjectIdentity(&object, false); sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_SCHEMA, @@ -179,7 +179,7 @@ sepgsql_proc_drop(Oid functionId) object.classId = ProcedureRelationId; object.objectId = functionId; object.objectSubId = 0; - audit_name = getObjectIdentity(&object); + audit_name = getObjectIdentity(&object, false); sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_PROCEDURE, @@ -204,7 +204,7 @@ sepgsql_proc_relabel(Oid functionId, const char *seclabel) object.classId = ProcedureRelationId; object.objectId = functionId; object.objectSubId = 0; - audit_name = getObjectIdentity(&object); + audit_name = getObjectIdentity(&object, false); /* * check db_procedure:{setattr relabelfrom} permission @@ -292,7 +292,7 @@ sepgsql_proc_setattr(Oid functionId) object.classId = ProcedureRelationId; object.objectId = functionId; object.objectSubId = 0; - audit_name = getObjectIdentity(&object); + audit_name = getObjectIdentity(&object, false); sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_PROCEDURE, @@ -324,7 +324,7 @@ sepgsql_proc_execute(Oid functionId) object.classId = ProcedureRelationId; object.objectId = functionId; object.objectSubId = 0; - audit_name = getObjectIdentity(&object); + audit_name = getObjectIdentity(&object, false); sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_PROCEDURE, SEPG_DB_PROCEDURE__EXECUTE, diff --git a/contrib/sepgsql/relation.c b/contrib/sepgsql/relation.c index 380bc6094d55..96c57854a21a 100644 --- a/contrib/sepgsql/relation.c +++ b/contrib/sepgsql/relation.c @@ -102,7 +102,7 @@ sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum) initStringInfo(&audit_name); appendStringInfo(&audit_name, "%s.%s", - getObjectIdentity(&object), + getObjectIdentity(&object, false), quote_identifier(NameStr(attForm->attname))); sepgsql_avc_check_perms_label(ncontext, SEPG_CLASS_DB_COLUMN, @@ -146,7 +146,7 @@ sepgsql_attribute_drop(Oid relOid, AttrNumber attnum) object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = attnum; - audit_name = getObjectIdentity(&object); + audit_name = getObjectIdentity(&object, false); sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_COLUMN, @@ -178,7 +178,7 @@ sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum, object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = attnum; - audit_name = getObjectIdentity(&object); + audit_name = getObjectIdentity(&object, false); /* * check db_column:{setattr relabelfrom} permission @@ -222,7 +222,7 @@ sepgsql_attribute_setattr(Oid relOid, AttrNumber attnum) object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = attnum; - audit_name = getObjectIdentity(&object); + audit_name = getObjectIdentity(&object, false); sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_COLUMN, @@ -288,7 +288,7 @@ sepgsql_relation_post_create(Oid relOid) sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_SCHEMA, SEPG_DB_SCHEMA__ADD_NAME, - getObjectIdentity(&object), + getObjectIdentity(&object, false), true); switch (classForm->relkind) @@ -450,7 +450,7 @@ sepgsql_relation_drop(Oid relOid) object.classId = NamespaceRelationId; object.objectId = get_rel_namespace(relOid); object.objectSubId = 0; - audit_name = getObjectIdentity(&object); + audit_name = getObjectIdentity(&object, false); sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_SCHEMA, @@ -472,7 +472,7 @@ sepgsql_relation_drop(Oid relOid) object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = 0; - audit_name = getObjectIdentity(&object); + audit_name = getObjectIdentity(&object, false); sepgsql_avc_check_perms(&object, tclass, @@ -503,7 +503,7 @@ sepgsql_relation_drop(Oid relOid) object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = attForm->attnum; - audit_name = getObjectIdentity(&object); + audit_name = getObjectIdentity(&object, false); sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_COLUMN, @@ -546,7 +546,7 @@ sepgsql_relation_truncate(Oid relOid) object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = 0; - audit_name = getObjectIdentity(&object); + audit_name = getObjectIdentity(&object, false); sepgsql_avc_check_perms(&object, tclass, @@ -584,7 +584,7 @@ sepgsql_relation_relabel(Oid relOid, const char *seclabel) object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = 0; - audit_name = getObjectIdentity(&object); + audit_name = getObjectIdentity(&object, false); /* * check db_xxx:{setattr relabelfrom} permission @@ -695,7 +695,7 @@ sepgsql_relation_setattr(Oid relOid) object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = 0; - audit_name = getObjectIdentity(&object); + audit_name = getObjectIdentity(&object, false); sepgsql_avc_check_perms(&object, tclass, diff --git a/contrib/sepgsql/schema.c b/contrib/sepgsql/schema.c index 90ecbc172553..3b2b80be831e 100644 --- a/contrib/sepgsql/schema.c +++ b/contrib/sepgsql/schema.c @@ -123,7 +123,7 @@ sepgsql_schema_drop(Oid namespaceId) object.classId = NamespaceRelationId; object.objectId = namespaceId; object.objectSubId = 0; - audit_name = getObjectIdentity(&object); + audit_name = getObjectIdentity(&object, false); sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_SCHEMA, @@ -148,7 +148,7 @@ sepgsql_schema_relabel(Oid namespaceId, const char *seclabel) object.classId = NamespaceRelationId; object.objectId = namespaceId; object.objectSubId = 0; - audit_name = getObjectIdentity(&object); + audit_name = getObjectIdentity(&object, false); /* * check db_schema:{setattr relabelfrom} permission @@ -186,7 +186,7 @@ check_schema_perms(Oid namespaceId, uint32 required, bool abort_on_violation) object.classId = NamespaceRelationId; object.objectId = namespaceId; object.objectSubId = 0; - audit_name = getObjectIdentity(&object); + audit_name = getObjectIdentity(&object, false); result = sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_SCHEMA, diff --git a/contrib/sepgsql/selinux.c b/contrib/sepgsql/selinux.c index 9fdc810f2ed4..2695e88f23c9 100644 --- a/contrib/sepgsql/selinux.c +++ b/contrib/sepgsql/selinux.c @@ -768,8 +768,8 @@ sepgsql_compute_avd(const char *scontext, * Ask SELinux what is allowed set of permissions on a pair of the * security contexts and the given object class. */ - if (security_compute_av_flags_raw((security_context_t) scontext, - (security_context_t) tcontext, + if (security_compute_av_flags_raw(scontext, + tcontext, tclass_ex, 0, &avd_ex) < 0) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), @@ -838,7 +838,7 @@ sepgsql_compute_create(const char *scontext, uint16 tclass, const char *objname) { - security_context_t ncontext; + char *ncontext; security_class_t tclass_ex; const char *tclass_name; char *result; @@ -853,8 +853,8 @@ sepgsql_compute_create(const char *scontext, * Ask SELinux what is the default context for the given object class on a * pair of security contexts */ - if (security_compute_create_name_raw((security_context_t) scontext, - (security_context_t) tcontext, + if (security_compute_create_name_raw(scontext, + tcontext, tclass_ex, objname, &ncontext) < 0) diff --git a/contrib/sepgsql/uavc.c b/contrib/sepgsql/uavc.c index 639a52c5567b..97189b7c46f0 100644 --- a/contrib/sepgsql/uavc.c +++ b/contrib/sepgsql/uavc.c @@ -171,7 +171,7 @@ sepgsql_avc_unlabeled(void) { if (!avc_unlabeled) { - security_context_t unlabeled; + char *unlabeled; if (security_get_initial_context_raw("unlabeled", &unlabeled) < 0) ereport(ERROR, @@ -216,7 +216,7 @@ sepgsql_avc_compute(const char *scontext, const char *tcontext, uint16 tclass) * policy is reloaded, validation status shall be kept, so we also cache * whether the supplied security context was valid, or not. */ - if (security_check_context_raw((security_context_t) tcontext) != 0) + if (security_check_context_raw(tcontext) != 0) ucontext = sepgsql_avc_unlabeled(); /* diff --git a/contrib/test_decoding/Makefile b/contrib/test_decoding/Makefile index f439c582a5f9..ed9a3d6c0ede 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 + spill slot truncate stream ISOLATION = mxact delayed_startup ondisk_startup concurrent_ddl_dml \ oldest_xmin snapshot_transfer subxact_without_top diff --git a/contrib/test_decoding/expected/stream.out b/contrib/test_decoding/expected/stream.out new file mode 100644 index 000000000000..d7e32f818546 --- /dev/null +++ b/contrib/test_decoding/expected/stream.out @@ -0,0 +1,94 @@ +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 +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); +COMMIT; +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL, 'include-xids', '0', 'skip-empty-xacts', '1', 'stream-changes', '1'); + data +---------------------------------------------------------- + opening a streamed block for transaction + streaming message: transactional: 1 prefix: test, sz: 50 + closing a streamed block for transaction + aborting streamed (sub)transaction + 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 + committing streamed transaction +(27 rows) + +-- streaming test for toast changes +ALTER TABLE stream_test ALTER COLUMN data set storage external; +-- consume DDL +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); + data +------ +(0 rows) + +INSERT INTO stream_test SELECT repeat('a', 6000) || g.i FROM generate_series(1, 10) g(i); +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL, 'include-xids', '0', 'skip-empty-xacts', '1', 'stream-changes', '1'); + data +------------------------------------------ + 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 + closing a streamed block for transaction + committing streamed transaction +(13 rows) + +DROP TABLE stream_test; +SELECT pg_drop_replication_slot('regression_slot'); + pg_drop_replication_slot +-------------------------- + +(1 row) + diff --git a/contrib/test_decoding/expected/truncate.out b/contrib/test_decoding/expected/truncate.out index 1cf2ae835c84..e64d377214ab 100644 --- a/contrib/test_decoding/expected/truncate.out +++ b/contrib/test_decoding/expected/truncate.out @@ -25,3 +25,9 @@ SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'inc COMMIT (9 rows) +SELECT pg_drop_replication_slot('regression_slot'); + pg_drop_replication_slot +-------------------------- + +(1 row) + diff --git a/contrib/test_decoding/sql/stream.sql b/contrib/test_decoding/sql/stream.sql new file mode 100644 index 000000000000..ce86c816d11f --- /dev/null +++ b/contrib/test_decoding/sql/stream.sql @@ -0,0 +1,30 @@ +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 +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); +COMMIT; + +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL, 'include-xids', '0', 'skip-empty-xacts', '1', 'stream-changes', '1'); + +-- streaming test for toast changes +ALTER TABLE stream_test ALTER COLUMN data set storage external; +-- consume DDL +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); + +INSERT INTO stream_test SELECT repeat('a', 6000) || g.i FROM generate_series(1, 10) g(i); +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL, 'include-xids', '0', 'skip-empty-xacts', '1', 'stream-changes', '1'); + +DROP TABLE stream_test; +SELECT pg_drop_replication_slot('regression_slot'); diff --git a/contrib/test_decoding/sql/truncate.sql b/contrib/test_decoding/sql/truncate.sql index 5aecdf0881f5..5633854e0dfc 100644 --- a/contrib/test_decoding/sql/truncate.sql +++ b/contrib/test_decoding/sql/truncate.sql @@ -11,3 +11,4 @@ TRUNCATE tab1, tab1 RESTART IDENTITY CASCADE; TRUNCATE tab1, tab2; SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +SELECT pg_drop_replication_slot('regression_slot'); diff --git a/contrib/test_decoding/test_decoding.c b/contrib/test_decoding/test_decoding.c index 93c948856e7b..34745150e9ba 100644 --- a/contrib/test_decoding/test_decoding.c +++ b/contrib/test_decoding/test_decoding.c @@ -62,6 +62,28 @@ static void pg_decode_message(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, XLogRecPtr message_lsn, bool transactional, const char *prefix, Size sz, const char *message); +static void pg_decode_stream_start(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn); +static void pg_decode_stream_stop(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn); +static void pg_decode_stream_abort(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr abort_lsn); +static void pg_decode_stream_commit(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr commit_lsn); +static void pg_decode_stream_change(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + Relation relation, + ReorderBufferChange *change); +static void pg_decode_stream_message(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, XLogRecPtr message_lsn, + bool transactional, const char *prefix, + Size sz, const char *message); +static void pg_decode_stream_truncate(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + int nrelations, Relation relations[], + ReorderBufferChange *change); void _PG_init(void) @@ -83,6 +105,13 @@ _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->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_commit_cb = pg_decode_stream_commit; + cb->stream_change_cb = pg_decode_stream_change; + cb->stream_message_cb = pg_decode_stream_message; + cb->stream_truncate_cb = pg_decode_stream_truncate; } @@ -93,6 +122,7 @@ pg_decode_startup(LogicalDecodingContext *ctx, OutputPluginOptions *opt, { ListCell *option; TestDecodingData *data; + bool enable_streaming = false; data = palloc0(sizeof(TestDecodingData)); data->context = AllocSetContextCreate(ctx->context, @@ -183,6 +213,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, "stream-changes") == 0) + { + if (elem->arg == NULL) + continue; + else if (!parse_bool(strVal(elem->arg), &enable_streaming)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("could not parse value \"%s\" for parameter \"%s\"", + strVal(elem->arg), elem->defname))); + } else { ereport(ERROR, @@ -192,6 +232,8 @@ pg_decode_startup(LogicalDecodingContext *ctx, OutputPluginOptions *opt, elem->arg ? strVal(elem->arg) : "(null)"))); } } + + ctx->streaming &= enable_streaming; } /* cleanup this plugin's resources */ @@ -540,3 +582,150 @@ pg_decode_message(LogicalDecodingContext *ctx, appendBinaryStringInfo(ctx->out, message, sz); OutputPluginWrite(ctx, true); } + +/* + * We never try to stream any empty xact so we don't need any special handling + * for skip_empty_xacts in streaming mode APIs. + */ +static void +pg_decode_stream_start(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn) +{ + TestDecodingData *data = ctx->output_plugin_private; + + OutputPluginPrepareWrite(ctx, true); + if (data->include_xids) + appendStringInfo(ctx->out, "opening a streamed block for transaction TXN %u", txn->xid); + else + appendStringInfo(ctx->out, "opening a streamed block for transaction"); + OutputPluginWrite(ctx, true); +} + +/* + * We never try to stream any empty xact so we don't need any special handling + * for skip_empty_xacts in streaming mode APIs. + */ +static void +pg_decode_stream_stop(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn) +{ + TestDecodingData *data = ctx->output_plugin_private; + + OutputPluginPrepareWrite(ctx, true); + if (data->include_xids) + appendStringInfo(ctx->out, "closing a streamed block for transaction TXN %u", txn->xid); + else + appendStringInfo(ctx->out, "closing a streamed block for transaction"); + OutputPluginWrite(ctx, true); +} + +/* + * We never try to stream any empty xact so we don't need any special handling + * for skip_empty_xacts in streaming mode APIs. + */ +static void +pg_decode_stream_abort(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr abort_lsn) +{ + TestDecodingData *data = ctx->output_plugin_private; + + OutputPluginPrepareWrite(ctx, true); + if (data->include_xids) + appendStringInfo(ctx->out, "aborting streamed (sub)transaction TXN %u", txn->xid); + else + appendStringInfo(ctx->out, "aborting streamed (sub)transaction"); + OutputPluginWrite(ctx, true); +} + +/* + * We never try to stream any empty xact so we don't need any special handling + * for skip_empty_xacts in streaming mode APIs. + */ +static void +pg_decode_stream_commit(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr commit_lsn) +{ + TestDecodingData *data = ctx->output_plugin_private; + + OutputPluginPrepareWrite(ctx, true); + + if (data->include_xids) + appendStringInfo(ctx->out, "committing streamed transaction TXN %u", txn->xid); + else + appendStringInfo(ctx->out, "committing streamed transaction"); + + if (data->include_timestamp) + appendStringInfo(ctx->out, " (at %s)", + timestamptz_to_str(txn->commit_time)); + + OutputPluginWrite(ctx, true); +} + +/* + * In streaming mode, we don't display the changes as the transaction can abort + * at a later point in time. We don't want users to see the changes until the + * transaction is committed. + */ +static void +pg_decode_stream_change(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + Relation relation, + ReorderBufferChange *change) +{ + TestDecodingData *data = ctx->output_plugin_private; + + OutputPluginPrepareWrite(ctx, true); + if (data->include_xids) + appendStringInfo(ctx->out, "streaming change for TXN %u", txn->xid); + else + appendStringInfo(ctx->out, "streaming change for transaction"); + OutputPluginWrite(ctx, true); +} + +/* + * In streaming mode, we don't display the contents for transactional messages + * as the transaction can abort at a later point in time. We don't want users to + * see the message contents until the transaction is committed. + */ +static void +pg_decode_stream_message(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, XLogRecPtr lsn, bool transactional, + const char *prefix, Size sz, const char *message) +{ + OutputPluginPrepareWrite(ctx, true); + + if (transactional) + { + appendStringInfo(ctx->out, "streaming message: transactional: %d prefix: %s, sz: %zu", + transactional, prefix, sz); + } + else + { + appendStringInfo(ctx->out, "streaming message: transactional: %d prefix: %s, sz: %zu content:", + transactional, prefix, sz); + appendBinaryStringInfo(ctx->out, message, sz); + } + + OutputPluginWrite(ctx, true); +} + +/* + * In streaming mode, we don't display the detailed information of Truncate. + * See pg_decode_stream_change. + */ +static void +pg_decode_stream_truncate(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, + int nrelations, Relation relations[], + ReorderBufferChange *change) +{ + TestDecodingData *data = ctx->output_plugin_private; + + OutputPluginPrepareWrite(ctx, true); + if (data->include_xids) + appendStringInfo(ctx->out, "streaming truncate for TXN %u", txn->xid); + else + appendStringInfo(ctx->out, "streaming truncate for transaction"); + OutputPluginWrite(ctx, true); +} diff --git a/contrib/vacuumlo/vacuumlo.c b/contrib/vacuumlo/vacuumlo.c index 92bdf71356b1..e4019fafaa9e 100644 --- a/contrib/vacuumlo/vacuumlo.c +++ b/contrib/vacuumlo/vacuumlo.c @@ -22,8 +22,8 @@ #endif #include "catalog/pg_class_d.h" +#include "common/connect.h" #include "common/logging.h" -#include "fe_utils/connect.h" #include "getopt_long.h" #include "libpq-fe.h" #include "pg_getopt.h" diff --git a/doc/src/sgml/backup-manifest.sgml b/doc/src/sgml/backup-manifest.sgml index b9634f270671..6ecf9977a54b 100644 --- a/doc/src/sgml/backup-manifest.sgml +++ b/doc/src/sgml/backup-manifest.sgml @@ -26,7 +26,7 @@ - Backup Manifest Toplevel Object + Backup Manifest Top-level Object The backup manifest JSON document contains the following keys. @@ -93,7 +93,7 @@ Normally, the Path key will be present. The associated string value is the path of the file relative to the root of the backup directory. Files located in a user-defined tablespace - will have paths whose first two components are pg_tblspc and the OID + will have paths whose first two components are pg_tblspc and the OID of the tablespace. If the path is not a string that is legal in UTF-8, or if the user requests that encoded paths be used for all files, then the Encoded-Path key will be present instead. This diff --git a/doc/src/sgml/glossary.sgml b/doc/src/sgml/glossary.sgml index 25b03f3b370f..9d2385031ca4 100644 --- a/doc/src/sgml/glossary.sgml +++ b/doc/src/sgml/glossary.sgml @@ -23,7 +23,7 @@ - Aggregate function + Aggregate function (routine) A function that @@ -39,6 +39,11 @@ + + Analytic function + + + Analyze (operation) @@ -54,14 +59,13 @@ (Don't confuse this term with the ANALYZE option to the command.) + + For more information, see + . + - - Analytic function - - - Atomic @@ -98,14 +102,13 @@ An element with a certain name and data type found within a - tuple or - table. + tuple. - Autovacuum + Autovacuum (process) A set of background processes that routinely perform @@ -175,6 +178,19 @@ + + Base Backup + + + A binary copy of all + database cluster + files. It is generated by the tool . + In combination with WAL files it can be used as the starting point + for recovery, log shipping, or streaming replication. + + + + Bloat @@ -389,40 +405,33 @@ - - Data directory + + Database - The base directory on the filesystem of a - server that contains all - data files and subdirectories associated with an - instance (with the - exception of tablespaces). - The environment variable PGDATA is commonly used to - refer to the - data directory. - - - An instance's storage - space comprises the data directory plus any additional tablespaces. + A named collection of + local SQL objects. For more information, see - . + . - - Database + + Database cluster - A named collection of - SQL objects. + A collection of databases and global SQL objects, + and their common static and dynamic metadata. + Sometimes referred to as a + cluster. - For more information, see - . + In PostgreSQL, the term + cluster is also sometimes used to refer to an instance. + (Don't confuse this term with the SQL command CLUSTER.) @@ -432,6 +441,31 @@ + + Data directory + + + The base directory on the file system of a + server that contains all + data files and subdirectories associated with a + database cluster + (with the exception of + tablespaces, + and optionally WAL). + The environment variable PGDATA is commonly used to + refer to the data directory. + + + A cluster's storage + space comprises the data directory plus any additional tablespaces. + + + For more information, see + . + + + + Data page @@ -578,7 +612,7 @@ - Foreign table + Foreign table (relation) A relation which appears to have @@ -631,12 +665,20 @@ - Function + Function (routine) - Any defined transformation of data. Many functions are already defined - within PostgreSQL itself, but user-defined - ones can also be added. + A type of routine that receives zero or more arguments, returns zero or more + output values, and is constrained to run within one transaction. + Functions are invoked as part of a query, for example via + SELECT. + Certain functions can return + sets; those are + called set-returning functions. + + + Functions can also be used for + triggers to invoke. For more information, see @@ -689,13 +731,12 @@ - Index + Index (relation) A relation that contains data derived from a table - (or relation types - such as a materialized view). + or materialized view. Its internal structure supports fast retrieval of and access to the original data. @@ -724,14 +765,12 @@ Instance - A set of databases and accompanying global SQL objects that are stored in - the same data directory - in a single server. - If running, one + A group of backend and auxiliary processes that communicate using + a common shared memory area. One postmaster process - manages a group of backend and auxiliary processes that communicate - using a common shared memory - area. Many instances can run on the same + manages the instance; one instance manages exactly one + database cluster + with all its databases. Many instances can run on the same server as long as their TCP ports do not conflict. @@ -739,14 +778,10 @@ The instance handles all key features of a DBMS: read and write access to files and shared memory, assurance of the ACID properties, - connections to client processes, + connections to + client processes, privilege verification, crash recovery, replication, etc. - - In PostgreSQL, the term - cluster is also sometimes used to refer to an instance. - (Don't confuse this term with the SQL command CLUSTER.) - @@ -769,8 +804,10 @@ Join - An SQL keyword used in SELECT statements for - combining data from multiple relations. + An operation and SQL keyword used in + queries + for combining data from multiple + relations. @@ -781,10 +818,10 @@ A means of identifying a row within a table or - relation by + other relation by values contained within one or more attributes - in that table. + in that relation. @@ -813,15 +850,6 @@ - - Log record - - - Archaic term for a WAL record. - - - - Logged @@ -840,8 +868,7 @@ Logger (process) - If activated, the - Logger process + If activated, the process writes information about database events into the current log file. When reaching certain time- or @@ -855,6 +882,15 @@ + + Log record + + + Archaic term for a WAL record. + + + + Master (server) @@ -883,12 +919,13 @@ - Materialized view + Materialized view (relation) A relation that is - defined in the same way that a view - is, but stores data in the same way that a + defined by a SELECT statement + (just like a view), + but stores data in the same way that a table does. It cannot be modified via INSERT, UPDATE, or DELETE operations. @@ -949,6 +986,8 @@ One of several disjoint (not overlapping) subsets of a larger set. + + In reference to a partitioned table: @@ -961,16 +1000,18 @@ - In reference to a window function: + In reference to a window function + in a query, a partition is a user-defined criterion that identifies which neighboring - rows can be considered by the - function. + rows + of the query's result set + can be considered by the function. - Partitioned table + Partitioned table (relation) A relation that is @@ -997,20 +1038,6 @@ - - Primary (server) - - - When two or more databases - are linked via replication, - the server - that is considered the authoritative source of information is called - the primary, - also known as a master. - - - - Primary key @@ -1031,19 +1058,29 @@ + + Primary (server) + + + When two or more databases + are linked via replication, + the server + that is considered the authoritative source of information is called + the primary, + also known as a master. + + + + - Procedure + Procedure (routine) - A defined set of instructions for manipulating data within a - database. - A procedure can - be written in a variety of programming languages. They are - similar to functions, - but are different in that they must be invoked via the CALL - command rather than the SELECT or PERFORM - commands, and they are allowed to make transactional statements such + A type of routine. + Their distinctive qualities are that they do not return values, + and that they are allowed to make transactional statements such as COMMIT and ROLLBACK. + They are invoked via the CALL command. For more information, see @@ -1115,6 +1152,11 @@ indexes are all relations. + More generically, a relation is a set of tuples; for example, + the result of a query is also a relation. + + + In PostgreSQL, Class is an archaic synonym for relation. @@ -1155,16 +1197,23 @@ Result set - A data structure transmitted from a - backend process to - a client upon the - completion of an SQL - command, usually a SELECT but it can be an + A relation transmitted + from a backend process + to a client upon the + completion of an SQL command, usually a + SELECT but it can be an INSERT, UPDATE, or DELETE command if the RETURNING - clause is specified. The data structure consists of zero or more - rows with the same ordered set of - attributes. + clause is specified. + + + The fact that a result set is a relation means that a query can be used + in the definition of another query, becoming a + subquery. + + + + @@ -1216,6 +1265,27 @@ + + Routine + + + A defined set of instructions stored in the database system + that can be invoked for execution. + A routine can be written in a variety of programming + languages. Routines can be + functions + (including set-returning functions and + trigger functions), + aggregate functions, + and procedures. + + + Many routines are already defined within PostgreSQL + itself, but user-defined ones can also be added. + + + + Row @@ -1248,16 +1318,7 @@ Each SQL object must reside in exactly one schema. - The names of SQL objects of the same type in the same schema are enforced - to be unique. - There is no restriction on reusing a name in multiple schemas. - - - All system-defined SQL objects reside in schema pg_catalog, - and commonly many user-defined SQL objects reside in the default schema - public, - but it is common and recommended that other schemas are created to hold - application-specific SQL objects. + All system-defined SQL objects reside in schema pg_catalog. @@ -1299,6 +1360,19 @@ + + Sequence (relation) + + + A type of relation that is used to generate values. + Typically the generated values are sequential non-repeating numbers. + They are commonly used to generate surrogate + primary key + values. + + + +