From: Pavan Deolasee Date: Thu, 15 Jun 2017 07:41:07 +0000 (+0530) Subject: Merge 'remotes/PGSQL/master' into xl10devel X-Git-Tag: XL_10_R1BETA1~274 X-Git-Url: http://git.postgresql.org/gitweb/static/gitweb.js?a=commitdiff_plain;h=0ffa504a17f58f2bc045b0039f40e4917ee50d20;p=postgres-xl.git Merge 'remotes/PGSQL/master' into xl10devel Merge upstream master branch upto e800656d9a9b40b2f55afabe76354ab6d93353b3. Code compiles and regression works ok (with lots and lots of failures though). --- 0ffa504a17f58f2bc045b0039f40e4917ee50d20 diff --cc doc/src/sgml/ddl.sgml index 71339bf81d,ec015e93d0..a70047b340 mode 100755,100644..100755 --- a/doc/src/sgml/ddl.sgml +++ b/doc/src/sgml/ddl.sgml diff --cc doc/src/sgml/ref/alter_table.sgml index 1dfbf6d3c8,69600321e6..c2a484186f mode 100755,100644..100755 --- a/doc/src/sgml/ref/alter_table.sgml +++ b/doc/src/sgml/ref/alter_table.sgml diff --cc doc/src/sgml/ref/create_table.sgml index 8d1e4ee487,bc014d0879..5a3821b25e mode 100755,100644..100755 --- a/doc/src/sgml/ref/create_table.sgml +++ b/doc/src/sgml/ref/create_table.sgml diff --cc doc/src/sgml/ref/set_transaction.sgml index 11c3bfefcc,188d2ed92e..e67c29e2ec mode 100755,100644..100755 --- a/doc/src/sgml/ref/set_transaction.sgml +++ b/doc/src/sgml/ref/set_transaction.sgml diff --cc src/backend/access/transam/recovery.conf.sample index acb81afd66,8e46612642..37fbaedaa5 --- a/src/backend/access/transam/recovery.conf.sample +++ b/src/backend/access/transam/recovery.conf.sample @@@ -66,11 -66,11 +66,11 @@@ # If you want to stop rollforward at a specific point, you # must set a recovery target. # - # You may set a recovery target either by transactionId, by name, - # or by timestamp or by WAL location (LSN) or by barrier. Recovery may either - # include or exclude the transaction(s) with the recovery target value (ie, - # stop either just after or just before the given target, respectively). In - # case of barrier, the recovery stops exactly at that point. + # You may set a recovery target either by transactionId, by name, by -# timestamp or by WAL location (LSN). Recovery may either include or ++# timestamp or by WAL location (LSN) or by barrier. Recovery may either include or + # exclude the transaction(s) with the recovery target value (i.e., + # stop either just after or just before the given target, -# respectively). ++# respectively). In case of barrier, the recovery stops exactly at that point. # # #recovery_target_name = '' # e.g. 'daily backup 2011-01-26' diff --cc src/backend/catalog/catalog.c index 2e8cd10ebb,92d943cac7..0f7ffef6d0 --- a/src/backend/catalog/catalog.c +++ b/src/backend/catalog/catalog.c @@@ -39,9 -38,8 +39,10 @@@ #include "catalog/pg_shseclabel.h" #include "catalog/pg_subscription.h" #include "catalog/pg_tablespace.h" + #include "catalog/pg_type.h" #include "catalog/toasting.h" +#include "catalog/pgxc_node.h" +#include "catalog/pgxc_group.h" #include "miscadmin.h" #include "storage/fd.h" #include "utils/fmgroids.h" diff --cc src/backend/catalog/namespace.c index d7f6075b13,94755d687b..a29a232e8b --- a/src/backend/catalog/namespace.c +++ b/src/backend/catalog/namespace.c @@@ -3898,18 -3793,8 +3898,18 @@@ InitTempTableNamespace(void if (IsParallelWorker()) ereport(ERROR, (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION), - errmsg("cannot create temporary tables in parallel mode"))); + errmsg("cannot create temporary tables during a parallel operation"))); +#ifdef XCP + /* + * In case of distributed session use MyFirstBackendId for temp objects + */ + if (OidIsValid(MyCoordId)) + snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", + MyFirstBackendId); + else + /* fallback to default */ +#endif snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", MyBackendId); namespaceId = get_namespace_oid(namespaceName, true); diff --cc src/backend/commands/sequence.c index ed50208d51,2d820e5ceb..13f818a036 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@@ -145,10 -101,9 +145,10 @@@ static Form_pg_sequence_data read_seq_t static void init_params(ParseState *pstate, List *options, bool for_identity, bool isInit, Form_pg_sequence seqform, - bool *changed_seqform, - Form_pg_sequence_data seqdataform, List **owned_by, + Form_pg_sequence_data seqdataform, + bool *need_seq_rewrite, - List **owned_by); ++ List **owned_by, + bool *is_restart); static void do_setval(Oid relid, int64 next, bool iscalled); static void process_owned_by(Relation seqrel, List *owned_by, bool for_identity); @@@ -210,8 -156,9 +210,10 @@@ DefineSequence(ParseState *pstate, Crea } /* Check and set all option values */ - init_params(pstate, seq->options, seq->for_identity, true, &seqform, - &changed_seqform, &seqdataform, &owned_by, &is_restart); + init_params(pstate, seq->options, seq->for_identity, true, + &seqform, &seqdataform, - &need_seq_rewrite, &owned_by); ++ &need_seq_rewrite, &owned_by, ++ &is_restart); /* * Create relation (and fill value[] and null[] for the tuple) @@@ -497,24 -419,15 +499,24 @@@ AlterSequence(ParseState *pstate, Alter SeqTable elm; Relation seqrel; Buffer buf; - HeapTupleData seqdatatuple; + HeapTupleData datatuple; Form_pg_sequence seqform; - Form_pg_sequence_data seqdata; - FormData_pg_sequence_data newseqdata; - bool changed_seqform = false; + Form_pg_sequence_data newdataform; + bool need_seq_rewrite; List *owned_by; +#ifdef PGXC + GTM_Sequence start_value; + GTM_Sequence last_value; + GTM_Sequence min_value; + GTM_Sequence max_value; + GTM_Sequence increment; + bool cycle; + bool is_restart; +#endif ObjectAddress address; Relation rel; - HeapTuple tuple; + HeapTuple seqtuple; + HeapTuple newdatatuple; /* Open and lock sequence. */ relid = RangeVarGetRelid(stmt->sequence, @@@ -542,66 -455,48 +544,59 @@@ elog(ERROR, "cache lookup failed for sequence %u", relid); - seqform = (Form_pg_sequence) GETSTRUCT(tuple); + seqform = (Form_pg_sequence) GETSTRUCT(seqtuple); /* lock page's buffer and read tuple into new sequence structure */ - seqdata = read_seq_tuple(seqrel, &buf, &seqdatatuple); + (void) read_seq_tuple(seqrel, &buf, &datatuple); + + /* copy the existing sequence data tuple, so it can be modified localy */ + newdatatuple = heap_copytuple(&datatuple); + newdataform = (Form_pg_sequence_data) GETSTRUCT(newdatatuple); - /* Copy old sequence data into workspace */ - memcpy(&newseqdata, seqdata, sizeof(FormData_pg_sequence_data)); + UnlockReleaseBuffer(buf); /* Check and set new values */ - init_params(pstate, stmt->options, stmt->for_identity, false, seqform, - &changed_seqform, &newseqdata, &owned_by, &is_restart); + init_params(pstate, stmt->options, stmt->for_identity, false, + seqform, newdataform, - &need_seq_rewrite, &owned_by); ++ &need_seq_rewrite, &owned_by, ++ &is_restart); /* Clear local cache so that we don't think we have cached numbers */ /* Note that we do not change the currval() state */ elm->cached = elm->last; - /* check the comment above nextval_internal()'s equivalent call. */ - if (RelationNeedsWAL(seqrel)) - GetTopTransactionId(); - + /* Now okay to update the on-disk tuple */ +#ifdef PGXC + increment = seqform->seqincrement; + min_value = seqform->seqmin; + max_value = seqform->seqmax; + start_value = seqform->seqstart; + last_value = elm->last; + cycle = seqform->seqcycle; +#endif + - START_CRIT_SECTION(); - - memcpy(seqdata, &newseqdata, sizeof(FormData_pg_sequence_data)); - - MarkBufferDirty(buf); - - /* XLOG stuff */ - if (RelationNeedsWAL(seqrel)) + /* If needed, rewrite the sequence relation itself */ + if (need_seq_rewrite) { - xl_seq_rec xlrec; - XLogRecPtr recptr; - Page page = BufferGetPage(buf); - - XLogBeginInsert(); - XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT); - - xlrec.node = seqrel->rd_node; - XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec)); - - XLogRegisterData((char *) seqdatatuple.t_data, seqdatatuple.t_len); + /* check the comment above nextval_internal()'s equivalent call. */ + if (RelationNeedsWAL(seqrel)) + GetTopTransactionId(); - recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG); + /* + * Create a new storage file for the sequence, making the state + * changes transactional. We want to keep the sequence's relfrozenxid + * at 0, since it won't contain any unfrozen XIDs. Same with + * relminmxid, since a sequence will never contain multixacts. + */ + RelationSetNewRelfilenode(seqrel, seqrel->rd_rel->relpersistence, + InvalidTransactionId, InvalidMultiXactId); - PageSetLSN(page, recptr); + /* + * Insert the modified tuple into the new storage file. + */ + fill_seq_with_data(seqrel, newdatatuple); } - END_CRIT_SECTION(); - - UnlockReleaseBuffer(buf); - /* process OWNED BY if given */ if (owned_by) process_owned_by(seqrel, owned_by, stmt->for_identity); @@@ -610,36 -508,9 +608,33 @@@ ObjectAddressSet(address, RelationRelationId, relid); - if (changed_seqform) - CatalogTupleUpdate(rel, &tuple->t_self, tuple); heap_close(rel, RowExclusiveLock); - relation_close(seqrel, NoLock); +#ifdef PGXC + /* + * Remote Coordinator is in charge of create sequence in GTM + * If sequence is temporary, no need to go through GTM. + */ + if (IS_PGXC_LOCAL_COORDINATOR && seqrel->rd_backend != MyBackendId) + { + char *seqname = GetGlobalSeqName(seqrel, NULL, NULL); + + /* We also need to create it on the GTM */ + if (AlterSequenceGTM(seqname, + increment, + min_value, + max_value, + start_value, + last_value, + cycle, + is_restart) < 0) + ereport(ERROR, + (errcode(ERRCODE_CONNECTION_FAILURE), + errmsg("GTM error, could not alter sequence"))); + pfree(seqname); + } +#endif return address; } @@@ -1485,10 -1236,9 +1464,10 @@@ static voi init_params(ParseState *pstate, List *options, bool for_identity, bool isInit, Form_pg_sequence seqform, - bool *changed_seqform, Form_pg_sequence_data seqdataform, + bool *need_seq_rewrite, - List **owned_by) + List **owned_by, + bool *is_restart) { DefElem *as_type = NULL; DefElem *start_value = NULL; @@@ -1502,10 -1252,7 +1481,11 @@@ bool reset_max_value = false; bool reset_min_value = false; +#ifdef PGXC + *is_restart = false; +#endif + + *need_seq_rewrite = false; *owned_by = NIL; foreach(option, options) diff --cc src/backend/nodes/readfuncs.c index 5147eaa4d3,039910e1f7..935bb196f7 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@@ -4023,15 -2637,9 +4022,15 @@@ parseNodeString(void return_value = _readAlternativeSubPlan(); else if (MATCH("EXTENSIBLENODE", 14)) return_value = _readExtensibleNode(); + else if (MATCH("REMOTESUBPLAN", 13)) + return_value = _readRemoteSubplan(); + else if (MATCH("REMOTESTMT", 10)) + return_value = _readRemoteStmt(); + else if (MATCH("SIMPLESORT", 10)) + return_value = _readSimpleSort(); - else if (MATCH("PARTITIONBOUND", 14)) + else if (MATCH("PARTITIONBOUNDSPEC", 18)) return_value = _readPartitionBoundSpec(); - else if (MATCH("PARTRANGEDATUM", 14)) + else if (MATCH("PARTITIONRANGEDATUM", 19)) return_value = _readPartitionRangeDatum(); else { diff --cc src/backend/storage/lmgr/predicate.c index 30aea14385,bce505a3fa..38c2e493a5 --- a/src/backend/storage/lmgr/predicate.c +++ b/src/backend/storage/lmgr/predicate.c @@@ -1741,9 -1745,9 +1745,9 @@@ GetSerializableTransactionSnapshotInt(S } while (!sxact); /* Get the snapshot, or check that it's safe to use */ - if (!TransactionIdIsValid(sourcexid)) + if (!sourcevxid) - snapshot = GetSnapshotData(snapshot); + snapshot = GetSnapshotData(snapshot, false); - else if (!ProcArrayInstallImportedXmin(snapshot->xmin, sourcexid)) + else if (!ProcArrayInstallImportedXmin(snapshot->xmin, sourcevxid)) { ReleasePredXact(sxact); LWLockRelease(SerializableXactHashLock); diff --cc src/bin/pg_dump/pg_dumpall.c index 9534134e61,2a08abfba5..fbd6342de5 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.c @@@ -144,11 -136,7 +145,10 @@@ main(int argc, char *argv[] {"no-subscriptions", no_argument, &no_subscriptions, 1}, {"no-sync", no_argument, NULL, 4}, {"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1}, - {"no-role-passwords", no_argument, &no_role_passwords, 1}, - +#ifdef PGXC + {"dump-nodes", no_argument, &dump_nodes, 1}, + {"include-nodes", no_argument, &include_nodes, 1}, +#endif {NULL, 0, NULL, 0} }; diff --cc src/include/Makefile index 6afa3cfe25,a689d352b6..ea3b9245c0 --- a/src/include/Makefile +++ b/src/include/Makefile @@@ -19,11 -19,11 +19,11 @@@ all: pg_config.h pg_config_ext.h pg_con # Subdirectories containing installable headers SUBDIRS = access bootstrap catalog commands common datatype \ executor fe_utils foreign \ - lib libpq mb nodes optimizer parser postmaster regex replication \ + lib libpq mb nodes optimizer parser pgxc postmaster regex replication \ - rewrite storage tcop snowball snowball/libstemmer tsearch \ + rewrite statistics storage tcop snowball snowball/libstemmer tsearch \ tsearch/dicts utils port port/atomics port/win32 port/win32_msvc \ port/win32_msvc/sys port/win32/arpa port/win32/netinet \ - port/win32/sys portability + port/win32/sys portability gtm # Install all headers install: all installdirs diff --cc src/include/nodes/parsenodes.h index 8d4e58ca89,271564fd23..fb3684eb5c --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@@ -951,12 -942,13 +951,17 @@@ typedef struct RangeTblEntr * code that is being actively worked on. FIXME someday. */ +#ifdef PGXC + char *relname; +#endif + /* * Fields valid for a plain relation RTE (else zero): + * + * As a special case, RTE_NAMEDTUPLESTORE can also set relid to indicate + * that the tuple format of the tuplestore is the same as the referenced + * relation. This allows plans referencing AFTER trigger transition + * tables to be invalidated if the underlying table is altered. */ Oid relid; /* OID of the relation */ char relkind; /* relation kind (see pg_class.relkind) */ diff --cc src/include/parser/parse_func.h index e0dad6ac10,68572e9d2a..c684217e33 --- a/src/include/parser/parse_func.h +++ b/src/include/parser/parse_func.h @@@ -67,7 -67,7 +67,8 @@@ extern Oid LookupFuncWithArgs(ObjectWit extern Oid LookupAggWithArgs(ObjectWithArgs *agg, bool noError); - extern void check_srf_call_placement(ParseState *pstate, int location); + extern void check_srf_call_placement(ParseState *pstate, Node *last_srf, + int location); +extern void check_pg_get_expr_args(ParseState *pstate, Oid fnoid, List *args); #endif /* PARSE_FUNC_H */ diff --cc src/include/storage/procarray.h index bc46229b42,5cf8ff7538..7dfe37f881 --- a/src/include/storage/procarray.h +++ b/src/include/storage/procarray.h @@@ -105,13 -79,11 +105,13 @@@ extern void ExpireOldKnownAssignedTrans extern int GetMaxSnapshotXidCount(void); extern int GetMaxSnapshotSubxidCount(void); -extern Snapshot GetSnapshotData(Snapshot snapshot); +extern Snapshot GetSnapshotData(Snapshot snapshot, bool latest); extern bool ProcArrayInstallImportedXmin(TransactionId xmin, - TransactionId sourcexid); + VirtualTransactionId *sourcevxid); extern bool ProcArrayInstallRestoredXmin(TransactionId xmin, PGPROC *proc); +extern void ProcArrayCheckXminConsistency(TransactionId global_xmin); +extern void SetLatestCompletedXid(TransactionId latestCompletedXid); extern RunningTransactions GetRunningTransactionData(void); diff --cc src/include/storage/procsignal.h index 67cb913829,8f0161bf77..d58c1bede9 --- a/src/include/storage/procsignal.h +++ b/src/include/storage/procsignal.h @@@ -41,11 -31,9 +41,13 @@@ typedef enu { PROCSIG_CATCHUP_INTERRUPT, /* sinval catchup interrupt */ PROCSIG_NOTIFY_INTERRUPT, /* listen/notify interrupt */ +#ifdef PGXC + PROCSIG_PGXCPOOL_RELOAD, /* abort current transaction and reconnect to pooler */ + PROCSIG_PGXCPOOL_REFRESH, /* refresh local view of connection handles */ +#endif PROCSIG_PARALLEL_MESSAGE, /* message from cooperating parallel backend */ + PROCSIG_WALSND_INIT_STOPPING, /* ask walsenders to prepare for + * shutdown */ /* Recovery conflict reasons */ PROCSIG_RECOVERY_CONFLICT_DATABASE, diff --cc src/test/regress/expected/foreign_data.out index de22510740,7f2f529393..cdafb90762 --- a/src/test/regress/expected/foreign_data.out +++ b/src/test/regress/expected/foreign_data.out @@@ -266,73 -283,65 +266,72 @@@ ERROR: foreign-data wrapper "foo" doe -- exercise CREATE SERVER CREATE SERVER s1 FOREIGN DATA WRAPPER foo; -- ERROR -ERROR: foreign-data wrapper "foo" does not exist +ERROR: Postgres-XL does not support SERVER yet +DETAIL: The feature is not currently supported CREATE FOREIGN DATA WRAPPER foo OPTIONS ("test wrapper" 'true'); +ERROR: Postgres-XL does not support FOREIGN DATA WRAPPER yet +DETAIL: The feature is not currently supported CREATE SERVER s1 FOREIGN DATA WRAPPER foo; +ERROR: Postgres-XL does not support SERVER yet +DETAIL: The feature is not currently supported CREATE SERVER s1 FOREIGN DATA WRAPPER foo; -- ERROR -ERROR: server "s1" already exists -CREATE SERVER IF NOT EXISTS s1 FOREIGN DATA WRAPPER foo; -- No ERROR, just NOTICE -NOTICE: server "s1" already exists, skipping +ERROR: Postgres-XL does not support SERVER yet +DETAIL: The feature is not currently supported CREATE SERVER s2 FOREIGN DATA WRAPPER foo OPTIONS (host 'a', dbname 'b'); +ERROR: Postgres-XL does not support SERVER yet +DETAIL: The feature is not currently supported CREATE SERVER s3 TYPE 'oracle' FOREIGN DATA WRAPPER foo; +ERROR: Postgres-XL does not support SERVER yet +DETAIL: The feature is not currently supported CREATE SERVER s4 TYPE 'oracle' FOREIGN DATA WRAPPER foo OPTIONS (host 'a', dbname 'b'); +ERROR: Postgres-XL does not support SERVER yet +DETAIL: The feature is not currently supported CREATE SERVER s5 VERSION '15.0' FOREIGN DATA WRAPPER foo; +ERROR: Postgres-XL does not support SERVER yet +DETAIL: The feature is not currently supported CREATE SERVER s6 VERSION '16.0' FOREIGN DATA WRAPPER foo OPTIONS (host 'a', dbname 'b'); +ERROR: Postgres-XL does not support SERVER yet +DETAIL: The feature is not currently supported CREATE SERVER s7 TYPE 'oracle' VERSION '17.0' FOREIGN DATA WRAPPER foo OPTIONS (host 'a', dbname 'b'); +ERROR: Postgres-XL does not support SERVER yet +DETAIL: The feature is not currently supported CREATE SERVER s8 FOREIGN DATA WRAPPER postgresql OPTIONS (foo '1'); -- ERROR -ERROR: invalid option "foo" -HINT: Valid options in this context are: authtype, service, connect_timeout, dbname, host, hostaddr, port, tty, options, requiressl, sslmode, gsslib +ERROR: Postgres-XL does not support SERVER yet +DETAIL: The feature is not currently supported CREATE SERVER s8 FOREIGN DATA WRAPPER postgresql OPTIONS (host 'localhost', dbname 's8db'); +ERROR: Postgres-XL does not support SERVER yet +DETAIL: The feature is not currently supported \des+ - List of foreign servers - Name | Owner | Foreign-data wrapper | Access privileges | Type | Version | FDW options | Description -------+---------------------------+----------------------+-------------------+--------+---------+-----------------------------------+------------- - s1 | regress_foreign_data_user | foo | | | | | - s2 | regress_foreign_data_user | foo | | | | (host 'a', dbname 'b') | - s3 | regress_foreign_data_user | foo | | oracle | | | - s4 | regress_foreign_data_user | foo | | oracle | | (host 'a', dbname 'b') | - s5 | regress_foreign_data_user | foo | | | 15.0 | | - s6 | regress_foreign_data_user | foo | | | 16.0 | (host 'a', dbname 'b') | - s7 | regress_foreign_data_user | foo | | oracle | 17.0 | (host 'a', dbname 'b') | - s8 | regress_foreign_data_user | postgresql | | | | (host 'localhost', dbname 's8db') | -(8 rows) - + List of foreign servers + Name | Owner | Foreign-data wrapper | Access privileges | Type | Version | FDW Options | Description +------+-------+----------------------+-------------------+------+---------+-------------+------------- +(0 rows) - SET ROLE regress_test_role; CREATE SERVER t1 FOREIGN DATA WRAPPER foo; -- ERROR: no usage on FDW -ERROR: permission denied for foreign-data wrapper foo +ERROR: Postgres-XL does not support SERVER yet +DETAIL: The feature is not currently supported RESET ROLE; GRANT USAGE ON FOREIGN DATA WRAPPER foo TO regress_test_role; +ERROR: foreign-data wrapper "foo" does not exist SET ROLE regress_test_role; CREATE SERVER t1 FOREIGN DATA WRAPPER foo; +ERROR: Postgres-XL does not support SERVER yet +DETAIL: The feature is not currently supported RESET ROLE; \des+ - List of foreign servers - Name | Owner | Foreign-data wrapper | Access privileges | Type | Version | FDW options | Description -------+---------------------------+----------------------+-------------------+--------+---------+-----------------------------------+------------- - s1 | regress_foreign_data_user | foo | | | | | - s2 | regress_foreign_data_user | foo | | | | (host 'a', dbname 'b') | - s3 | regress_foreign_data_user | foo | | oracle | | | - s4 | regress_foreign_data_user | foo | | oracle | | (host 'a', dbname 'b') | - s5 | regress_foreign_data_user | foo | | | 15.0 | | - s6 | regress_foreign_data_user | foo | | | 16.0 | (host 'a', dbname 'b') | - s7 | regress_foreign_data_user | foo | | oracle | 17.0 | (host 'a', dbname 'b') | - s8 | regress_foreign_data_user | postgresql | | | | (host 'localhost', dbname 's8db') | - t1 | regress_test_role | foo | | | | | -(9 rows) + List of foreign servers + Name | Owner | Foreign-data wrapper | Access privileges | Type | Version | FDW Options | Description +------+-------+----------------------+-------------------+------+---------+-------------+------------- +(0 rows) REVOKE USAGE ON FOREIGN DATA WRAPPER foo FROM regress_test_role; +ERROR: foreign-data wrapper "foo" does not exist GRANT USAGE ON FOREIGN DATA WRAPPER foo TO regress_test_indirect; +ERROR: foreign-data wrapper "foo" does not exist SET ROLE regress_test_role; CREATE SERVER t2 FOREIGN DATA WRAPPER foo; -- ERROR -ERROR: permission denied for foreign-data wrapper foo +ERROR: Postgres-XL does not support SERVER yet +DETAIL: The feature is not currently supported RESET ROLE; GRANT regress_test_indirect TO regress_test_role; SET ROLE regress_test_role; diff --cc src/test/regress/expected/rowsecurity.out index 67fd53a2a0,26d28f248b..68c4e740fe --- a/src/test/regress/expected/rowsecurity.out +++ b/src/test/regress/expected/rowsecurity.out @@@ -784,20 -888,453 +784,456 @@@ SELECT * FROM t1 WHERE f_leak(b) (11 rows) EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE f_leak(b); - QUERY PLAN ---------------------------- + QUERY PLAN +----------------------------------------------------------- Append - -> Seq Scan on t1 - Filter: f_leak(b) - -> Seq Scan on t2 - Filter: f_leak(b) - -> Seq Scan on t3 - Filter: f_leak(b) -(7 rows) + -> Remote Subquery Scan on all (datanode_1,datanode_2) + -> Seq Scan on t1 + Filter: f_leak(b) + -> Remote Subquery Scan on all (datanode_1,datanode_2) + -> Seq Scan on t2 + Filter: f_leak(b) + -> Remote Subquery Scan on all (datanode_1,datanode_2) + -> Seq Scan on t3 + Filter: f_leak(b) +(10 rows) + -- + -- Partitioned Tables + -- + SET SESSION AUTHORIZATION regress_rls_alice; + CREATE TABLE part_document ( + did int, + cid int, + dlevel int not null, + dauthor name, + dtitle text + ) PARTITION BY RANGE (cid); + GRANT ALL ON part_document TO public; + -- Create partitions for document categories + CREATE TABLE part_document_fiction PARTITION OF part_document FOR VALUES FROM (11) to (12); + CREATE TABLE part_document_satire PARTITION OF part_document FOR VALUES FROM (55) to (56); + CREATE TABLE part_document_nonfiction PARTITION OF part_document FOR VALUES FROM (99) to (100); + GRANT ALL ON part_document_fiction TO public; + GRANT ALL ON part_document_satire TO public; + GRANT ALL ON part_document_nonfiction TO public; + INSERT INTO part_document VALUES + ( 1, 11, 1, 'regress_rls_bob', 'my first novel'), + ( 2, 11, 2, 'regress_rls_bob', 'my second novel'), + ( 3, 99, 2, 'regress_rls_bob', 'my science textbook'), + ( 4, 55, 1, 'regress_rls_bob', 'my first satire'), + ( 5, 99, 2, 'regress_rls_bob', 'my history book'), + ( 6, 11, 1, 'regress_rls_carol', 'great science fiction'), + ( 7, 99, 2, 'regress_rls_carol', 'great technology book'), + ( 8, 55, 2, 'regress_rls_carol', 'great satire'), + ( 9, 11, 1, 'regress_rls_dave', 'awesome science fiction'), + (10, 99, 2, 'regress_rls_dave', 'awesome technology book'); + ALTER TABLE part_document ENABLE ROW LEVEL SECURITY; + -- Create policy on parent + -- user's security level must be higher than or equal to document's + CREATE POLICY pp1 ON part_document AS PERMISSIVE + USING (dlevel <= (SELECT seclv FROM uaccount WHERE pguser = current_user)); + -- Dave is only allowed to see cid < 55 + CREATE POLICY pp1r ON part_document AS RESTRICTIVE TO regress_rls_dave + USING (cid < 55); + \d+ part_document + Table "regress_rls_schema.part_document" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description + ---------+---------+-----------+----------+---------+----------+--------------+------------- + did | integer | | | | plain | | + cid | integer | | | | plain | | + dlevel | integer | | not null | | plain | | + dauthor | name | | | | plain | | + dtitle | text | | | | extended | | + Partition key: RANGE (cid) + Policies: + POLICY "pp1" + USING ((dlevel <= ( SELECT uaccount.seclv + FROM uaccount + WHERE (uaccount.pguser = CURRENT_USER)))) + POLICY "pp1r" AS RESTRICTIVE + TO regress_rls_dave + USING ((cid < 55)) + Partitions: part_document_fiction FOR VALUES FROM (11) TO (12), + part_document_nonfiction FOR VALUES FROM (99) TO (100), + part_document_satire FOR VALUES FROM (55) TO (56) + + SELECT * FROM pg_policies WHERE schemaname = 'regress_rls_schema' AND tablename like '%part_document%' ORDER BY policyname; + schemaname | tablename | policyname | permissive | roles | cmd | qual | with_check + --------------------+---------------+------------+-------------+--------------------+-----+--------------------------------------------+------------ + regress_rls_schema | part_document | pp1 | PERMISSIVE | {public} | ALL | (dlevel <= ( SELECT uaccount.seclv +| + | | | | | | FROM uaccount +| + | | | | | | WHERE (uaccount.pguser = CURRENT_USER))) | + regress_rls_schema | part_document | pp1r | RESTRICTIVE | {regress_rls_dave} | ALL | (cid < 55) | + (2 rows) + + -- viewpoint from regress_rls_bob + SET SESSION AUTHORIZATION regress_rls_bob; + SET row_security TO ON; + SELECT * FROM part_document WHERE f_leak(dtitle) ORDER BY did; + NOTICE: f_leak => my first novel + NOTICE: f_leak => great science fiction + NOTICE: f_leak => awesome science fiction + NOTICE: f_leak => my first satire + did | cid | dlevel | dauthor | dtitle + -----+-----+--------+-------------------+------------------------- + 1 | 11 | 1 | regress_rls_bob | my first novel + 4 | 55 | 1 | regress_rls_bob | my first satire + 6 | 11 | 1 | regress_rls_carol | great science fiction + 9 | 11 | 1 | regress_rls_dave | awesome science fiction + (4 rows) + + EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle); + QUERY PLAN + ----------------------------------------------------- + Append + InitPlan 1 (returns $0) + -> Index Scan using uaccount_pkey on uaccount + Index Cond: (pguser = CURRENT_USER) + -> Seq Scan on part_document_fiction + Filter: ((dlevel <= $0) AND f_leak(dtitle)) + -> Seq Scan on part_document_satire + Filter: ((dlevel <= $0) AND f_leak(dtitle)) + -> Seq Scan on part_document_nonfiction + Filter: ((dlevel <= $0) AND f_leak(dtitle)) + (10 rows) + + -- viewpoint from regress_rls_carol + SET SESSION AUTHORIZATION regress_rls_carol; + SELECT * FROM part_document WHERE f_leak(dtitle) ORDER BY did; + NOTICE: f_leak => my first novel + NOTICE: f_leak => my second novel + NOTICE: f_leak => great science fiction + NOTICE: f_leak => awesome science fiction + NOTICE: f_leak => my first satire + NOTICE: f_leak => great satire + NOTICE: f_leak => my science textbook + NOTICE: f_leak => my history book + NOTICE: f_leak => great technology book + NOTICE: f_leak => awesome technology book + did | cid | dlevel | dauthor | dtitle + -----+-----+--------+-------------------+------------------------- + 1 | 11 | 1 | regress_rls_bob | my first novel + 2 | 11 | 2 | regress_rls_bob | my second novel + 3 | 99 | 2 | regress_rls_bob | my science textbook + 4 | 55 | 1 | regress_rls_bob | my first satire + 5 | 99 | 2 | regress_rls_bob | my history book + 6 | 11 | 1 | regress_rls_carol | great science fiction + 7 | 99 | 2 | regress_rls_carol | great technology book + 8 | 55 | 2 | regress_rls_carol | great satire + 9 | 11 | 1 | regress_rls_dave | awesome science fiction + 10 | 99 | 2 | regress_rls_dave | awesome technology book + (10 rows) + + EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle); + QUERY PLAN + ----------------------------------------------------- + Append + InitPlan 1 (returns $0) + -> Index Scan using uaccount_pkey on uaccount + Index Cond: (pguser = CURRENT_USER) + -> Seq Scan on part_document_fiction + Filter: ((dlevel <= $0) AND f_leak(dtitle)) + -> Seq Scan on part_document_satire + Filter: ((dlevel <= $0) AND f_leak(dtitle)) + -> Seq Scan on part_document_nonfiction + Filter: ((dlevel <= $0) AND f_leak(dtitle)) + (10 rows) + + -- viewpoint from regress_rls_dave + SET SESSION AUTHORIZATION regress_rls_dave; + SELECT * FROM part_document WHERE f_leak(dtitle) ORDER BY did; + NOTICE: f_leak => my first novel + NOTICE: f_leak => my second novel + NOTICE: f_leak => great science fiction + NOTICE: f_leak => awesome science fiction + did | cid | dlevel | dauthor | dtitle + -----+-----+--------+-------------------+------------------------- + 1 | 11 | 1 | regress_rls_bob | my first novel + 2 | 11 | 2 | regress_rls_bob | my second novel + 6 | 11 | 1 | regress_rls_carol | great science fiction + 9 | 11 | 1 | regress_rls_dave | awesome science fiction + (4 rows) + + EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle); + QUERY PLAN + -------------------------------------------------------------------- + Append + InitPlan 1 (returns $0) + -> Index Scan using uaccount_pkey on uaccount + Index Cond: (pguser = CURRENT_USER) + -> Seq Scan on part_document_fiction + Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle)) + (6 rows) + + -- pp1 ERROR + INSERT INTO part_document VALUES (100, 11, 5, 'regress_rls_dave', 'testing pp1'); -- fail + ERROR: new row violates row-level security policy for table "part_document" + -- pp1r ERROR + INSERT INTO part_document VALUES (100, 99, 1, 'regress_rls_dave', 'testing pp1r'); -- fail + ERROR: new row violates row-level security policy "pp1r" for table "part_document" + -- Show that RLS policy does not apply for direct inserts to children + -- This should fail with RLS POLICY pp1r violation. + INSERT INTO part_document VALUES (100, 55, 1, 'regress_rls_dave', 'testing RLS with partitions'); -- fail + ERROR: new row violates row-level security policy "pp1r" for table "part_document" + -- But this should succeed. + INSERT INTO part_document_satire VALUES (100, 55, 1, 'regress_rls_dave', 'testing RLS with partitions'); -- success + -- We still cannot see the row using the parent + SELECT * FROM part_document WHERE f_leak(dtitle) ORDER BY did; + NOTICE: f_leak => my first novel + NOTICE: f_leak => my second novel + NOTICE: f_leak => great science fiction + NOTICE: f_leak => awesome science fiction + did | cid | dlevel | dauthor | dtitle + -----+-----+--------+-------------------+------------------------- + 1 | 11 | 1 | regress_rls_bob | my first novel + 2 | 11 | 2 | regress_rls_bob | my second novel + 6 | 11 | 1 | regress_rls_carol | great science fiction + 9 | 11 | 1 | regress_rls_dave | awesome science fiction + (4 rows) + + -- But we can if we look directly + SELECT * FROM part_document_satire WHERE f_leak(dtitle) ORDER BY did; + NOTICE: f_leak => my first satire + NOTICE: f_leak => great satire + NOTICE: f_leak => testing RLS with partitions + did | cid | dlevel | dauthor | dtitle + -----+-----+--------+-------------------+----------------------------- + 4 | 55 | 1 | regress_rls_bob | my first satire + 8 | 55 | 2 | regress_rls_carol | great satire + 100 | 55 | 1 | regress_rls_dave | testing RLS with partitions + (3 rows) + + -- Turn on RLS and create policy on child to show RLS is checked before constraints + SET SESSION AUTHORIZATION regress_rls_alice; + ALTER TABLE part_document_satire ENABLE ROW LEVEL SECURITY; + CREATE POLICY pp3 ON part_document_satire AS RESTRICTIVE + USING (cid < 55); + -- This should fail with RLS violation now. + SET SESSION AUTHORIZATION regress_rls_dave; + INSERT INTO part_document_satire VALUES (101, 55, 1, 'regress_rls_dave', 'testing RLS with partitions'); -- fail + ERROR: new row violates row-level security policy for table "part_document_satire" + -- And now we cannot see directly into the partition either, due to RLS + SELECT * FROM part_document_satire WHERE f_leak(dtitle) ORDER BY did; + did | cid | dlevel | dauthor | dtitle + -----+-----+--------+---------+-------- + (0 rows) + + -- The parent looks same as before + -- viewpoint from regress_rls_dave + SELECT * FROM part_document WHERE f_leak(dtitle) ORDER BY did; + NOTICE: f_leak => my first novel + NOTICE: f_leak => my second novel + NOTICE: f_leak => great science fiction + NOTICE: f_leak => awesome science fiction + did | cid | dlevel | dauthor | dtitle + -----+-----+--------+-------------------+------------------------- + 1 | 11 | 1 | regress_rls_bob | my first novel + 2 | 11 | 2 | regress_rls_bob | my second novel + 6 | 11 | 1 | regress_rls_carol | great science fiction + 9 | 11 | 1 | regress_rls_dave | awesome science fiction + (4 rows) + + EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle); + QUERY PLAN + -------------------------------------------------------------------- + Append + InitPlan 1 (returns $0) + -> Index Scan using uaccount_pkey on uaccount + Index Cond: (pguser = CURRENT_USER) + -> Seq Scan on part_document_fiction + Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle)) + (6 rows) + + -- viewpoint from regress_rls_carol + SET SESSION AUTHORIZATION regress_rls_carol; + SELECT * FROM part_document WHERE f_leak(dtitle) ORDER BY did; + NOTICE: f_leak => my first novel + NOTICE: f_leak => my second novel + NOTICE: f_leak => great science fiction + NOTICE: f_leak => awesome science fiction + NOTICE: f_leak => my first satire + NOTICE: f_leak => great satire + NOTICE: f_leak => testing RLS with partitions + NOTICE: f_leak => my science textbook + NOTICE: f_leak => my history book + NOTICE: f_leak => great technology book + NOTICE: f_leak => awesome technology book + did | cid | dlevel | dauthor | dtitle + -----+-----+--------+-------------------+----------------------------- + 1 | 11 | 1 | regress_rls_bob | my first novel + 2 | 11 | 2 | regress_rls_bob | my second novel + 3 | 99 | 2 | regress_rls_bob | my science textbook + 4 | 55 | 1 | regress_rls_bob | my first satire + 5 | 99 | 2 | regress_rls_bob | my history book + 6 | 11 | 1 | regress_rls_carol | great science fiction + 7 | 99 | 2 | regress_rls_carol | great technology book + 8 | 55 | 2 | regress_rls_carol | great satire + 9 | 11 | 1 | regress_rls_dave | awesome science fiction + 10 | 99 | 2 | regress_rls_dave | awesome technology book + 100 | 55 | 1 | regress_rls_dave | testing RLS with partitions + (11 rows) + + EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle); + QUERY PLAN + ----------------------------------------------------- + Append + InitPlan 1 (returns $0) + -> Index Scan using uaccount_pkey on uaccount + Index Cond: (pguser = CURRENT_USER) + -> Seq Scan on part_document_fiction + Filter: ((dlevel <= $0) AND f_leak(dtitle)) + -> Seq Scan on part_document_satire + Filter: ((dlevel <= $0) AND f_leak(dtitle)) + -> Seq Scan on part_document_nonfiction + Filter: ((dlevel <= $0) AND f_leak(dtitle)) + (10 rows) + + -- only owner can change policies + ALTER POLICY pp1 ON part_document USING (true); --fail + ERROR: must be owner of relation part_document + DROP POLICY pp1 ON part_document; --fail + ERROR: must be owner of relation part_document + SET SESSION AUTHORIZATION regress_rls_alice; + ALTER POLICY pp1 ON part_document USING (dauthor = current_user); + -- viewpoint from regress_rls_bob again + SET SESSION AUTHORIZATION regress_rls_bob; + SELECT * FROM part_document WHERE f_leak(dtitle) ORDER BY did; + NOTICE: f_leak => my first novel + NOTICE: f_leak => my second novel + NOTICE: f_leak => my first satire + NOTICE: f_leak => my science textbook + NOTICE: f_leak => my history book + did | cid | dlevel | dauthor | dtitle + -----+-----+--------+-----------------+--------------------- + 1 | 11 | 1 | regress_rls_bob | my first novel + 2 | 11 | 2 | regress_rls_bob | my second novel + 3 | 99 | 2 | regress_rls_bob | my science textbook + 4 | 55 | 1 | regress_rls_bob | my first satire + 5 | 99 | 2 | regress_rls_bob | my history book + (5 rows) + + -- viewpoint from rls_regres_carol again + SET SESSION AUTHORIZATION regress_rls_carol; + SELECT * FROM part_document WHERE f_leak(dtitle) ORDER BY did; + NOTICE: f_leak => great science fiction + NOTICE: f_leak => great satire + NOTICE: f_leak => great technology book + did | cid | dlevel | dauthor | dtitle + -----+-----+--------+-------------------+----------------------- + 6 | 11 | 1 | regress_rls_carol | great science fiction + 7 | 99 | 2 | regress_rls_carol | great technology book + 8 | 55 | 2 | regress_rls_carol | great satire + (3 rows) + + EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle); + QUERY PLAN + --------------------------------------------------------------- + Append + -> Seq Scan on part_document_fiction + Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle)) + -> Seq Scan on part_document_satire + Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle)) + -> Seq Scan on part_document_nonfiction + Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle)) + (7 rows) + + -- database superuser does bypass RLS policy when enabled + RESET SESSION AUTHORIZATION; + SET row_security TO ON; + SELECT * FROM part_document ORDER BY did; + did | cid | dlevel | dauthor | dtitle + -----+-----+--------+-------------------+----------------------------- + 1 | 11 | 1 | regress_rls_bob | my first novel + 2 | 11 | 2 | regress_rls_bob | my second novel + 3 | 99 | 2 | regress_rls_bob | my science textbook + 4 | 55 | 1 | regress_rls_bob | my first satire + 5 | 99 | 2 | regress_rls_bob | my history book + 6 | 11 | 1 | regress_rls_carol | great science fiction + 7 | 99 | 2 | regress_rls_carol | great technology book + 8 | 55 | 2 | regress_rls_carol | great satire + 9 | 11 | 1 | regress_rls_dave | awesome science fiction + 10 | 99 | 2 | regress_rls_dave | awesome technology book + 100 | 55 | 1 | regress_rls_dave | testing RLS with partitions + (11 rows) + + SELECT * FROM part_document_satire ORDER by did; + did | cid | dlevel | dauthor | dtitle + -----+-----+--------+-------------------+----------------------------- + 4 | 55 | 1 | regress_rls_bob | my first satire + 8 | 55 | 2 | regress_rls_carol | great satire + 100 | 55 | 1 | regress_rls_dave | testing RLS with partitions + (3 rows) + + -- database non-superuser with bypass privilege can bypass RLS policy when disabled + SET SESSION AUTHORIZATION regress_rls_exempt_user; + SET row_security TO OFF; + SELECT * FROM part_document ORDER BY did; + did | cid | dlevel | dauthor | dtitle + -----+-----+--------+-------------------+----------------------------- + 1 | 11 | 1 | regress_rls_bob | my first novel + 2 | 11 | 2 | regress_rls_bob | my second novel + 3 | 99 | 2 | regress_rls_bob | my science textbook + 4 | 55 | 1 | regress_rls_bob | my first satire + 5 | 99 | 2 | regress_rls_bob | my history book + 6 | 11 | 1 | regress_rls_carol | great science fiction + 7 | 99 | 2 | regress_rls_carol | great technology book + 8 | 55 | 2 | regress_rls_carol | great satire + 9 | 11 | 1 | regress_rls_dave | awesome science fiction + 10 | 99 | 2 | regress_rls_dave | awesome technology book + 100 | 55 | 1 | regress_rls_dave | testing RLS with partitions + (11 rows) + + SELECT * FROM part_document_satire ORDER by did; + did | cid | dlevel | dauthor | dtitle + -----+-----+--------+-------------------+----------------------------- + 4 | 55 | 1 | regress_rls_bob | my first satire + 8 | 55 | 2 | regress_rls_carol | great satire + 100 | 55 | 1 | regress_rls_dave | testing RLS with partitions + (3 rows) + + -- RLS policy does not apply to table owner when RLS enabled. + SET SESSION AUTHORIZATION regress_rls_alice; + SET row_security TO ON; + SELECT * FROM part_document ORDER by did; + did | cid | dlevel | dauthor | dtitle + -----+-----+--------+-------------------+----------------------------- + 1 | 11 | 1 | regress_rls_bob | my first novel + 2 | 11 | 2 | regress_rls_bob | my second novel + 3 | 99 | 2 | regress_rls_bob | my science textbook + 4 | 55 | 1 | regress_rls_bob | my first satire + 5 | 99 | 2 | regress_rls_bob | my history book + 6 | 11 | 1 | regress_rls_carol | great science fiction + 7 | 99 | 2 | regress_rls_carol | great technology book + 8 | 55 | 2 | regress_rls_carol | great satire + 9 | 11 | 1 | regress_rls_dave | awesome science fiction + 10 | 99 | 2 | regress_rls_dave | awesome technology book + 100 | 55 | 1 | regress_rls_dave | testing RLS with partitions + (11 rows) + + SELECT * FROM part_document_satire ORDER by did; + did | cid | dlevel | dauthor | dtitle + -----+-----+--------+-------------------+----------------------------- + 4 | 55 | 1 | regress_rls_bob | my first satire + 8 | 55 | 2 | regress_rls_carol | great satire + 100 | 55 | 1 | regress_rls_dave | testing RLS with partitions + (3 rows) + + -- When RLS disabled, other users get ERROR. + SET SESSION AUTHORIZATION regress_rls_dave; + SET row_security TO OFF; + SELECT * FROM part_document ORDER by did; + ERROR: query would be affected by row-level security policy for table "part_document" + SELECT * FROM part_document_satire ORDER by did; + ERROR: query would be affected by row-level security policy for table "part_document_satire" + -- Check behavior with a policy that uses a SubPlan not an InitPlan. + SET SESSION AUTHORIZATION regress_rls_alice; + SET row_security TO ON; + CREATE POLICY pp3 ON part_document AS RESTRICTIVE + USING ((SELECT dlevel <= seclv FROM uaccount WHERE pguser = current_user)); + SET SESSION AUTHORIZATION regress_rls_carol; + INSERT INTO part_document VALUES (100, 11, 5, 'regress_rls_carol', 'testing pp3'); -- fail + ERROR: new row violates row-level security policy "pp3" for table "part_document" ----- Dependencies ----- SET SESSION AUTHORIZATION regress_rls_alice; SET row_security TO ON;