#! /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 <pgsql-bugs@postgresql.org>.
+# Report bugs to <bugs@postgres-xl.org>.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
# 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_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_URL=''
ac_unique_file="src/backend/access/common/heaptuple.c"
# 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]...
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
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.
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 $@
_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
# 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
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\\"
dnl
m4_pattern_forbid(^PGAC_)dnl to catch undefined macros
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
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) :
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)
/*
* 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
#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
*
*
* 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))
* 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
signal_child(BgWriterPID, SIGTERM);
if (WalReceiverPID != 0)
signal_child(WalReceiverPID, SIGTERM);
- if (pmState == PM_RECOVERY)
+#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_STARTUP || pmState == PM_RECOVERY)
{
SignalSomeChildren(SIGTERM, BACKEND_TYPE_BGWORKER);
{
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),
* 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);
+ }
}
/*
static LOCALLOCK *awaitedLock;
static ResourceOwner awaitedOwner;
- LOCKMODE lockmode, bool sessionLock, bool dontWait, bool reportMemoryError,
- bool only_increment);
+static LockAcquireResult LockAcquireExtendedXC(const LOCKTAG *locktag,
++ LOCKMODE lockmode,
++ bool sessionLock,
++ bool dontWait,
++ bool reportMemoryError,
++ LOCALLOCK **locallockp,
++ bool only_increment);
+
#ifdef LOCK_DEBUG
bool sessionLock,
bool dontWait)
{
- return LockAcquireExtended(locktag, lockmode, sessionLock, dontWait, true);
+ return LockAcquireExtended(locktag, lockmode, sessionLock, dontWait,
+ true, NULL);
}
- true, true);
+#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, NULL, true);
+
+ return (ret == LOCKACQUIRE_ALREADY_HELD);
+}
+#endif
+
/*
* LockAcquireExtended - allows us to specify additional options
*
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;
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.
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)
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
};
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);
Oid table_oid,
ItemPointer current_tid);
- ScanState *search_plan_tree(PlanState *node, Oid table_oid);
+#ifdef PGXC
++ScanState *search_plan_tree(PlanState *node, Oid table_oid,
++ bool *pending_rescan);
+#endif
+
/*
* prototypes from functions in execGrouping.c
*/
#define MEMSET_LOOP_LIMIT 1024
/* Define to the address where bug reports for this package should be sent. */
/* 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
#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) */
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;
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;
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
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"
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;
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;
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;