From: Pavan Deolasee Date: Fri, 7 Dec 2018 07:27:12 +0000 (+0530) Subject: Merge tag 'REL_10_6' into XL_10_STABLE X-Git-Tag: XL_10_R1_1~14 X-Git-Url: http://git.postgresql.org/gitweb/static/gitweb.js?a=commitdiff_plain;h=8abb97a40ecd880b2902b025905ea0bdb8ea0e11;p=postgres-xl.git Merge tag 'REL_10_6' into XL_10_STABLE --- 8abb97a40ecd880b2902b025905ea0bdb8ea0e11 diff --cc configure index c6b7e1ed3d,d39564c569..6a3c672cbe --- a/configure +++ b/configure @@@ -1,8 -1,8 +1,8 @@@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. - # Generated by GNU Autoconf 2.69 for PostgreSQL 10.5 (Postgres-XL 10r1). -# Generated by GNU Autoconf 2.69 for PostgreSQL 10.6. ++# Generated by GNU Autoconf 2.69 for PostgreSQL 10.6 (Postgres-XL 10r1). # -# Report bugs to . +# Report bugs to . # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@@ -582,10 -582,9 +582,10 @@@ MAKEFLAGS # Identity of this package. PACKAGE_NAME='PostgreSQL' PACKAGE_TARNAME='postgresql' - PACKAGE_VERSION='10.5 (Postgres-XL 10r1)' -PACKAGE_VERSION='10.6' -PACKAGE_STRING='PostgreSQL 10.6' -PACKAGE_BUGREPORT='pgsql-bugs@postgresql.org' ++PACKAGE_VERSION='10.6 (Postgres-XL 10r1)' +PACKAGE_XC_VERSION='10r1' - PACKAGE_STRING='PostgreSQL 10.5 (Postgres-XL 10r1)' ++PACKAGE_STRING='PostgreSQL 10.6 (Postgres-XL 10r1)' +PACKAGE_BUGREPORT='bugs@postgres-xl.org' PACKAGE_URL='' ac_unique_file="src/backend/access/common/heaptuple.c" @@@ -1413,7 -1411,7 +1415,7 @@@ if test "$ac_init_help" = "long"; the # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF - \`configure' configures PostgreSQL 10.5 (Postgres-XL 10r1) to adapt to many kinds of systems. -\`configure' configures PostgreSQL 10.6 to adapt to many kinds of systems. ++\`configure' configures PostgreSQL 10.6 (Postgres-XL 10r1) to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@@ -1478,7 -1476,7 +1480,7 @@@ f if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of PostgreSQL 10.5 (Postgres-XL 10r1):";; - short | recursive ) echo "Configuration of PostgreSQL 10.6:";; ++ short | recursive ) echo "Configuration of PostgreSQL 10.6 (Postgres-XL 10r1):";; esac cat <<\_ACEOF @@@ -1637,7 -1635,7 +1639,7 @@@ f test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF - PostgreSQL configure 10.5 (Postgres-XL 10r1) -PostgreSQL configure 10.6 ++PostgreSQL configure 10.6 (Postgres-XL 10r1) generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@@ -2348,7 -2346,7 +2350,7 @@@ cat >config.log <<_ACEO This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. - It was created by PostgreSQL $as_me 10.5 (Postgres-XL 10r1), which was -It was created by PostgreSQL $as_me 10.6, which was ++It was created by PostgreSQL $as_me 10.6 (Postgres-XL 10r1), which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@@ -17008,10 -17010,16 +17057,19 @@@ cat >>confdefs.h <<_ACEO _ACEOF +# For PGXC, set -DPGXC by default. This can be overriden with -UPGXC if the user sets it. +# For Postgres-XL, set both -DPGXC and -DXCP +CFLAGS="-DPGXC -DXCP $CFLAGS" + # If we are inserting PG_SYSROOT into CPPFLAGS, do so symbolically not + # literally, so that it's possible to override it at build time using + # a command like "make ... PG_SYSROOT=path". This has to be done after + # we've finished all configure checks that depend on CPPFLAGS. + if test x"$PG_SYSROOT" != x; then + CPPFLAGS=`echo "$CPPFLAGS" | sed -e "s| $PG_SYSROOT | \\\$(PG_SYSROOT) |"` + fi + + # Begin output steps @@@ -17571,7 -17579,7 +17629,7 @@@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_wr # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" - This file was extended by PostgreSQL $as_me 10.5 (Postgres-XL 10r1), which was -This file was extended by PostgreSQL $as_me 10.6, which was ++This file was extended by PostgreSQL $as_me 10.6 (Postgres-XL 10r1), which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@@ -17641,7 -17649,7 +17699,7 @@@ _ACEO cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ - PostgreSQL config.status 10.5 (Postgres-XL 10r1) -PostgreSQL config.status 10.6 ++PostgreSQL config.status 10.6 (Postgres-XL 10r1) configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --cc configure.in index fe4e88d00c,60c1b4b7a5..29c06721f1 --- a/configure.in +++ b/configure.in @@@ -17,7 -17,7 +17,7 @@@ dnl Read the Autoconf manual for detail dnl m4_pattern_forbid(^PGAC_)dnl to catch undefined macros - AC_INIT([PostgreSQL], [10.5 (Postgres-XL 10r1)], [bugs@postgres-xl.org]) -AC_INIT([PostgreSQL], [10.6], [pgsql-bugs@postgresql.org]) ++AC_INIT([PostgreSQL], [10.6 (Postgres-XL 10r1)], [bugs@postgres-xl.org]) m4_if(m4_defn([m4_PACKAGE_VERSION]), [2.69], [], [m4_fatal([Autoconf version 2.69 is required. Untested combinations of 'autoconf' and PostgreSQL versions are not diff --cc doc/bug.template index d943220e8e,4a36036032..f984f4bca4 --- a/doc/bug.template +++ b/doc/bug.template @@@ -27,7 -27,7 +27,7 @@@ System Configuration Operating System (example: Linux 2.4.18) : - PostgreSQL version (example: PostgreSQL 10.5): Postgres-XL 10r1 - PostgreSQL version (example: PostgreSQL 10.6): PostgreSQL 10.6 ++ PostgreSQL version (example: PostgreSQL 10.6): Postgres-XL 10r1 Compiler used (example: gcc 3.3.5) : diff --cc src/backend/access/transam/xact.c index 35d22ac082,b028b318e5..a38bab5823 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@@ -976,21 -747,13 +992,24 @@@ GetCurrentTransactionStopTimestamp(void if (xactStopTimestamp != 0) return xactStopTimestamp; return GetCurrentTimestamp(); +#endif } +#ifdef PGXC +TimestampTz +GetCurrentGTMStartTimestamp(void) +{ + if (GTMxactStartTimestamp == 0) + GTMxactStartTimestamp = xactStartTimestamp; + return GTMxactStartTimestamp; +} +#endif + /* * SetCurrentStatementStartTimestamp + * + * In a parallel worker, this should already have been provided by a call + * to SetParallelStartTimestamps(). */ void SetCurrentStatementStartTimestamp(void) @@@ -2223,19 -1915,18 +2245,25 @@@ StartTransaction(void /* * set transaction_timestamp() (a/k/a now()). We want this to be the same * as the first command's statement_timestamp(), so don't do a fresh - * GetCurrentTimestamp() call (which'd be expensive anyway). Also, mark - * xactStopTimestamp as unset. + * GetCurrentTimestamp() call (which'd be expensive anyway). In a + * parallel worker, this should already have been provided by a call to + * SetParallelStartTimestamps(). + * + * Also, mark xactStopTimestamp as unset. */ - xactStartTimestamp = stmtStartTimestamp; + if (!IsParallelWorker()) + xactStartTimestamp = stmtStartTimestamp; + else + Assert(xactStartTimestamp != 0); xactStopTimestamp = 0; +#ifdef PGXC + /* For Postgres-XC, transaction start timestamp has to follow the GTM timeline */ + pgstat_report_xact_timestamp(GTMxactStartTimestamp ? + GTMxactStartTimestamp : + xactStartTimestamp); +#else pgstat_report_xact_timestamp(xactStartTimestamp); +#endif /* * initialize current transaction state fields diff --cc src/backend/executor/execCurrent.c index c98f85ba3f,a4cdde0847..087e055339 --- a/src/backend/executor/execCurrent.c +++ b/src/backend/executor/execCurrent.c @@@ -22,16 -21,12 +22,12 @@@ #include "utils/portal.h" #include "utils/rel.h" +#ifdef PGXC +#include "pgxc/execRemote.h" +#endif static char *fetch_cursor_param_value(ExprContext *econtext, int paramId); -static ScanState *search_plan_tree(PlanState *node, Oid table_oid, - bool *pending_rescan); - - #ifndef PGXC - static ScanState *search_plan_tree(PlanState *node, Oid table_oid); - #endif - /* * execCurrentOf * @@@ -294,15 -295,20 +296,20 @@@ fetch_cursor_param_value(ExprContext *e * * Search through a PlanState tree for a scan node on the specified table. * Return NULL if not found or multiple candidates. + * + * If a candidate is found, set *pending_rescan to true if that candidate + * or any node above it has a pending rescan action, i.e. chgParam != NULL. + * That indicates that we shouldn't consider the node to be positioned on a + * valid tuple, even if its own state would indicate that it is. (Caller + * must initialize *pending_rescan to false, and should not trust its state + * if multiple candidates are found.) */ - #ifdef PGXC -static ScanState * +ScanState * - search_plan_tree(PlanState *node, Oid table_oid) - #else - static ScanState * - search_plan_tree(PlanState *node, Oid table_oid) - #endif + search_plan_tree(PlanState *node, Oid table_oid, + bool *pending_rescan) { + ScanState *result = NULL; + if (node == NULL) return NULL; switch (nodeTag(node)) @@@ -377,12 -383,12 +384,15 @@@ * Result and Limit can be descended through (these are safe * because they always return their input's current row) */ +#ifdef PGXC + case T_MaterialState: +#endif case T_ResultState: case T_LimitState: - return search_plan_tree(node->lefttree, table_oid); + result = search_plan_tree(node->lefttree, + table_oid, + pending_rescan); + break; /* * SubqueryScan too, but it keeps the child in a different place diff --cc src/backend/postmaster/postmaster.c index c4a258452d,56d81890bc..577d38fa9c --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@@ -2864,15 -2734,7 +2864,15 @@@ pmdie(SIGNAL_ARGS signal_child(BgWriterPID, SIGTERM); if (WalReceiverPID != 0) signal_child(WalReceiverPID, SIGTERM); +#ifdef XCP + /* and the pool manager too */ + if (PgPoolerPID != 0) + signal_child(PgPoolerPID, SIGTERM); + /* and the cluster monitor too */ + if (ClusterMonPID != 0) + signal_child(ClusterMonPID, SIGTERM); +#endif /* XCP */ - if (pmState == PM_RECOVERY) + if (pmState == PM_STARTUP || pmState == PM_RECOVERY) { SignalSomeChildren(SIGTERM, BACKEND_TYPE_BGWORKER); diff --cc src/backend/replication/logical/logical.c index f6774df96f,46f13bbe61..e38df742e2 --- a/src/backend/replication/logical/logical.c +++ b/src/backend/replication/logical/logical.c @@@ -77,16 -77,11 +77,21 @@@ CheckLogicalDecodingRequirements(void { CheckSlotRequirements(); + /* + * Postgres-XL does not support logical replication for now. We could create + * the logical replication slot, but attempts to decode the WAL would crash + * and burn as ReorderBufferCommit() uses subtransactions internally. We need + */ + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Postgres-XL does not support logical replication"), + errdetail("The feature is not currently supported"))); + + /* + * NB: Adding a new requirement likely means that RestoreSlotFromDisk() + * needs the same check. + */ + if (wal_level < WAL_LEVEL_LOGICAL) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), diff --cc src/backend/storage/lmgr/lmgr.c index e1c74616d7,10e2d028fa..21a373a817 --- a/src/backend/storage/lmgr/lmgr.c +++ b/src/backend/storage/lmgr/lmgr.c @@@ -123,18 -122,17 +124,27 @@@ LockRelationOid(Oid relid, LOCKMODE loc * modifies the rel, the relcache update happens via * CommandCounterIncrement, not here.) * + * However, in corner cases where code acts on tables (usually catalogs) + * recursively, we might get here while still processing invalidation + * messages in some outer execution of this function or a sibling. The + * "cleared" status of the lock tells us whether we really are done + * absorbing relevant inval messages. ++ * + * In Postgres-XL, multiple backends may run concurrently to serve a + * distributed transaction. In that case, a conflicting lock may be granted + * to another backend running the same distributed transaction. But it's + * important that such backends process invalidation messages to ensure + * that relcache entry modified by the other cooperating backend is truly + * reflected. For example, the other backend may TRUNCATE the table and + * change the relfilenode. So we must see that change and work with the new + * relfilenode. */ - if ((res != LOCKACQUIRE_ALREADY_HELD) || - if (res != LOCKACQUIRE_ALREADY_CLEAR) ++ if ((res != LOCKACQUIRE_ALREADY_CLEAR) || + (MyProc->coordPid && MyProc->coordId)) + { AcceptInvalidationMessages(); + MarkLockClear(locallock); + } } /* diff --cc src/backend/storage/lmgr/lock.c index b332890aee,2810b2401e..1499a9ddaf --- a/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@@ -261,10 -260,6 +261,14 @@@ static LOCALLOCK *StrongLockInProgress static LOCALLOCK *awaitedLock; static ResourceOwner awaitedOwner; +static LockAcquireResult LockAcquireExtendedXC(const LOCKTAG *locktag, - LOCKMODE lockmode, bool sessionLock, bool dontWait, bool reportMemoryError, - bool only_increment); ++ LOCKMODE lockmode, ++ bool sessionLock, ++ bool dontWait, ++ bool reportMemoryError, ++ LOCALLOCK **locallockp, ++ bool only_increment); + #ifdef LOCK_DEBUG @@@ -690,31 -686,10 +695,32 @@@ LockAcquire(const LOCKTAG *locktag bool sessionLock, bool dontWait) { - return LockAcquireExtended(locktag, lockmode, sessionLock, dontWait, true); + return LockAcquireExtended(locktag, lockmode, sessionLock, dontWait, + true, NULL); } +#ifdef PGXC +/* + * LockIncrementIfExists - Special purpose case of LockAcquire(). + * This checks if there is already a reference to the lock. If yes, + * increments it, and returns true. If not, just returns back false. + * Effectively, it never creates a new lock. + */ +bool +LockIncrementIfExists(const LOCKTAG *locktag, + LOCKMODE lockmode, bool sessionLock) +{ + int ret; + + ret = LockAcquireExtendedXC(locktag, lockmode, + sessionLock, + true, /* never wait */ - true, true); ++ true, NULL, true); + + return (ret == LOCKACQUIRE_ALREADY_HELD); +} +#endif + /* * LockAcquireExtended - allows us to specify additional options * @@@ -729,23 -709,8 +740,25 @@@ LockAcquireExtended(const LOCKTAG *lock LOCKMODE lockmode, bool sessionLock, bool dontWait, - bool reportMemoryError) + bool reportMemoryError, + LOCALLOCK **locallockp) +{ + return LockAcquireExtendedXC(locktag, lockmode, sessionLock, dontWait, - reportMemoryError, false); ++ reportMemoryError, locallockp, false); +} + +/* + * LockAcquireExtendedXC - additional parameter only_increment. This is XC + * specific. Check comments for the function LockIncrementIfExists() + */ +static LockAcquireResult +LockAcquireExtendedXC(const LOCKTAG *locktag, + LOCKMODE lockmode, + bool sessionLock, + bool dontWait, + bool reportMemoryError, ++ LOCALLOCK **locallockp, + bool only_increment) { LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid; LockMethod lockMethodTable; @@@ -838,15 -810,12 +858,18 @@@ if (locallock->nLocks > 0) { GrantLockLocal(locallock, owner); - return LOCKACQUIRE_ALREADY_HELD; + if (locallock->lockCleared) + return LOCKACQUIRE_ALREADY_CLEAR; + else + return LOCKACQUIRE_ALREADY_HELD; } - +#ifdef PGXC + else if (only_increment) + { + /* User does not want to create new lock if it does not already exist */ + return LOCKACQUIRE_NOT_AVAIL; + } +#endif /* * Prepare to emit a WAL record if acquisition of this lock needs to be * replayed in a standby server. diff --cc src/backend/tcop/utility.c index afcdf3e937,135286ebbf..783fc52faa --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@@ -1356,37 -383,9 +1356,40 @@@ standard_ProcessUtility(PlannedStmt *ps bool isTopLevel = (context == PROCESS_UTILITY_TOPLEVEL); ParseState *pstate; + /* This can recurse, so check for excessive recursion */ + check_stack_depth(); + + /* + * For more detail see comments in function pgxc_lock_for_backup. + * + * Cosider the following scenario: + * Imagine a two cordinator cluster CO1, CO2 + * Suppose a client connected to CO1 issues select pgxc_lock_for_backup() + * Now assume that a client connected to CO2 issues a create table + * select pgxc_lock_for_backup() would try to acquire the advisory lock + * in exclusive mode, whereas create table would try to acquire the same + * lock in shared mode. Both these requests will always try acquire the + * lock in the same order i.e. they would both direct the request first to + * CO1 and then to CO2. One of the two requests would therefore pass + * and the other would fail. + * + * Consider another scenario: + * Suppose we have a two cooridnator cluster CO1 and CO2 + * Assume one client connected to each coordinator + * Further assume one client starts a transaction + * and issues a DDL. This is an unfinished transaction. + * Now assume the second client issues + * select pgxc_lock_for_backup() + * This request would fail because the unfinished transaction + * would already hold the advisory lock. + */ + if (IS_PGXC_LOCAL_COORDINATOR && IsNormalProcessingMode()) + { + /* Is the statement a prohibited one? */ + if (!IsStmtAllowedInLockedMode(parsetree, queryString)) + pgxc_lock_for_utility_stmt(parsetree); + } + check_xact_readonly(parsetree); if (completionTag) diff --cc src/bin/psql/tab-complete.c index 38abb2907d,83b2b9cee3..f0ff68d3a8 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@@ -1421,17 -1405,32 +1421,32 @@@ psql_completion(const char *text, int s word_matches(p2, previous_words[previous_words_count - 2]) && \ word_matches(p3, previous_words[previous_words_count - 3])) + #define HeadMatches4(p1, p2, p3, p4) \ + (previous_words_count >= 4 && \ + word_matches(p1, previous_words[previous_words_count - 1]) && \ + word_matches(p2, previous_words[previous_words_count - 2]) && \ + word_matches(p3, previous_words[previous_words_count - 3]) && \ + word_matches(p4, previous_words[previous_words_count - 4])) + + #define HeadMatches5(p1, p2, p3, p4, p5) \ + (previous_words_count >= 5 && \ + word_matches(p1, previous_words[previous_words_count - 1]) && \ + word_matches(p2, previous_words[previous_words_count - 2]) && \ + word_matches(p3, previous_words[previous_words_count - 3]) && \ + word_matches(p4, previous_words[previous_words_count - 4]) && \ + word_matches(p5, previous_words[previous_words_count - 5])) + /* Known command-starting keywords. */ static const char *const sql_commands[] = { - "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER", + "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLEAN CONNECTION", "CLOSE", "CLUSTER", "COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE", - "DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN", - "FETCH", "GRANT", "IMPORT", "INSERT", "LISTEN", "LOAD", "LOCK", - "MOVE", "NOTIFY", "PREPARE", - "REASSIGN", "REFRESH MATERIALIZED VIEW", "REINDEX", "RELEASE", + "DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXECUTE DIRECT", "EXPLAIN", + "FETCH", "GRANT", "INSERT", "LOAD", "LOCK", + "MOVE", "PREPARE", + "REASSIGN", "REINDEX", "RESET", "REVOKE", "ROLLBACK", - "SAVEPOINT", "SECURITY LABEL", "SELECT", "SET", "SHOW", "START", - "TABLE", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", "VALUES", "WITH", + "SECURITY LABEL", "SELECT", "SET", "SHOW", "START", + "TABLE", "TRUNCATE", "UPDATE", "VACUUM", "VALUES", "WITH", NULL }; diff --cc src/include/access/xact.h index 34c54198e2,905f42c2b1..358523de48 --- a/src/include/access/xact.h +++ b/src/include/access/xact.h @@@ -362,17 -337,11 +362,18 @@@ extern SubTransactionId GetCurrentSubTr extern void MarkCurrentTransactionIdLoggedIfAny(void); extern bool SubTransactionIsActive(SubTransactionId subxid); extern CommandId GetCurrentCommandId(bool used); + extern void SetParallelStartTimestamps(TimestampTz xact_ts, TimestampTz stmt_ts); extern TimestampTz GetCurrentTransactionStartTimestamp(void); extern TimestampTz GetCurrentStatementStartTimestamp(void); +#ifdef XCP +extern TimestampTz GetCurrentLocalStatementStartTimestamp(void); +#endif extern TimestampTz GetCurrentTransactionStopTimestamp(void); extern void SetCurrentStatementStartTimestamp(void); +#ifdef PGXC +extern TimestampTz GetCurrentGTMStartTimestamp(void); +extern void SetCurrentGTMDeltaTimestamp(TimestampTz timestamp); +#endif extern int GetCurrentTransactionNestLevel(void); extern bool TransactionIdIsCurrentTransactionId(TransactionId xid); extern void CommandCounterIncrement(void); diff --cc src/include/executor/executor.h index 389e346209,379e7c77a1..0cf0bfa6c8 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@@ -114,10 -109,6 +114,11 @@@ extern bool execCurrentOf(CurrentOfExp Oid table_oid, ItemPointer current_tid); +#ifdef PGXC - ScanState *search_plan_tree(PlanState *node, Oid table_oid); ++ScanState *search_plan_tree(PlanState *node, Oid table_oid, ++ bool *pending_rescan); +#endif + /* * prototypes from functions in execGrouping.c */ diff --cc src/include/pg_config.h.win32 index 53015a1b99,a86261f5bb..1cf42d5f42 --- a/src/include/pg_config.h.win32 +++ b/src/include/pg_config.h.win32 @@@ -564,16 -564,16 +564,16 @@@ #define MEMSET_LOOP_LIMIT 1024 /* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "pgsql-bugs@postgresql.org" +#define PACKAGE_BUGREPORT "postgres-xl-bugs@lists.sourceforge.net" /* Define to the full name of this package. */ -#define PACKAGE_NAME "PostgreSQL" +#define PACKAGE_NAME "Postgres-XL" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "PostgreSQL 10.6" +#define PACKAGE_STRING "Postgres-XL 10r1" /* Define to the version of this package. */ - #define PACKAGE_VERSION "10.5" + #define PACKAGE_VERSION "10.6" /* Define to the name of a signed 128-bit integer type. */ #undef PG_INT128_TYPE @@@ -582,19 -582,13 +582,19 @@@ #define PG_INT64_TYPE long long int /* PostgreSQL version as a string */ - #define PG_VERSION "10.5" + #define PG_VERSION "10.6" /* PostgreSQL version as a number */ - #define PG_VERSION_NUM 100005 + #define PG_VERSION_NUM 100006 /* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "postgresql" +#define PACKAGE_TARNAME "postgres-xl" + +/* Postgres-XC version as a string */ +#define PGXC_VERSION "1.1devel" + +/* Postgres-XC version as a number */ +#define PGXC_VERSION_NUM 10100 /* Define to the name of the default PostgreSQL service principal in Kerberos. (--with-krb-srvnam=NAME) */ diff --cc src/test/regress/expected/alter_table.out index b7eec60670,70e140039a..a7f6a4cf54 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@@ -3693,119 -3669,36 +3693,154 @@@ alter table temp_part_parent attach par for values in (1, 2); -- ok drop table perm_part_parent cascade; drop table temp_part_parent cascade; ++ + -- check that attaching partitions to a table while it is being used is + -- prevented + create table tab_part_attach (a int) partition by list (a); + create or replace function func_part_attach() returns trigger + language plpgsql as $$ + begin + execute 'create table tab_part_attach_1 (a int)'; + execute 'alter table tab_part_attach attach partition tab_part_attach_1 for values in (1)'; + return null; + end $$; + create trigger trig_part_attach before insert on tab_part_attach + for each statement execute procedure func_part_attach(); + insert into tab_part_attach values (1); + ERROR: cannot ALTER TABLE "tab_part_attach" because it is being used by active queries in this session + CONTEXT: SQL statement "alter table tab_part_attach attach partition tab_part_attach_1 for values in (1)" + PL/pgSQL function func_part_attach() line 4 at EXECUTE + drop table tab_part_attach; + drop function func_part_attach(); + -- test case where the partitioning operator is a SQL function whose + -- evaluation results in the table's relcache being rebuilt partway through + -- the execution of an ATTACH PARTITION command + create function at_test_sql_partop (int4, int4) returns int language sql + as $$ select case when $1 = $2 then 0 when $1 > $2 then 1 else -1 end; $$; + create operator class at_test_sql_partop for type int4 using btree as + operator 1 < (int4, int4), operator 2 <= (int4, int4), + operator 3 = (int4, int4), operator 4 >= (int4, int4), + operator 5 > (int4, int4), function 1 at_test_sql_partop(int4, int4); + create table at_test_sql_partop (a int) partition by range (a at_test_sql_partop); + create table at_test_sql_partop_1 (a int); + alter table at_test_sql_partop attach partition at_test_sql_partop_1 for values from (0) to (10); + drop table at_test_sql_partop; + drop operator class at_test_sql_partop using btree; + drop function at_test_sql_partop; ++ +-- xl tests +create table xl_parent (a int, b int, c text) partition by list (a); +-- create a partition +create table xl_child1 partition of xl_parent for values in (1, 2, 3); +-- attach a partition +create table xl_child2 (a int, b int, c text); +alter table xl_parent attach partition xl_child2 for values in (4, 5, 6); +-- attach a partition, distribution column position does not match +create table xl_child3 (b int, a int, c text) distribute by hash (a); +alter table xl_parent attach partition xl_child3 for values in (7, 8, 9); +ERROR: table "xl_child3" is distributed on column "a" at position 1, but the parent table "xl_parent" is distributed on column "a" at position 2 +DETAIL: Distribution column for the child must be same as the parent +-- attach a partition, distribution column position matches, others do not +create table xl_child4 (a int, c text, b int) distribute by hash (a); +alter table xl_parent attach partition xl_child4 for values in (10, 11, 12); +create table xl_child5 (a int) distribute by hash (a); +alter table xl_child5 add column c text; +alter table xl_child5 add column b int; +alter table xl_parent attach partition xl_child5 for values in (13, 14, 15); +create table xl_child6 (a int, b int) distribute by hash (b); +alter table xl_child6 distribute by hash (a); +alter table xl_child6 add column c text; +alter table xl_parent attach partition xl_child6 for values in (16, 17, 18); +create table xl_child7 (a int, b int); +alter table xl_child7 drop column b; +alter table xl_child7 add column b int; +alter table xl_child7 add column c text; +alter table xl_parent attach partition xl_child7 for values in (19, 20, 21); +insert into xl_parent values (1, 100, 'us'); +insert into xl_parent values (4, 200, 'they'); +insert into xl_parent values (6, 300, 'me'); +insert into xl_parent values (11, 400, 'mine'); +insert into xl_parent values (12, 500, 'theirs'); +insert into xl_parent values (9, 600, 'ours'); +ERROR: no partition of relation "xl_parent" found for row +DETAIL: Partition key of the failing row contains (a) = (9). +insert into xl_parent values (13, 700, 'yours'); +insert into xl_parent values (16, 800, 'my'); +insert into xl_parent values (19, 900, 'his'); +select * from xl_parent order by a; + a | b | c +----+-----+-------- + 1 | 100 | us + 4 | 200 | they + 6 | 300 | me + 11 | 400 | mine + 12 | 500 | theirs + 13 | 700 | yours + 16 | 800 | my + 19 | 900 | his +(8 rows) + +select * from xl_parent where a = 1; + a | b | c +---+-----+---- + 1 | 100 | us +(1 row) + +select * from xl_parent where a = 10; + a | b | c +---+---+--- +(0 rows) + +select * from xl_parent where a = 4; + a | b | c +---+-----+------ + 4 | 200 | they +(1 row) + +select * from xl_parent where a = 13; + a | b | c +----+-----+------- + 13 | 700 | yours +(1 row) + +drop table xl_parent; +create table xl_parted (a int, b int, c text) partition by list (b) distribute by hash (b); +create table xl_c1 (a int, b int, c text); +alter table xl_parted attach partition xl_c1 for values in (1, 2, 3); +ERROR: table "xl_c1" is distributed on column "a" at position 2, but the parent table "xl_parted" is distributed on column "b" at position 1 +DETAIL: Distribution column for the child must be same as the parent +drop table xl_c1; +create table xl_c1 (a int, b int, c text) distribute by hash (b); +alter table xl_parted attach partition xl_c1 for values in (1, 2, 3); +insert into xl_parted values (100, 1, 'foo'); +insert into xl_parted values (200, 3, 'bar'); +alter table xl_parted drop column a; +create table xl_c2 (b int, c text); +-- fails +alter table xl_parted attach partition xl_c2 for values in (4, 5, 6); +ERROR: table "xl_c2" is distributed on column "b" at position 2, but the parent table "xl_parted" is distributed on column "b" at position 1 +DETAIL: Distribution column for the child must be same as the parent +insert into xl_parted values (5, 'baz'); +ERROR: no partition of relation "xl_parted" found for row +DETAIL: Partition key of the failing row contains (b) = (5). +-- since attach failed above +drop table xl_c2; +create table xl_c2 (a int, b text, c text) distribute by hash (b); +alter table xl_c2 drop column a; +alter table xl_parted attach partition xl_c2 for values in (4, 5, 6); +ERROR: child table "xl_c2" has different type for column "b" +-- since attach failed above +drop table xl_c2; +create table xl_c2 (a int, b int, c text) distribute by hash (b); +alter table xl_c2 drop column a; +alter table xl_parted attach partition xl_c2 for values in (4, 5, 6); +insert into xl_parted values (5, 'baz'); +select * from xl_parted; + b | c +---+----- + 1 | foo + 5 | baz + 3 | bar +(3 rows) + +drop table xl_parted; diff --cc src/test/regress/expected/create_table.out index 6e3ec8046a,481510c2bb..92d756e54f --- a/src/test/regress/expected/create_table.out +++ b/src/test/regress/expected/create_table.out @@@ -856,19 -830,19 +856,35 @@@ ERROR: cannot create a temporary relat create temp table temp_part partition of temp_parted for values in (1, 2); -- ok drop table perm_parted cascade; drop table temp_parted cascade; + -- check that adding partitions to a table while it is being used is prevented + create table tab_part_create (a int) partition by list (a); + create or replace function func_part_create() returns trigger + language plpgsql as $$ + begin + execute 'create table tab_part_create_1 partition of tab_part_create for values in (1)'; + return null; + end $$; + create trigger trig_part_create before insert on tab_part_create + for each statement execute procedure func_part_create(); + insert into tab_part_create values (1); + ERROR: cannot CREATE TABLE .. PARTITION OF "tab_part_create" because it is being used by active queries in this session + CONTEXT: SQL statement "create table tab_part_create_1 partition of tab_part_create for values in (1)" + PL/pgSQL function func_part_create() line 3 at EXECUTE + drop table tab_part_create; + drop function func_part_create(); +-- xl tests +create table xl_parted (a int, b int, c text) partition by list (b) distribute by hash (b); +create table xl_c1 partition of xl_parted for values in (1, 2, 3); +insert into xl_parted values (100, 1, 'foo'); +insert into xl_parted values (200, 3, 'bar'); +alter table xl_parted drop column a; +create table xl_c2 partition of xl_parted for values in (4, 5, 6); +insert into xl_parted values (1, 'foo'); +insert into xl_parted values (3, 'bar'); +insert into xl_parted values (5, 'baz'); +-- syntax error +create table xl_c3 partition of xl_parted for values in (4, 5, 6) distribute by hash (b); +ERROR: syntax error at or near "distribute" +LINE 1: ...c3 partition of xl_parted for values in (4, 5, 6) distribute... + ^ +drop table xl_parted; diff --cc src/test/regress/expected/event_trigger.out index 085eb207b9,9f22a65012..b0615594ac --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@@ -283,17 -331,45 +283,40 @@@ CREATE SCHEMA evttri CREATE TABLE one (col_a SERIAL PRIMARY KEY, col_b text DEFAULT 'forty two') CREATE INDEX one_idx ON one (col_b) CREATE TABLE two (col_c INTEGER CHECK (col_c > 0) REFERENCES one DEFAULT 42); + -- Partitioned tables + CREATE TABLE evttrig.parted ( + id int) + PARTITION BY RANGE (id); + CREATE TABLE evttrig.part_1_10 PARTITION OF evttrig.parted (id) + FOR VALUES FROM (1) TO (10); + CREATE TABLE evttrig.part_10_20 PARTITION OF evttrig.parted (id) + FOR VALUES FROM (10) TO (20) PARTITION BY RANGE (id); + CREATE TABLE evttrig.part_10_15 PARTITION OF evttrig.part_10_20 (id) + FOR VALUES FROM (10) TO (15); + CREATE TABLE evttrig.part_15_20 PARTITION OF evttrig.part_10_20 (id) + FOR VALUES FROM (15) TO (20); ALTER TABLE evttrig.two DROP COLUMN col_c; -NOTICE: NORMAL: orig=t normal=f istemp=f type=table column identity=evttrig.two.col_c name={evttrig,two,col_c} args={} -NOTICE: NORMAL: orig=f normal=t istemp=f type=table constraint identity=two_col_c_check on evttrig.two name={evttrig,two,two_col_c_check} args={} ALTER TABLE evttrig.one ALTER COLUMN col_b DROP DEFAULT; -NOTICE: NORMAL: orig=t normal=f istemp=f type=default value identity=for evttrig.one.col_b name={evttrig,one,col_b} args={} ALTER TABLE evttrig.one DROP CONSTRAINT one_pkey; -NOTICE: NORMAL: orig=t normal=f istemp=f type=table constraint identity=one_pkey on evttrig.one name={evttrig,one,one_pkey} args={} DROP INDEX evttrig.one_idx; -NOTICE: NORMAL: orig=t normal=f istemp=f type=index identity=evttrig.one_idx name={evttrig,one_idx} args={} DROP SCHEMA evttrig CASCADE; - NOTICE: drop cascades to 2 other objects + NOTICE: drop cascades to 3 other objects DETAIL: drop cascades to table evttrig.one drop cascades to table evttrig.two + drop cascades to table evttrig.parted + NOTICE: NORMAL: orig=t normal=f istemp=f type=schema identity=evttrig name={evttrig} args={} + NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.one name={evttrig,one} args={} + NOTICE: NORMAL: orig=f normal=t istemp=f type=sequence identity=evttrig.one_col_a_seq name={evttrig,one_col_a_seq} args={} + NOTICE: NORMAL: orig=f normal=t istemp=f type=default value identity=for evttrig.one.col_a name={evttrig,one,col_a} args={} + NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.two name={evttrig,two} args={} + NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.parted name={evttrig,parted} args={} + NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.part_1_10 name={evttrig,part_1_10} args={} + NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.part_10_20 name={evttrig,part_10_20} args={} + NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.part_10_15 name={evttrig,part_10_15} args={} + NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.part_15_20 name={evttrig,part_15_20} args={} DROP TABLE a_temp_tbl; -NOTICE: NORMAL: orig=t normal=f istemp=t type=table identity=pg_temp.a_temp_tbl name={pg_temp,a_temp_tbl} args={} DROP EVENT TRIGGER regress_event_trigger_report_dropped; +ERROR: event trigger "regress_event_trigger_report_dropped" does not exist -- only allowed from within an event trigger function, should fail select pg_event_trigger_table_rewrite_oid(); ERROR: pg_event_trigger_table_rewrite_oid() can only be called in a table_rewrite event trigger function diff --cc src/test/regress/expected/select_parallel.out index 50e7ab17b6,70c6fe43eb..fa84891def --- a/src/test/regress/expected/select_parallel.out +++ b/src/test/regress/expected/select_parallel.out @@@ -580,35 -564,97 +580,107 @@@ reset role set force_parallel_mode=1; explain (costs off) select stringu1::int2 from tenk1 where unique1 = 1; - QUERY PLAN ------------------------------------------------ - Gather - Workers Planned: 1 - Single Copy: true - -> Index Scan using tenk1_unique1 on tenk1 - Index Cond: (unique1 = 1) -(5 rows) + QUERY PLAN +----------------------------------------------------- + Remote Fast Query Execution + Node/s: datanode_1 + -> Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using tenk1_unique1 on tenk1 + Index Cond: (unique1 = 1) +(7 rows) + -- Window function calculation can't be pushed to workers. + explain (costs off, verbose) + select count(*) from tenk1 a where (unique1, two) in + (select unique1, row_number() over() from tenk1 b); + QUERY PLAN + ---------------------------------------------------------------------------------------------- + Aggregate + Output: count(*) + -> Hash Semi Join + Hash Cond: ((a.unique1 = b.unique1) AND (a.two = (row_number() OVER (?)))) + -> Gather + Output: a.unique1, a.two + Workers Planned: 4 + -> Parallel Seq Scan on public.tenk1 a + Output: a.unique1, a.two + -> Hash + Output: b.unique1, (row_number() OVER (?)) + -> WindowAgg + Output: b.unique1, row_number() OVER (?) + -> Gather + Output: b.unique1 + Workers Planned: 4 + -> Parallel Index Only Scan using tenk1_unique1 on public.tenk1 b + Output: b.unique1 + (18 rows) + + -- LIMIT/OFFSET within sub-selects can't be pushed to workers. + explain (costs off) + select * from tenk1 a where two in + (select two from tenk1 b where stringu1 like '%AAAA' limit 3); + QUERY PLAN + --------------------------------------------------------------- + Hash Semi Join + Hash Cond: (a.two = b.two) + -> Gather + Workers Planned: 4 + -> Parallel Seq Scan on tenk1 a + -> Hash + -> Limit + -> Gather + Workers Planned: 4 + -> Parallel Seq Scan on tenk1 b + Filter: (stringu1 ~~ '%AAAA'::text) + (11 rows) + -- to increase the parallel query test coverage +EXPLAIN (timing off, summary off, costs off) SELECT * FROM tenk1; + QUERY PLAN +---------------------------------------- + Remote Fast Query Execution + Node/s: datanode_1, datanode_2 + -> Gather + Workers Planned: 4 + -> Parallel Seq Scan on tenk1 +(5 rows) + EXPLAIN (analyze, timing off, summary off, costs off) SELECT * FROM tenk1; - QUERY PLAN -------------------------------------------------------------- - Gather (actual rows=10000 loops=1) - Workers Planned: 4 - Workers Launched: 4 - -> Parallel Seq Scan on tenk1 (actual rows=2000 loops=5) -(4 rows) + QUERY PLAN +--------------------------------------------------------- + Remote Fast Query Execution (actual rows=10000 loops=1) + Node/s: datanode_1, datanode_2 +(2 rows) + -- test passing expanded-value representations to workers + CREATE FUNCTION make_some_array(int,int) returns int[] as + $$declare x int[]; + begin + x[1] := $1; + x[2] := $2; + return x; + end$$ language plpgsql parallel safe; + CREATE TABLE fooarr(f1 text, f2 int[], f3 text); + INSERT INTO fooarr VALUES('1', ARRAY[1,2], 'one'); + PREPARE pstmt(text, int[]) AS SELECT * FROM fooarr WHERE f1 = $1 AND f2 = $2; + EXPLAIN (COSTS OFF) EXECUTE pstmt('1', make_some_array(1,2)); + QUERY PLAN + ------------------------------------------------------------------ + Gather + Workers Planned: 3 + -> Parallel Seq Scan on fooarr + Filter: ((f1 = '1'::text) AND (f2 = '{1,2}'::integer[])) + (4 rows) + + EXECUTE pstmt('1', make_some_array(1,2)); + f1 | f2 | f3 + ----+-------+----- + 1 | {1,2} | one + (1 row) + + DEALLOCATE pstmt; -- provoke error in worker select stringu1::int2 from tenk1 where unique1 = 1; ERROR: invalid input syntax for integer: "BAAAAA" diff --cc src/test/regress/sql/alter_table.sql index 67ca7f206f,e79b402a32..304c3f7bdf --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@@ -2407,79 -2389,34 +2407,110 @@@ alter table temp_part_parent attach par drop table perm_part_parent cascade; drop table temp_part_parent cascade; + -- check that attaching partitions to a table while it is being used is + -- prevented + create table tab_part_attach (a int) partition by list (a); + create or replace function func_part_attach() returns trigger + language plpgsql as $$ + begin + execute 'create table tab_part_attach_1 (a int)'; + execute 'alter table tab_part_attach attach partition tab_part_attach_1 for values in (1)'; + return null; + end $$; + create trigger trig_part_attach before insert on tab_part_attach + for each statement execute procedure func_part_attach(); + insert into tab_part_attach values (1); + drop table tab_part_attach; + drop function func_part_attach(); + + -- test case where the partitioning operator is a SQL function whose + -- evaluation results in the table's relcache being rebuilt partway through + -- the execution of an ATTACH PARTITION command + create function at_test_sql_partop (int4, int4) returns int language sql + as $$ select case when $1 = $2 then 0 when $1 > $2 then 1 else -1 end; $$; + create operator class at_test_sql_partop for type int4 using btree as + operator 1 < (int4, int4), operator 2 <= (int4, int4), + operator 3 = (int4, int4), operator 4 >= (int4, int4), + operator 5 > (int4, int4), function 1 at_test_sql_partop(int4, int4); + create table at_test_sql_partop (a int) partition by range (a at_test_sql_partop); + create table at_test_sql_partop_1 (a int); + alter table at_test_sql_partop attach partition at_test_sql_partop_1 for values from (0) to (10); + drop table at_test_sql_partop; + drop operator class at_test_sql_partop using btree; + drop function at_test_sql_partop; +-- xl tests +create table xl_parent (a int, b int, c text) partition by list (a); +-- create a partition +create table xl_child1 partition of xl_parent for values in (1, 2, 3); + +-- attach a partition +create table xl_child2 (a int, b int, c text); +alter table xl_parent attach partition xl_child2 for values in (4, 5, 6); + +-- attach a partition, distribution column position does not match +create table xl_child3 (b int, a int, c text) distribute by hash (a); +alter table xl_parent attach partition xl_child3 for values in (7, 8, 9); + +-- attach a partition, distribution column position matches, others do not +create table xl_child4 (a int, c text, b int) distribute by hash (a); +alter table xl_parent attach partition xl_child4 for values in (10, 11, 12); + +create table xl_child5 (a int) distribute by hash (a); +alter table xl_child5 add column c text; +alter table xl_child5 add column b int; +alter table xl_parent attach partition xl_child5 for values in (13, 14, 15); + +create table xl_child6 (a int, b int) distribute by hash (b); +alter table xl_child6 distribute by hash (a); +alter table xl_child6 add column c text; +alter table xl_parent attach partition xl_child6 for values in (16, 17, 18); + +create table xl_child7 (a int, b int); +alter table xl_child7 drop column b; +alter table xl_child7 add column b int; +alter table xl_child7 add column c text; +alter table xl_parent attach partition xl_child7 for values in (19, 20, 21); + +insert into xl_parent values (1, 100, 'us'); +insert into xl_parent values (4, 200, 'they'); +insert into xl_parent values (6, 300, 'me'); +insert into xl_parent values (11, 400, 'mine'); +insert into xl_parent values (12, 500, 'theirs'); +insert into xl_parent values (9, 600, 'ours'); +insert into xl_parent values (13, 700, 'yours'); +insert into xl_parent values (16, 800, 'my'); +insert into xl_parent values (19, 900, 'his'); + +select * from xl_parent order by a; +select * from xl_parent where a = 1; +select * from xl_parent where a = 10; +select * from xl_parent where a = 4; +select * from xl_parent where a = 13; +drop table xl_parent; + +create table xl_parted (a int, b int, c text) partition by list (b) distribute by hash (b); +create table xl_c1 (a int, b int, c text); +alter table xl_parted attach partition xl_c1 for values in (1, 2, 3); +drop table xl_c1; +create table xl_c1 (a int, b int, c text) distribute by hash (b); +alter table xl_parted attach partition xl_c1 for values in (1, 2, 3); +insert into xl_parted values (100, 1, 'foo'); +insert into xl_parted values (200, 3, 'bar'); +alter table xl_parted drop column a; +create table xl_c2 (b int, c text); +-- fails +alter table xl_parted attach partition xl_c2 for values in (4, 5, 6); +insert into xl_parted values (5, 'baz'); +-- since attach failed above +drop table xl_c2; +create table xl_c2 (a int, b text, c text) distribute by hash (b); +alter table xl_c2 drop column a; +alter table xl_parted attach partition xl_c2 for values in (4, 5, 6); +-- since attach failed above +drop table xl_c2; +create table xl_c2 (a int, b int, c text) distribute by hash (b); +alter table xl_c2 drop column a; +alter table xl_parted attach partition xl_c2 for values in (4, 5, 6); +insert into xl_parted values (5, 'baz'); +select * from xl_parted; +drop table xl_parted; diff --cc src/test/regress/sql/create_table.sql index 412405c898,bc6191f4ac..ba5228759c --- a/src/test/regress/sql/create_table.sql +++ b/src/test/regress/sql/create_table.sql @@@ -679,16 -680,16 +679,29 @@@ create temp table temp_part partition o drop table perm_parted cascade; drop table temp_parted cascade; + -- check that adding partitions to a table while it is being used is prevented + create table tab_part_create (a int) partition by list (a); + create or replace function func_part_create() returns trigger + language plpgsql as $$ + begin + execute 'create table tab_part_create_1 partition of tab_part_create for values in (1)'; + return null; + end $$; + create trigger trig_part_create before insert on tab_part_create + for each statement execute procedure func_part_create(); + insert into tab_part_create values (1); + drop table tab_part_create; + drop function func_part_create(); +-- xl tests +create table xl_parted (a int, b int, c text) partition by list (b) distribute by hash (b); +create table xl_c1 partition of xl_parted for values in (1, 2, 3); +insert into xl_parted values (100, 1, 'foo'); +insert into xl_parted values (200, 3, 'bar'); +alter table xl_parted drop column a; +create table xl_c2 partition of xl_parted for values in (4, 5, 6); +insert into xl_parted values (1, 'foo'); +insert into xl_parted values (3, 'bar'); +insert into xl_parted values (5, 'baz'); +-- syntax error +create table xl_c3 partition of xl_parted for values in (4, 5, 6) distribute by hash (b); +drop table xl_parted; diff --cc src/test/regress/sql/select_parallel.sql index 34c53d6424,8225719ff3..203884ea7e --- a/src/test/regress/sql/select_parallel.sql +++ b/src/test/regress/sql/select_parallel.sql @@@ -203,11 -204,36 +203,38 @@@ set force_parallel_mode=1 explain (costs off) select stringu1::int2 from tenk1 where unique1 = 1; + -- Window function calculation can't be pushed to workers. + explain (costs off, verbose) + select count(*) from tenk1 a where (unique1, two) in + (select unique1, row_number() over() from tenk1 b); + + + -- LIMIT/OFFSET within sub-selects can't be pushed to workers. + explain (costs off) + select * from tenk1 a where two in + (select two from tenk1 b where stringu1 like '%AAAA' limit 3); + -- to increase the parallel query test coverage +EXPLAIN (timing off, summary off, costs off) SELECT * FROM tenk1; + EXPLAIN (analyze, timing off, summary off, costs off) SELECT * FROM tenk1; + -- test passing expanded-value representations to workers + CREATE FUNCTION make_some_array(int,int) returns int[] as + $$declare x int[]; + begin + x[1] := $1; + x[2] := $2; + return x; + end$$ language plpgsql parallel safe; + CREATE TABLE fooarr(f1 text, f2 int[], f3 text); + INSERT INTO fooarr VALUES('1', ARRAY[1,2], 'one'); + + PREPARE pstmt(text, int[]) AS SELECT * FROM fooarr WHERE f1 = $1 AND f2 = $2; + EXPLAIN (COSTS OFF) EXECUTE pstmt('1', make_some_array(1,2)); + EXECUTE pstmt('1', make_some_array(1,2)); + DEALLOCATE pstmt; + -- provoke error in worker select stringu1::int2 from tenk1 where unique1 = 1;