Fix search_path to a safe value during maintenance operations.
While executing maintenance operations (ANALYZE, CLUSTER, REFRESH MATERIALIZED VIEW, REINDEX, or VACUUM), set search_path to 'pg_catalog, pg_temp' to prevent inconsistent behavior. Functions that are used for functional indexes, in index expressions, or in materialized views and depend on a different search path must be declared with CREATE FUNCTION ... SET search_path='...'. This change was previously committed as05e1737351
, then reverted in commit2fcc7ee7af
because it was too late in the cycle. Preparation for the MAINTAIN privilege, which was previously reverted due to search_path manipulation hazards. Discussion: https://postgr.es/m/d4ccaf3658cb3c281ec88c851a09733cd9482f22.camel@j-davis.com Discussion: https://postgr.es/m/E1q7j7Y-000z1H-Hr%40gemulon.postgresql.org Discussion: https://postgr.es/m/e44327179e5c9015c8dda67351c04da552066017.camel%40j-davis.com Reviewed-by: Greg Stark, Nathan Bossart, Noah Misch
This commit is contained in:
parent
2c29e7fc95
commit
2af07e2f74
|
@ -20,8 +20,11 @@ $node->safe_psql(
|
|||
'postgres', q(
|
||||
CREATE EXTENSION amcheck;
|
||||
|
||||
CREATE SCHEMA test_amcheck;
|
||||
SET search_path = test_amcheck;
|
||||
|
||||
CREATE FUNCTION ok_cmp (int4, int4)
|
||||
RETURNS int LANGUAGE sql AS
|
||||
RETURNS int LANGUAGE sql SET search_path = test_amcheck AS
|
||||
$$
|
||||
SELECT
|
||||
CASE WHEN $1 < $2 THEN -1
|
||||
|
@ -34,7 +37,7 @@ $node->safe_psql(
|
|||
--- Check 1: uniqueness violation.
|
||||
---
|
||||
CREATE FUNCTION ok_cmp1 (int4, int4)
|
||||
RETURNS int LANGUAGE sql AS
|
||||
RETURNS int LANGUAGE sql SET search_path = test_amcheck AS
|
||||
$$
|
||||
SELECT ok_cmp($1, $2);
|
||||
$$;
|
||||
|
@ -43,7 +46,7 @@ $node->safe_psql(
|
|||
--- Make values 768 and 769 look equal.
|
||||
---
|
||||
CREATE FUNCTION bad_cmp1 (int4, int4)
|
||||
RETURNS int LANGUAGE sql AS
|
||||
RETURNS int LANGUAGE sql SET search_path = test_amcheck AS
|
||||
$$
|
||||
SELECT
|
||||
CASE WHEN ($1 = 768 AND $2 = 769) OR
|
||||
|
@ -56,13 +59,13 @@ $node->safe_psql(
|
|||
--- Check 2: uniqueness violation without deduplication.
|
||||
---
|
||||
CREATE FUNCTION ok_cmp2 (int4, int4)
|
||||
RETURNS int LANGUAGE sql AS
|
||||
RETURNS int LANGUAGE sql SET search_path = test_amcheck AS
|
||||
$$
|
||||
SELECT ok_cmp($1, $2);
|
||||
$$;
|
||||
|
||||
CREATE FUNCTION bad_cmp2 (int4, int4)
|
||||
RETURNS int LANGUAGE sql AS
|
||||
RETURNS int LANGUAGE sql SET search_path = test_amcheck AS
|
||||
$$
|
||||
SELECT
|
||||
CASE WHEN $1 = $2 AND $1 = 400 THEN -1
|
||||
|
@ -74,13 +77,13 @@ $node->safe_psql(
|
|||
--- Check 3: uniqueness violation with deduplication.
|
||||
---
|
||||
CREATE FUNCTION ok_cmp3 (int4, int4)
|
||||
RETURNS int LANGUAGE sql AS
|
||||
RETURNS int LANGUAGE sql SET search_path = test_amcheck AS
|
||||
$$
|
||||
SELECT ok_cmp($1, $2);
|
||||
$$;
|
||||
|
||||
CREATE FUNCTION bad_cmp3 (int4, int4)
|
||||
RETURNS int LANGUAGE sql AS
|
||||
RETURNS int LANGUAGE sql SET search_path = test_amcheck AS
|
||||
$$
|
||||
SELECT bad_cmp2($1, $2);
|
||||
$$;
|
||||
|
@ -142,7 +145,7 @@ my ($result, $stdout, $stderr);
|
|||
# We have not yet broken the index, so we should get no corruption
|
||||
$result = $node->safe_psql(
|
||||
'postgres', q(
|
||||
SELECT bt_index_check('bttest_unique_idx1', true, true);
|
||||
SELECT bt_index_check('test_amcheck.bttest_unique_idx1', true, true);
|
||||
));
|
||||
is($result, '', 'run amcheck on non-broken bttest_unique_idx1');
|
||||
|
||||
|
@ -150,6 +153,7 @@ is($result, '', 'run amcheck on non-broken bttest_unique_idx1');
|
|||
# values to be equal.
|
||||
$node->safe_psql(
|
||||
'postgres', q(
|
||||
SET search_path = test_amcheck;
|
||||
UPDATE pg_catalog.pg_amproc SET
|
||||
amproc = 'bad_cmp1'::regproc
|
||||
WHERE amproc = 'ok_cmp1'::regproc;
|
||||
|
@ -157,7 +161,7 @@ $node->safe_psql(
|
|||
|
||||
($result, $stdout, $stderr) = $node->psql(
|
||||
'postgres', q(
|
||||
SELECT bt_index_check('bttest_unique_idx1', true, true);
|
||||
SELECT bt_index_check('test_amcheck.bttest_unique_idx1', true, true);
|
||||
));
|
||||
ok( $stderr =~ /index uniqueness is violated for index "bttest_unique_idx1"/,
|
||||
'detected uniqueness violation for index "bttest_unique_idx1"');
|
||||
|
@ -175,13 +179,14 @@ ok( $stderr =~ /index uniqueness is violated for index "bttest_unique_idx1"/,
|
|||
# but no uniqueness violation.
|
||||
($result, $stdout, $stderr) = $node->psql(
|
||||
'postgres', q(
|
||||
SELECT bt_index_check('bttest_unique_idx2', true, true);
|
||||
SELECT bt_index_check('test_amcheck.bttest_unique_idx2', true, true);
|
||||
));
|
||||
ok( $stderr =~ /item order invariant violated for index "bttest_unique_idx2"/,
|
||||
'detected item order invariant violation for index "bttest_unique_idx2"');
|
||||
|
||||
$node->safe_psql(
|
||||
'postgres', q(
|
||||
SET search_path = test_amcheck;
|
||||
UPDATE pg_catalog.pg_amproc SET
|
||||
amproc = 'ok_cmp2'::regproc
|
||||
WHERE amproc = 'bad_cmp2'::regproc;
|
||||
|
@ -189,7 +194,7 @@ $node->safe_psql(
|
|||
|
||||
($result, $stdout, $stderr) = $node->psql(
|
||||
'postgres', q(
|
||||
SELECT bt_index_check('bttest_unique_idx2', true, true);
|
||||
SELECT bt_index_check('test_amcheck.bttest_unique_idx2', true, true);
|
||||
));
|
||||
ok( $stderr =~ /index uniqueness is violated for index "bttest_unique_idx2"/,
|
||||
'detected uniqueness violation for index "bttest_unique_idx2"');
|
||||
|
@ -206,7 +211,7 @@ ok( $stderr =~ /index uniqueness is violated for index "bttest_unique_idx2"/,
|
|||
# but no uniqueness violation.
|
||||
($result, $stdout, $stderr) = $node->psql(
|
||||
'postgres', q(
|
||||
SELECT bt_index_check('bttest_unique_idx3', true, true);
|
||||
SELECT bt_index_check('test_amcheck.bttest_unique_idx3', true, true);
|
||||
));
|
||||
ok( $stderr =~ /item order invariant violated for index "bttest_unique_idx3"/,
|
||||
'detected item order invariant violation for index "bttest_unique_idx3"');
|
||||
|
@ -215,6 +220,7 @@ ok( $stderr =~ /item order invariant violated for index "bttest_unique_idx3"/,
|
|||
# with different visibility.
|
||||
$node->safe_psql(
|
||||
'postgres', q(
|
||||
SET search_path = test_amcheck;
|
||||
DELETE FROM bttest_unique3 WHERE 380 <= i AND i <= 420;
|
||||
INSERT INTO bttest_unique3 (SELECT * FROM generate_series(380, 420));
|
||||
INSERT INTO bttest_unique3 VALUES (400);
|
||||
|
@ -228,6 +234,7 @@ $node->safe_psql(
|
|||
|
||||
$node->safe_psql(
|
||||
'postgres', q(
|
||||
SET search_path = test_amcheck;
|
||||
UPDATE pg_catalog.pg_amproc SET
|
||||
amproc = 'ok_cmp3'::regproc
|
||||
WHERE amproc = 'bad_cmp3'::regproc;
|
||||
|
@ -235,7 +242,7 @@ $node->safe_psql(
|
|||
|
||||
($result, $stdout, $stderr) = $node->psql(
|
||||
'postgres', q(
|
||||
SELECT bt_index_check('bttest_unique_idx3', true, true);
|
||||
SELECT bt_index_check('test_amcheck.bttest_unique_idx3', true, true);
|
||||
));
|
||||
ok( $stderr =~ /index uniqueness is violated for index "bttest_unique_idx3"/,
|
||||
'detected uniqueness violation for index "bttest_unique_idx3"');
|
||||
|
|
|
@ -313,6 +313,8 @@ bt_index_check_internal(Oid indrelid, bool parentcheck, bool heapallindexed,
|
|||
SetUserIdAndSecContext(heaprel->rd_rel->relowner,
|
||||
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
||||
save_nestlevel = NewGUCNestLevel();
|
||||
SetConfigOption("search_path", GUC_SAFE_SEARCH_PATH, PGC_USERSET,
|
||||
PGC_S_SESSION);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -24,6 +24,9 @@
|
|||
to hold, we can expect binary searches on the affected page to
|
||||
incorrectly guide index scans, resulting in wrong answers to SQL
|
||||
queries. If the structure appears to be valid, no error is raised.
|
||||
While these checking functions are run, the <xref
|
||||
linkend="guc-search-path"/> is temporarily changed to <literal>pg_catalog,
|
||||
pg_temp</literal>.
|
||||
</para>
|
||||
<para>
|
||||
Verification is performed using the same procedures as those used by
|
||||
|
|
|
@ -95,7 +95,9 @@
|
|||
</para>
|
||||
|
||||
<para>
|
||||
Lastly, the following functions can be used:
|
||||
Lastly, the following functions can be used (while these functions run,
|
||||
<xref linkend="guc-search-path"/> is temporarily changed to
|
||||
<literal>pg_catalog, pg_temp</literal>):
|
||||
<simplelist>
|
||||
<member>
|
||||
<function>brin_summarize_new_values(regclass)</function>
|
||||
|
|
|
@ -205,6 +205,12 @@ ANALYZE [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] [ <r
|
|||
(This will not be sufficient if there is heavy update activity.)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
While <command>ANALYZE</command> is running, the <xref
|
||||
linkend="guc-search-path"/> is temporarily changed to <literal>pg_catalog,
|
||||
pg_temp</literal>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<command>ANALYZE</command>
|
||||
requires only a read lock on the target table, so it can run in
|
||||
|
|
|
@ -153,6 +153,12 @@ CLUSTER [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] [ <r
|
|||
information.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
While <command>CLUSTER</command> is running, the <xref
|
||||
linkend="guc-search-path"/> is temporarily changed to <literal>pg_catalog,
|
||||
pg_temp</literal>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
When an index scan is used, a temporary copy of the table is created that
|
||||
contains the table data in the index order. Temporary copies of each
|
||||
|
|
|
@ -789,6 +789,12 @@ Indexes:
|
|||
the table to generate statistics for these indexes.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
While <command>CREATE INDEX</command> is running, the <xref
|
||||
linkend="guc-search-path"/> is temporarily changed to <literal>pg_catalog,
|
||||
pg_temp</literal>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For most index methods, the speed of creating an index is
|
||||
dependent on the setting of <xref linkend="guc-maintenance-work-mem"/>.
|
||||
|
|
|
@ -98,6 +98,12 @@ REFRESH MATERIALIZED VIEW [ CONCURRENTLY ] <replaceable class="parameter">name</
|
|||
will be ordered that way; but <command>REFRESH MATERIALIZED
|
||||
VIEW</command> does not guarantee to preserve that ordering.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
While <command>REFRESH MATERIALIZED VIEW</command> is running, the <xref
|
||||
linkend="guc-search-path"/> is temporarily changed to <literal>pg_catalog,
|
||||
pg_temp</literal>.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
|
|
@ -291,6 +291,12 @@ REINDEX [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] { DA
|
|||
into expensive sequential scans.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
While <command>REINDEX</command> is running, the <xref
|
||||
linkend="guc-search-path"/> is temporarily changed to <literal>pg_catalog,
|
||||
pg_temp</literal>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Reindexing a single index or table requires being the owner of that
|
||||
index or table. Reindexing a schema or database requires being the
|
||||
|
|
|
@ -443,6 +443,12 @@ VACUUM [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] [ <re
|
|||
does not have permission to vacuum.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
While <command>VACUUM</command> is running, the <xref
|
||||
linkend="guc-search-path"/> is temporarily changed to <literal>pg_catalog,
|
||||
pg_temp</literal>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<command>VACUUM</command> cannot be executed inside a transaction block.
|
||||
</para>
|
||||
|
|
|
@ -1412,6 +1412,8 @@ brin_summarize_range(PG_FUNCTION_ARGS)
|
|||
SetUserIdAndSecContext(heapRel->rd_rel->relowner,
|
||||
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
||||
save_nestlevel = NewGUCNestLevel();
|
||||
SetConfigOption("search_path", GUC_SAFE_SEARCH_PATH, PGC_USERSET,
|
||||
PGC_S_SESSION);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1464,6 +1464,8 @@ index_concurrently_build(Oid heapRelationId,
|
|||
SetUserIdAndSecContext(heapRel->rd_rel->relowner,
|
||||
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
||||
save_nestlevel = NewGUCNestLevel();
|
||||
SetConfigOption("search_path", GUC_SAFE_SEARCH_PATH, PGC_USERSET,
|
||||
PGC_S_SESSION);
|
||||
|
||||
indexRelation = index_open(indexRelationId, RowExclusiveLock);
|
||||
|
||||
|
@ -3016,6 +3018,9 @@ index_build(Relation heapRelation,
|
|||
SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
|
||||
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
||||
save_nestlevel = NewGUCNestLevel();
|
||||
if (!IsBootstrapProcessingMode())
|
||||
SetConfigOption("search_path", GUC_SAFE_SEARCH_PATH, PGC_USERSET,
|
||||
PGC_S_SESSION);
|
||||
|
||||
/* Set up initial progress report status */
|
||||
{
|
||||
|
@ -3351,6 +3356,8 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
|
|||
SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
|
||||
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
||||
save_nestlevel = NewGUCNestLevel();
|
||||
SetConfigOption("search_path", GUC_SAFE_SEARCH_PATH, PGC_USERSET,
|
||||
PGC_S_SESSION);
|
||||
|
||||
indexRelation = index_open(indexId, RowExclusiveLock);
|
||||
|
||||
|
@ -3612,6 +3619,8 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
|
|||
SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
|
||||
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
||||
save_nestlevel = NewGUCNestLevel();
|
||||
SetConfigOption("search_path", GUC_SAFE_SEARCH_PATH, PGC_USERSET,
|
||||
PGC_S_SESSION);
|
||||
|
||||
if (progress)
|
||||
{
|
||||
|
|
|
@ -4697,6 +4697,9 @@ check_search_path(char **newval, void **extra, GucSource source)
|
|||
void
|
||||
assign_search_path(const char *newval, void *extra)
|
||||
{
|
||||
/* don't access search_path during bootstrap */
|
||||
Assert(!IsBootstrapProcessingMode());
|
||||
|
||||
/*
|
||||
* We mark the path as needing recomputation, but don't do anything until
|
||||
* it's needed. This avoids trying to do database access during GUC
|
||||
|
|
|
@ -339,6 +339,8 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
|
|||
SetUserIdAndSecContext(onerel->rd_rel->relowner,
|
||||
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
||||
save_nestlevel = NewGUCNestLevel();
|
||||
SetConfigOption("search_path", GUC_SAFE_SEARCH_PATH, PGC_USERSET,
|
||||
PGC_S_SESSION);
|
||||
|
||||
/* measure elapsed time iff autovacuum logging requires it */
|
||||
if (AmAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
|
||||
|
|
|
@ -350,6 +350,8 @@ cluster_rel(Oid tableOid, Oid indexOid, ClusterParams *params)
|
|||
SetUserIdAndSecContext(OldHeap->rd_rel->relowner,
|
||||
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
||||
save_nestlevel = NewGUCNestLevel();
|
||||
SetConfigOption("search_path", GUC_SAFE_SEARCH_PATH, PGC_USERSET,
|
||||
PGC_S_SESSION);
|
||||
|
||||
/*
|
||||
* Since we may open a new transaction for each relation, we have to check
|
||||
|
|
|
@ -585,6 +585,10 @@ DefineIndex(Oid tableId,
|
|||
|
||||
root_save_nestlevel = NewGUCNestLevel();
|
||||
|
||||
if (!IsBootstrapProcessingMode())
|
||||
SetConfigOption("search_path", GUC_SAFE_SEARCH_PATH, PGC_USERSET,
|
||||
PGC_S_SESSION);
|
||||
|
||||
/*
|
||||
* Some callers need us to run with an empty default_tablespace; this is a
|
||||
* necessary hack to be able to reproduce catalog state accurately when
|
||||
|
@ -1340,6 +1344,8 @@ DefineIndex(Oid tableId,
|
|||
SetUserIdAndSecContext(childrel->rd_rel->relowner,
|
||||
child_save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
||||
child_save_nestlevel = NewGUCNestLevel();
|
||||
SetConfigOption("search_path", GUC_SAFE_SEARCH_PATH, PGC_USERSET,
|
||||
PGC_S_SESSION);
|
||||
|
||||
/*
|
||||
* Don't try to create indexes on foreign tables, though. Skip
|
||||
|
@ -3881,6 +3887,8 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein
|
|||
SetUserIdAndSecContext(heapRel->rd_rel->relowner,
|
||||
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
||||
save_nestlevel = NewGUCNestLevel();
|
||||
SetConfigOption("search_path", GUC_SAFE_SEARCH_PATH, PGC_USERSET,
|
||||
PGC_S_SESSION);
|
||||
|
||||
/* determine safety of this index for set_indexsafe_procflags */
|
||||
idx->safe = (indexRel->rd_indexprs == NIL &&
|
||||
|
|
|
@ -173,6 +173,8 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
|
|||
SetUserIdAndSecContext(relowner,
|
||||
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
||||
save_nestlevel = NewGUCNestLevel();
|
||||
SetConfigOption("search_path", GUC_SAFE_SEARCH_PATH, PGC_USERSET,
|
||||
PGC_S_SESSION);
|
||||
|
||||
/* Make sure it is a materialized view. */
|
||||
if (matviewRel->rd_rel->relkind != RELKIND_MATVIEW)
|
||||
|
|
|
@ -2166,6 +2166,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params,
|
|||
SetUserIdAndSecContext(rel->rd_rel->relowner,
|
||||
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
||||
save_nestlevel = NewGUCNestLevel();
|
||||
SetConfigOption("search_path", GUC_SAFE_SEARCH_PATH, PGC_USERSET,
|
||||
PGC_S_SESSION);
|
||||
|
||||
/*
|
||||
* If PROCESS_MAIN is set (the default), it's time to vacuum the main
|
||||
|
|
|
@ -109,7 +109,6 @@ $node->safe_psql(
|
|||
CREATE FUNCTION f1(int) RETURNS int LANGUAGE SQL AS 'SELECT f0($1)';
|
||||
CREATE TABLE funcidx (x int);
|
||||
INSERT INTO funcidx VALUES (0),(1),(2),(3);
|
||||
CREATE INDEX i0 ON funcidx ((f1(x)));
|
||||
CREATE SCHEMA "Foo";
|
||||
CREATE TABLE "Foo".bar(id int);
|
||||
CREATE SCHEMA "Bar";
|
||||
|
@ -117,9 +116,6 @@ $node->safe_psql(
|
|||
|);
|
||||
$node->command_ok([qw|vacuumdb -Z --table="need""q(uot"(")x") postgres|],
|
||||
'column list');
|
||||
$node->command_fails(
|
||||
[qw|vacuumdb -Zt funcidx postgres|],
|
||||
'unqualified name via functional index');
|
||||
|
||||
$node->command_fails(
|
||||
[ 'vacuumdb', '--analyze', '--table', 'vactable(c)', 'postgres' ],
|
||||
|
|
|
@ -203,6 +203,12 @@ typedef enum
|
|||
|
||||
#define GUC_QUALIFIER_SEPARATOR '.'
|
||||
|
||||
/*
|
||||
* Safe search path when executing code as the table owner, such as during
|
||||
* maintenance operations.
|
||||
*/
|
||||
#define GUC_SAFE_SEARCH_PATH "pg_catalog, pg_temp"
|
||||
|
||||
/*
|
||||
* Bit values in "flags" of a GUC variable. Note that these don't appear
|
||||
* on disk, so we can reassign their values freely.
|
||||
|
|
|
@ -62,6 +62,8 @@ BEGIN
|
|||
END IF;
|
||||
END; $$;
|
||||
NOTICE: in process utility: superuser attempting CREATE FUNCTION
|
||||
NOTICE: in object access: superuser attempting namespace search (subId=0x0) [no report on violation, allowed]
|
||||
NOTICE: in object access: superuser finished namespace search (subId=0x0) [no report on violation, allowed]
|
||||
NOTICE: in object access: superuser attempting create (subId=0x0) [explicit]
|
||||
NOTICE: in object access: superuser finished create (subId=0x0) [explicit]
|
||||
NOTICE: in process utility: superuser finished CREATE FUNCTION
|
||||
|
|
|
@ -89,11 +89,15 @@ NOTICE: in object access: superuser finished create (subId=0x0) [internal]
|
|||
NOTICE: in process utility: superuser finished CREATE TABLE
|
||||
CREATE INDEX regress_test_table_t_idx ON regress_test_table (t);
|
||||
NOTICE: in process utility: superuser attempting CREATE INDEX
|
||||
NOTICE: in object access: superuser attempting namespace search (subId=0x0) [no report on violation, allowed]
|
||||
NOTICE: in object access: superuser finished namespace search (subId=0x0) [no report on violation, allowed]
|
||||
NOTICE: in object access: superuser attempting create (subId=0x0) [explicit]
|
||||
NOTICE: in object access: superuser finished create (subId=0x0) [explicit]
|
||||
NOTICE: in process utility: superuser finished CREATE INDEX
|
||||
GRANT SELECT ON Table regress_test_table TO public;
|
||||
NOTICE: in process utility: superuser attempting GRANT
|
||||
NOTICE: in object access: superuser attempting namespace search (subId=0x0) [no report on violation, allowed]
|
||||
NOTICE: in object access: superuser finished namespace search (subId=0x0) [no report on violation, allowed]
|
||||
NOTICE: in process utility: superuser finished GRANT
|
||||
CREATE FUNCTION regress_test_func (t text) RETURNS text AS $$
|
||||
SELECT $1;
|
||||
|
|
|
@ -574,10 +574,11 @@ DROP OWNED BY regress_user_mvtest CASCADE;
|
|||
DROP ROLE regress_user_mvtest;
|
||||
-- Concurrent refresh requires a unique index on the materialized
|
||||
-- view. Test what happens if it's dropped during the refresh.
|
||||
SET search_path = mvtest_mvschema, public;
|
||||
CREATE OR REPLACE FUNCTION mvtest_drop_the_index()
|
||||
RETURNS bool AS $$
|
||||
BEGIN
|
||||
EXECUTE 'DROP INDEX IF EXISTS mvtest_drop_idx';
|
||||
EXECUTE 'DROP INDEX IF EXISTS mvtest_mvschema.mvtest_drop_idx';
|
||||
RETURN true;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
@ -588,6 +589,7 @@ CREATE UNIQUE INDEX mvtest_drop_idx ON drop_idx_matview (i);
|
|||
REFRESH MATERIALIZED VIEW CONCURRENTLY drop_idx_matview;
|
||||
ERROR: could not find suitable unique index on materialized view
|
||||
DROP MATERIALIZED VIEW drop_idx_matview; -- clean up
|
||||
RESET search_path;
|
||||
-- make sure that create WITH NO DATA works via SPI
|
||||
BEGIN;
|
||||
CREATE FUNCTION mvtest_func()
|
||||
|
|
|
@ -114,3 +114,47 @@ SELECT COUNT(*) FROM pg_class WHERE relnamespace =
|
|||
0
|
||||
(1 row)
|
||||
|
||||
--
|
||||
-- Verify that search_path is set to a safe value during maintenance
|
||||
-- commands.
|
||||
--
|
||||
CREATE SCHEMA test_maint_search_path;
|
||||
SET search_path = test_maint_search_path;
|
||||
CREATE FUNCTION fn(INT) RETURNS INT IMMUTABLE LANGUAGE plpgsql AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'current search_path: %', current_setting('search_path');
|
||||
RETURN $1;
|
||||
END;
|
||||
$$;
|
||||
CREATE TABLE test_maint(i INT);
|
||||
INSERT INTO test_maint VALUES (1), (2);
|
||||
CREATE MATERIALIZED VIEW test_maint_mv AS SELECT fn(i) FROM test_maint;
|
||||
NOTICE: current search_path: test_maint_search_path
|
||||
NOTICE: current search_path: test_maint_search_path
|
||||
-- the following commands should see search_path as pg_catalog, pg_temp
|
||||
CREATE INDEX test_maint_idx ON test_maint_search_path.test_maint (fn(i));
|
||||
NOTICE: current search_path: pg_catalog, pg_temp
|
||||
NOTICE: current search_path: pg_catalog, pg_temp
|
||||
REINDEX TABLE test_maint_search_path.test_maint;
|
||||
NOTICE: current search_path: pg_catalog, pg_temp
|
||||
NOTICE: current search_path: pg_catalog, pg_temp
|
||||
ANALYZE test_maint_search_path.test_maint;
|
||||
NOTICE: current search_path: pg_catalog, pg_temp
|
||||
NOTICE: current search_path: pg_catalog, pg_temp
|
||||
VACUUM FULL test_maint_search_path.test_maint;
|
||||
NOTICE: current search_path: pg_catalog, pg_temp
|
||||
NOTICE: current search_path: pg_catalog, pg_temp
|
||||
CLUSTER test_maint_search_path.test_maint USING test_maint_idx;
|
||||
NOTICE: current search_path: pg_catalog, pg_temp
|
||||
NOTICE: current search_path: pg_catalog, pg_temp
|
||||
NOTICE: current search_path: pg_catalog, pg_temp
|
||||
NOTICE: current search_path: pg_catalog, pg_temp
|
||||
REFRESH MATERIALIZED VIEW test_maint_search_path.test_maint_mv;
|
||||
NOTICE: current search_path: pg_catalog, pg_temp
|
||||
NOTICE: current search_path: pg_catalog, pg_temp
|
||||
RESET search_path;
|
||||
DROP SCHEMA test_maint_search_path CASCADE;
|
||||
NOTICE: drop cascades to 3 other objects
|
||||
DETAIL: drop cascades to function test_maint_search_path.fn(integer)
|
||||
drop cascades to table test_maint_search_path.test_maint
|
||||
drop cascades to materialized view test_maint_search_path.test_maint_mv
|
||||
|
|
|
@ -1769,7 +1769,7 @@ SET SESSION AUTHORIZATION regress_sro_user;
|
|||
CREATE FUNCTION unwanted_grant() RETURNS void LANGUAGE sql AS
|
||||
'GRANT regress_priv_group2 TO regress_sro_user';
|
||||
CREATE FUNCTION mv_action() RETURNS bool LANGUAGE sql AS
|
||||
'DECLARE c CURSOR WITH HOLD FOR SELECT unwanted_grant(); SELECT true';
|
||||
'DECLARE c CURSOR WITH HOLD FOR SELECT public.unwanted_grant(); SELECT true';
|
||||
-- REFRESH of this MV will queue a GRANT at end of transaction
|
||||
CREATE MATERIALIZED VIEW sro_mv AS SELECT mv_action() WITH NO DATA;
|
||||
REFRESH MATERIALIZED VIEW sro_mv;
|
||||
|
@ -1783,12 +1783,12 @@ SET SESSION AUTHORIZATION regress_sro_user;
|
|||
-- INSERT to this table will queue a GRANT at end of transaction
|
||||
CREATE TABLE sro_trojan_table ();
|
||||
CREATE FUNCTION sro_trojan() RETURNS trigger LANGUAGE plpgsql AS
|
||||
'BEGIN PERFORM unwanted_grant(); RETURN NULL; END';
|
||||
'BEGIN PERFORM public.unwanted_grant(); RETURN NULL; END';
|
||||
CREATE CONSTRAINT TRIGGER t AFTER INSERT ON sro_trojan_table
|
||||
INITIALLY DEFERRED FOR EACH ROW EXECUTE PROCEDURE sro_trojan();
|
||||
-- Now, REFRESH will issue such an INSERT, queueing the GRANT
|
||||
CREATE OR REPLACE FUNCTION mv_action() RETURNS bool LANGUAGE sql AS
|
||||
'INSERT INTO sro_trojan_table DEFAULT VALUES; SELECT true';
|
||||
'INSERT INTO public.sro_trojan_table DEFAULT VALUES; SELECT true';
|
||||
REFRESH MATERIALIZED VIEW sro_mv;
|
||||
ERROR: cannot fire deferred trigger within security-restricted operation
|
||||
CONTEXT: SQL function "mv_action" statement 1
|
||||
|
@ -1800,15 +1800,15 @@ BEGIN; SET CONSTRAINTS ALL IMMEDIATE; REFRESH MATERIALIZED VIEW sro_mv; COMMIT;
|
|||
ERROR: permission denied to grant role "regress_priv_group2"
|
||||
DETAIL: Only roles with the ADMIN option on role "regress_priv_group2" may grant this role.
|
||||
CONTEXT: SQL function "unwanted_grant" statement 1
|
||||
SQL statement "SELECT unwanted_grant()"
|
||||
PL/pgSQL function sro_trojan() line 1 at PERFORM
|
||||
SQL statement "SELECT public.unwanted_grant()"
|
||||
PL/pgSQL function public.sro_trojan() line 1 at PERFORM
|
||||
SQL function "mv_action" statement 1
|
||||
-- REFRESH MATERIALIZED VIEW CONCURRENTLY use of eval_const_expressions()
|
||||
SET SESSION AUTHORIZATION regress_sro_user;
|
||||
CREATE FUNCTION unwanted_grant_nofail(int) RETURNS int
|
||||
IMMUTABLE LANGUAGE plpgsql AS $$
|
||||
BEGIN
|
||||
PERFORM unwanted_grant();
|
||||
PERFORM public.unwanted_grant();
|
||||
RAISE WARNING 'owned';
|
||||
RETURN 1;
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
|
|
|
@ -64,7 +64,7 @@ CLUSTER vaccluster;
|
|||
CREATE FUNCTION do_analyze() RETURNS VOID VOLATILE LANGUAGE SQL
|
||||
AS 'ANALYZE pg_am';
|
||||
CREATE FUNCTION wrap_do_analyze(c INT) RETURNS INT IMMUTABLE LANGUAGE SQL
|
||||
AS 'SELECT $1 FROM do_analyze()';
|
||||
AS 'SELECT $1 FROM public.do_analyze()';
|
||||
CREATE INDEX ON vaccluster(wrap_do_analyze(i));
|
||||
INSERT INTO vaccluster VALUES (1), (2);
|
||||
ANALYZE vaccluster;
|
||||
|
|
|
@ -233,10 +233,11 @@ DROP ROLE regress_user_mvtest;
|
|||
|
||||
-- Concurrent refresh requires a unique index on the materialized
|
||||
-- view. Test what happens if it's dropped during the refresh.
|
||||
SET search_path = mvtest_mvschema, public;
|
||||
CREATE OR REPLACE FUNCTION mvtest_drop_the_index()
|
||||
RETURNS bool AS $$
|
||||
BEGIN
|
||||
EXECUTE 'DROP INDEX IF EXISTS mvtest_drop_idx';
|
||||
EXECUTE 'DROP INDEX IF EXISTS mvtest_mvschema.mvtest_drop_idx';
|
||||
RETURN true;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
@ -247,6 +248,7 @@ CREATE MATERIALIZED VIEW drop_idx_matview AS
|
|||
CREATE UNIQUE INDEX mvtest_drop_idx ON drop_idx_matview (i);
|
||||
REFRESH MATERIALIZED VIEW CONCURRENTLY drop_idx_matview;
|
||||
DROP MATERIALIZED VIEW drop_idx_matview; -- clean up
|
||||
RESET search_path;
|
||||
|
||||
-- make sure that create WITH NO DATA works via SPI
|
||||
BEGIN;
|
||||
|
|
|
@ -66,3 +66,35 @@ DROP SCHEMA test_ns_schema_renamed CASCADE;
|
|||
-- verify that the objects were dropped
|
||||
SELECT COUNT(*) FROM pg_class WHERE relnamespace =
|
||||
(SELECT oid FROM pg_namespace WHERE nspname = 'test_ns_schema_renamed');
|
||||
|
||||
--
|
||||
-- Verify that search_path is set to a safe value during maintenance
|
||||
-- commands.
|
||||
--
|
||||
|
||||
CREATE SCHEMA test_maint_search_path;
|
||||
SET search_path = test_maint_search_path;
|
||||
|
||||
CREATE FUNCTION fn(INT) RETURNS INT IMMUTABLE LANGUAGE plpgsql AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'current search_path: %', current_setting('search_path');
|
||||
RETURN $1;
|
||||
END;
|
||||
$$;
|
||||
|
||||
CREATE TABLE test_maint(i INT);
|
||||
INSERT INTO test_maint VALUES (1), (2);
|
||||
CREATE MATERIALIZED VIEW test_maint_mv AS SELECT fn(i) FROM test_maint;
|
||||
|
||||
-- the following commands should see search_path as pg_catalog, pg_temp
|
||||
|
||||
CREATE INDEX test_maint_idx ON test_maint_search_path.test_maint (fn(i));
|
||||
REINDEX TABLE test_maint_search_path.test_maint;
|
||||
ANALYZE test_maint_search_path.test_maint;
|
||||
VACUUM FULL test_maint_search_path.test_maint;
|
||||
CLUSTER test_maint_search_path.test_maint USING test_maint_idx;
|
||||
REFRESH MATERIALIZED VIEW test_maint_search_path.test_maint_mv;
|
||||
|
||||
RESET search_path;
|
||||
|
||||
DROP SCHEMA test_maint_search_path CASCADE;
|
||||
|
|
|
@ -1177,7 +1177,7 @@ SET SESSION AUTHORIZATION regress_sro_user;
|
|||
CREATE FUNCTION unwanted_grant() RETURNS void LANGUAGE sql AS
|
||||
'GRANT regress_priv_group2 TO regress_sro_user';
|
||||
CREATE FUNCTION mv_action() RETURNS bool LANGUAGE sql AS
|
||||
'DECLARE c CURSOR WITH HOLD FOR SELECT unwanted_grant(); SELECT true';
|
||||
'DECLARE c CURSOR WITH HOLD FOR SELECT public.unwanted_grant(); SELECT true';
|
||||
-- REFRESH of this MV will queue a GRANT at end of transaction
|
||||
CREATE MATERIALIZED VIEW sro_mv AS SELECT mv_action() WITH NO DATA;
|
||||
REFRESH MATERIALIZED VIEW sro_mv;
|
||||
|
@ -1188,12 +1188,12 @@ SET SESSION AUTHORIZATION regress_sro_user;
|
|||
-- INSERT to this table will queue a GRANT at end of transaction
|
||||
CREATE TABLE sro_trojan_table ();
|
||||
CREATE FUNCTION sro_trojan() RETURNS trigger LANGUAGE plpgsql AS
|
||||
'BEGIN PERFORM unwanted_grant(); RETURN NULL; END';
|
||||
'BEGIN PERFORM public.unwanted_grant(); RETURN NULL; END';
|
||||
CREATE CONSTRAINT TRIGGER t AFTER INSERT ON sro_trojan_table
|
||||
INITIALLY DEFERRED FOR EACH ROW EXECUTE PROCEDURE sro_trojan();
|
||||
-- Now, REFRESH will issue such an INSERT, queueing the GRANT
|
||||
CREATE OR REPLACE FUNCTION mv_action() RETURNS bool LANGUAGE sql AS
|
||||
'INSERT INTO sro_trojan_table DEFAULT VALUES; SELECT true';
|
||||
'INSERT INTO public.sro_trojan_table DEFAULT VALUES; SELECT true';
|
||||
REFRESH MATERIALIZED VIEW sro_mv;
|
||||
\c -
|
||||
REFRESH MATERIALIZED VIEW sro_mv;
|
||||
|
@ -1204,7 +1204,7 @@ SET SESSION AUTHORIZATION regress_sro_user;
|
|||
CREATE FUNCTION unwanted_grant_nofail(int) RETURNS int
|
||||
IMMUTABLE LANGUAGE plpgsql AS $$
|
||||
BEGIN
|
||||
PERFORM unwanted_grant();
|
||||
PERFORM public.unwanted_grant();
|
||||
RAISE WARNING 'owned';
|
||||
RETURN 1;
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
|
|
|
@ -49,7 +49,7 @@ CLUSTER vaccluster;
|
|||
CREATE FUNCTION do_analyze() RETURNS VOID VOLATILE LANGUAGE SQL
|
||||
AS 'ANALYZE pg_am';
|
||||
CREATE FUNCTION wrap_do_analyze(c INT) RETURNS INT IMMUTABLE LANGUAGE SQL
|
||||
AS 'SELECT $1 FROM do_analyze()';
|
||||
AS 'SELECT $1 FROM public.do_analyze()';
|
||||
CREATE INDEX ON vaccluster(wrap_do_analyze(i));
|
||||
INSERT INTO vaccluster VALUES (1), (2);
|
||||
ANALYZE vaccluster;
|
||||
|
|
Loading…
Reference in New Issue