mirror of
https://github.com/postgres/postgres.git
synced 2025-06-05 23:56:58 +03:00
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 as 05e1737351, then reverted in commit 2fcc7ee7af 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(
|
'postgres', q(
|
||||||
CREATE EXTENSION amcheck;
|
CREATE EXTENSION amcheck;
|
||||||
|
|
||||||
|
CREATE SCHEMA test_amcheck;
|
||||||
|
SET search_path = test_amcheck;
|
||||||
|
|
||||||
CREATE FUNCTION ok_cmp (int4, int4)
|
CREATE FUNCTION ok_cmp (int4, int4)
|
||||||
RETURNS int LANGUAGE sql AS
|
RETURNS int LANGUAGE sql SET search_path = test_amcheck AS
|
||||||
$$
|
$$
|
||||||
SELECT
|
SELECT
|
||||||
CASE WHEN $1 < $2 THEN -1
|
CASE WHEN $1 < $2 THEN -1
|
||||||
@ -34,7 +37,7 @@ $node->safe_psql(
|
|||||||
--- Check 1: uniqueness violation.
|
--- Check 1: uniqueness violation.
|
||||||
---
|
---
|
||||||
CREATE FUNCTION ok_cmp1 (int4, int4)
|
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);
|
SELECT ok_cmp($1, $2);
|
||||||
$$;
|
$$;
|
||||||
@ -43,7 +46,7 @@ $node->safe_psql(
|
|||||||
--- Make values 768 and 769 look equal.
|
--- Make values 768 and 769 look equal.
|
||||||
---
|
---
|
||||||
CREATE FUNCTION bad_cmp1 (int4, int4)
|
CREATE FUNCTION bad_cmp1 (int4, int4)
|
||||||
RETURNS int LANGUAGE sql AS
|
RETURNS int LANGUAGE sql SET search_path = test_amcheck AS
|
||||||
$$
|
$$
|
||||||
SELECT
|
SELECT
|
||||||
CASE WHEN ($1 = 768 AND $2 = 769) OR
|
CASE WHEN ($1 = 768 AND $2 = 769) OR
|
||||||
@ -56,13 +59,13 @@ $node->safe_psql(
|
|||||||
--- Check 2: uniqueness violation without deduplication.
|
--- Check 2: uniqueness violation without deduplication.
|
||||||
---
|
---
|
||||||
CREATE FUNCTION ok_cmp2 (int4, int4)
|
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);
|
SELECT ok_cmp($1, $2);
|
||||||
$$;
|
$$;
|
||||||
|
|
||||||
CREATE FUNCTION bad_cmp2 (int4, int4)
|
CREATE FUNCTION bad_cmp2 (int4, int4)
|
||||||
RETURNS int LANGUAGE sql AS
|
RETURNS int LANGUAGE sql SET search_path = test_amcheck AS
|
||||||
$$
|
$$
|
||||||
SELECT
|
SELECT
|
||||||
CASE WHEN $1 = $2 AND $1 = 400 THEN -1
|
CASE WHEN $1 = $2 AND $1 = 400 THEN -1
|
||||||
@ -74,13 +77,13 @@ $node->safe_psql(
|
|||||||
--- Check 3: uniqueness violation with deduplication.
|
--- Check 3: uniqueness violation with deduplication.
|
||||||
---
|
---
|
||||||
CREATE FUNCTION ok_cmp3 (int4, int4)
|
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);
|
SELECT ok_cmp($1, $2);
|
||||||
$$;
|
$$;
|
||||||
|
|
||||||
CREATE FUNCTION bad_cmp3 (int4, int4)
|
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);
|
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
|
# We have not yet broken the index, so we should get no corruption
|
||||||
$result = $node->safe_psql(
|
$result = $node->safe_psql(
|
||||||
'postgres', q(
|
'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');
|
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.
|
# values to be equal.
|
||||||
$node->safe_psql(
|
$node->safe_psql(
|
||||||
'postgres', q(
|
'postgres', q(
|
||||||
|
SET search_path = test_amcheck;
|
||||||
UPDATE pg_catalog.pg_amproc SET
|
UPDATE pg_catalog.pg_amproc SET
|
||||||
amproc = 'bad_cmp1'::regproc
|
amproc = 'bad_cmp1'::regproc
|
||||||
WHERE amproc = 'ok_cmp1'::regproc;
|
WHERE amproc = 'ok_cmp1'::regproc;
|
||||||
@ -157,7 +161,7 @@ $node->safe_psql(
|
|||||||
|
|
||||||
($result, $stdout, $stderr) = $node->psql(
|
($result, $stdout, $stderr) = $node->psql(
|
||||||
'postgres', q(
|
'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"/,
|
ok( $stderr =~ /index uniqueness is violated for index "bttest_unique_idx1"/,
|
||||||
'detected uniqueness violation 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.
|
# but no uniqueness violation.
|
||||||
($result, $stdout, $stderr) = $node->psql(
|
($result, $stdout, $stderr) = $node->psql(
|
||||||
'postgres', q(
|
'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"/,
|
ok( $stderr =~ /item order invariant violated for index "bttest_unique_idx2"/,
|
||||||
'detected item order invariant violation for index "bttest_unique_idx2"');
|
'detected item order invariant violation for index "bttest_unique_idx2"');
|
||||||
|
|
||||||
$node->safe_psql(
|
$node->safe_psql(
|
||||||
'postgres', q(
|
'postgres', q(
|
||||||
|
SET search_path = test_amcheck;
|
||||||
UPDATE pg_catalog.pg_amproc SET
|
UPDATE pg_catalog.pg_amproc SET
|
||||||
amproc = 'ok_cmp2'::regproc
|
amproc = 'ok_cmp2'::regproc
|
||||||
WHERE amproc = 'bad_cmp2'::regproc;
|
WHERE amproc = 'bad_cmp2'::regproc;
|
||||||
@ -189,7 +194,7 @@ $node->safe_psql(
|
|||||||
|
|
||||||
($result, $stdout, $stderr) = $node->psql(
|
($result, $stdout, $stderr) = $node->psql(
|
||||||
'postgres', q(
|
'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"/,
|
ok( $stderr =~ /index uniqueness is violated for index "bttest_unique_idx2"/,
|
||||||
'detected uniqueness violation 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.
|
# but no uniqueness violation.
|
||||||
($result, $stdout, $stderr) = $node->psql(
|
($result, $stdout, $stderr) = $node->psql(
|
||||||
'postgres', q(
|
'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"/,
|
ok( $stderr =~ /item order invariant violated for index "bttest_unique_idx3"/,
|
||||||
'detected item order invariant violation 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.
|
# with different visibility.
|
||||||
$node->safe_psql(
|
$node->safe_psql(
|
||||||
'postgres', q(
|
'postgres', q(
|
||||||
|
SET search_path = test_amcheck;
|
||||||
DELETE FROM bttest_unique3 WHERE 380 <= i AND i <= 420;
|
DELETE FROM bttest_unique3 WHERE 380 <= i AND i <= 420;
|
||||||
INSERT INTO bttest_unique3 (SELECT * FROM generate_series(380, 420));
|
INSERT INTO bttest_unique3 (SELECT * FROM generate_series(380, 420));
|
||||||
INSERT INTO bttest_unique3 VALUES (400);
|
INSERT INTO bttest_unique3 VALUES (400);
|
||||||
@ -228,6 +234,7 @@ $node->safe_psql(
|
|||||||
|
|
||||||
$node->safe_psql(
|
$node->safe_psql(
|
||||||
'postgres', q(
|
'postgres', q(
|
||||||
|
SET search_path = test_amcheck;
|
||||||
UPDATE pg_catalog.pg_amproc SET
|
UPDATE pg_catalog.pg_amproc SET
|
||||||
amproc = 'ok_cmp3'::regproc
|
amproc = 'ok_cmp3'::regproc
|
||||||
WHERE amproc = 'bad_cmp3'::regproc;
|
WHERE amproc = 'bad_cmp3'::regproc;
|
||||||
@ -235,7 +242,7 @@ $node->safe_psql(
|
|||||||
|
|
||||||
($result, $stdout, $stderr) = $node->psql(
|
($result, $stdout, $stderr) = $node->psql(
|
||||||
'postgres', q(
|
'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"/,
|
ok( $stderr =~ /index uniqueness is violated for index "bttest_unique_idx3"/,
|
||||||
'detected uniqueness violation 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,
|
SetUserIdAndSecContext(heaprel->rd_rel->relowner,
|
||||||
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
||||||
save_nestlevel = NewGUCNestLevel();
|
save_nestlevel = NewGUCNestLevel();
|
||||||
|
SetConfigOption("search_path", GUC_SAFE_SEARCH_PATH, PGC_USERSET,
|
||||||
|
PGC_S_SESSION);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -24,6 +24,9 @@
|
|||||||
to hold, we can expect binary searches on the affected page to
|
to hold, we can expect binary searches on the affected page to
|
||||||
incorrectly guide index scans, resulting in wrong answers to SQL
|
incorrectly guide index scans, resulting in wrong answers to SQL
|
||||||
queries. If the structure appears to be valid, no error is raised.
|
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>
|
||||||
<para>
|
<para>
|
||||||
Verification is performed using the same procedures as those used by
|
Verification is performed using the same procedures as those used by
|
||||||
|
@ -95,7 +95,9 @@
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<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>
|
<simplelist>
|
||||||
<member>
|
<member>
|
||||||
<function>brin_summarize_new_values(regclass)</function>
|
<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.)
|
(This will not be sufficient if there is heavy update activity.)
|
||||||
</para>
|
</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>
|
<para>
|
||||||
<command>ANALYZE</command>
|
<command>ANALYZE</command>
|
||||||
requires only a read lock on the target table, so it can run in
|
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.
|
information.
|
||||||
</para>
|
</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>
|
<para>
|
||||||
When an index scan is used, a temporary copy of the table is created that
|
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
|
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.
|
the table to generate statistics for these indexes.
|
||||||
</para>
|
</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>
|
<para>
|
||||||
For most index methods, the speed of creating an index is
|
For most index methods, the speed of creating an index is
|
||||||
dependent on the setting of <xref linkend="guc-maintenance-work-mem"/>.
|
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
|
will be ordered that way; but <command>REFRESH MATERIALIZED
|
||||||
VIEW</command> does not guarantee to preserve that ordering.
|
VIEW</command> does not guarantee to preserve that ordering.
|
||||||
</para>
|
</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>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
|
@ -291,6 +291,12 @@ REINDEX [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] { DA
|
|||||||
into expensive sequential scans.
|
into expensive sequential scans.
|
||||||
</para>
|
</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>
|
<para>
|
||||||
Reindexing a single index or table requires being the owner of that
|
Reindexing a single index or table requires being the owner of that
|
||||||
index or table. Reindexing a schema or database requires being the
|
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.
|
does not have permission to vacuum.
|
||||||
</para>
|
</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>
|
<para>
|
||||||
<command>VACUUM</command> cannot be executed inside a transaction block.
|
<command>VACUUM</command> cannot be executed inside a transaction block.
|
||||||
</para>
|
</para>
|
||||||
|
@ -1412,6 +1412,8 @@ brin_summarize_range(PG_FUNCTION_ARGS)
|
|||||||
SetUserIdAndSecContext(heapRel->rd_rel->relowner,
|
SetUserIdAndSecContext(heapRel->rd_rel->relowner,
|
||||||
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
||||||
save_nestlevel = NewGUCNestLevel();
|
save_nestlevel = NewGUCNestLevel();
|
||||||
|
SetConfigOption("search_path", GUC_SAFE_SEARCH_PATH, PGC_USERSET,
|
||||||
|
PGC_S_SESSION);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1464,6 +1464,8 @@ index_concurrently_build(Oid heapRelationId,
|
|||||||
SetUserIdAndSecContext(heapRel->rd_rel->relowner,
|
SetUserIdAndSecContext(heapRel->rd_rel->relowner,
|
||||||
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
||||||
save_nestlevel = NewGUCNestLevel();
|
save_nestlevel = NewGUCNestLevel();
|
||||||
|
SetConfigOption("search_path", GUC_SAFE_SEARCH_PATH, PGC_USERSET,
|
||||||
|
PGC_S_SESSION);
|
||||||
|
|
||||||
indexRelation = index_open(indexRelationId, RowExclusiveLock);
|
indexRelation = index_open(indexRelationId, RowExclusiveLock);
|
||||||
|
|
||||||
@ -3016,6 +3018,9 @@ index_build(Relation heapRelation,
|
|||||||
SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
|
SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
|
||||||
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
||||||
save_nestlevel = NewGUCNestLevel();
|
save_nestlevel = NewGUCNestLevel();
|
||||||
|
if (!IsBootstrapProcessingMode())
|
||||||
|
SetConfigOption("search_path", GUC_SAFE_SEARCH_PATH, PGC_USERSET,
|
||||||
|
PGC_S_SESSION);
|
||||||
|
|
||||||
/* Set up initial progress report status */
|
/* Set up initial progress report status */
|
||||||
{
|
{
|
||||||
@ -3351,6 +3356,8 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
|
|||||||
SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
|
SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
|
||||||
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
||||||
save_nestlevel = NewGUCNestLevel();
|
save_nestlevel = NewGUCNestLevel();
|
||||||
|
SetConfigOption("search_path", GUC_SAFE_SEARCH_PATH, PGC_USERSET,
|
||||||
|
PGC_S_SESSION);
|
||||||
|
|
||||||
indexRelation = index_open(indexId, RowExclusiveLock);
|
indexRelation = index_open(indexId, RowExclusiveLock);
|
||||||
|
|
||||||
@ -3612,6 +3619,8 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
|
|||||||
SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
|
SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
|
||||||
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
||||||
save_nestlevel = NewGUCNestLevel();
|
save_nestlevel = NewGUCNestLevel();
|
||||||
|
SetConfigOption("search_path", GUC_SAFE_SEARCH_PATH, PGC_USERSET,
|
||||||
|
PGC_S_SESSION);
|
||||||
|
|
||||||
if (progress)
|
if (progress)
|
||||||
{
|
{
|
||||||
|
@ -4697,6 +4697,9 @@ check_search_path(char **newval, void **extra, GucSource source)
|
|||||||
void
|
void
|
||||||
assign_search_path(const char *newval, void *extra)
|
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
|
* 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
|
* 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,
|
SetUserIdAndSecContext(onerel->rd_rel->relowner,
|
||||||
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
||||||
save_nestlevel = NewGUCNestLevel();
|
save_nestlevel = NewGUCNestLevel();
|
||||||
|
SetConfigOption("search_path", GUC_SAFE_SEARCH_PATH, PGC_USERSET,
|
||||||
|
PGC_S_SESSION);
|
||||||
|
|
||||||
/* measure elapsed time iff autovacuum logging requires it */
|
/* measure elapsed time iff autovacuum logging requires it */
|
||||||
if (AmAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
|
if (AmAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
|
||||||
|
@ -350,6 +350,8 @@ cluster_rel(Oid tableOid, Oid indexOid, ClusterParams *params)
|
|||||||
SetUserIdAndSecContext(OldHeap->rd_rel->relowner,
|
SetUserIdAndSecContext(OldHeap->rd_rel->relowner,
|
||||||
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
||||||
save_nestlevel = NewGUCNestLevel();
|
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
|
* 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();
|
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
|
* 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
|
* necessary hack to be able to reproduce catalog state accurately when
|
||||||
@ -1340,6 +1344,8 @@ DefineIndex(Oid tableId,
|
|||||||
SetUserIdAndSecContext(childrel->rd_rel->relowner,
|
SetUserIdAndSecContext(childrel->rd_rel->relowner,
|
||||||
child_save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
child_save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
||||||
child_save_nestlevel = NewGUCNestLevel();
|
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
|
* 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,
|
SetUserIdAndSecContext(heapRel->rd_rel->relowner,
|
||||||
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
||||||
save_nestlevel = NewGUCNestLevel();
|
save_nestlevel = NewGUCNestLevel();
|
||||||
|
SetConfigOption("search_path", GUC_SAFE_SEARCH_PATH, PGC_USERSET,
|
||||||
|
PGC_S_SESSION);
|
||||||
|
|
||||||
/* determine safety of this index for set_indexsafe_procflags */
|
/* determine safety of this index for set_indexsafe_procflags */
|
||||||
idx->safe = (indexRel->rd_indexprs == NIL &&
|
idx->safe = (indexRel->rd_indexprs == NIL &&
|
||||||
|
@ -173,6 +173,8 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
|
|||||||
SetUserIdAndSecContext(relowner,
|
SetUserIdAndSecContext(relowner,
|
||||||
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
||||||
save_nestlevel = NewGUCNestLevel();
|
save_nestlevel = NewGUCNestLevel();
|
||||||
|
SetConfigOption("search_path", GUC_SAFE_SEARCH_PATH, PGC_USERSET,
|
||||||
|
PGC_S_SESSION);
|
||||||
|
|
||||||
/* Make sure it is a materialized view. */
|
/* Make sure it is a materialized view. */
|
||||||
if (matviewRel->rd_rel->relkind != RELKIND_MATVIEW)
|
if (matviewRel->rd_rel->relkind != RELKIND_MATVIEW)
|
||||||
|
@ -2166,6 +2166,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params,
|
|||||||
SetUserIdAndSecContext(rel->rd_rel->relowner,
|
SetUserIdAndSecContext(rel->rd_rel->relowner,
|
||||||
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
save_sec_context | SECURITY_RESTRICTED_OPERATION);
|
||||||
save_nestlevel = NewGUCNestLevel();
|
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
|
* 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 FUNCTION f1(int) RETURNS int LANGUAGE SQL AS 'SELECT f0($1)';
|
||||||
CREATE TABLE funcidx (x int);
|
CREATE TABLE funcidx (x int);
|
||||||
INSERT INTO funcidx VALUES (0),(1),(2),(3);
|
INSERT INTO funcidx VALUES (0),(1),(2),(3);
|
||||||
CREATE INDEX i0 ON funcidx ((f1(x)));
|
|
||||||
CREATE SCHEMA "Foo";
|
CREATE SCHEMA "Foo";
|
||||||
CREATE TABLE "Foo".bar(id int);
|
CREATE TABLE "Foo".bar(id int);
|
||||||
CREATE SCHEMA "Bar";
|
CREATE SCHEMA "Bar";
|
||||||
@ -117,9 +116,6 @@ $node->safe_psql(
|
|||||||
|);
|
|);
|
||||||
$node->command_ok([qw|vacuumdb -Z --table="need""q(uot"(")x") postgres|],
|
$node->command_ok([qw|vacuumdb -Z --table="need""q(uot"(")x") postgres|],
|
||||||
'column list');
|
'column list');
|
||||||
$node->command_fails(
|
|
||||||
[qw|vacuumdb -Zt funcidx postgres|],
|
|
||||||
'unqualified name via functional index');
|
|
||||||
|
|
||||||
$node->command_fails(
|
$node->command_fails(
|
||||||
[ 'vacuumdb', '--analyze', '--table', 'vactable(c)', 'postgres' ],
|
[ 'vacuumdb', '--analyze', '--table', 'vactable(c)', 'postgres' ],
|
||||||
|
@ -203,6 +203,12 @@ typedef enum
|
|||||||
|
|
||||||
#define GUC_QUALIFIER_SEPARATOR '.'
|
#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
|
* Bit values in "flags" of a GUC variable. Note that these don't appear
|
||||||
* on disk, so we can reassign their values freely.
|
* on disk, so we can reassign their values freely.
|
||||||
|
@ -62,6 +62,8 @@ BEGIN
|
|||||||
END IF;
|
END IF;
|
||||||
END; $$;
|
END; $$;
|
||||||
NOTICE: in process utility: superuser attempting CREATE FUNCTION
|
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 attempting create (subId=0x0) [explicit]
|
||||||
NOTICE: in object access: superuser finished create (subId=0x0) [explicit]
|
NOTICE: in object access: superuser finished create (subId=0x0) [explicit]
|
||||||
NOTICE: in process utility: superuser finished CREATE FUNCTION
|
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
|
NOTICE: in process utility: superuser finished CREATE TABLE
|
||||||
CREATE INDEX regress_test_table_t_idx ON regress_test_table (t);
|
CREATE INDEX regress_test_table_t_idx ON regress_test_table (t);
|
||||||
NOTICE: in process utility: superuser attempting CREATE INDEX
|
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 attempting create (subId=0x0) [explicit]
|
||||||
NOTICE: in object access: superuser finished create (subId=0x0) [explicit]
|
NOTICE: in object access: superuser finished create (subId=0x0) [explicit]
|
||||||
NOTICE: in process utility: superuser finished CREATE INDEX
|
NOTICE: in process utility: superuser finished CREATE INDEX
|
||||||
GRANT SELECT ON Table regress_test_table TO public;
|
GRANT SELECT ON Table regress_test_table TO public;
|
||||||
NOTICE: in process utility: superuser attempting GRANT
|
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
|
NOTICE: in process utility: superuser finished GRANT
|
||||||
CREATE FUNCTION regress_test_func (t text) RETURNS text AS $$
|
CREATE FUNCTION regress_test_func (t text) RETURNS text AS $$
|
||||||
SELECT $1;
|
SELECT $1;
|
||||||
|
@ -574,10 +574,11 @@ DROP OWNED BY regress_user_mvtest CASCADE;
|
|||||||
DROP ROLE regress_user_mvtest;
|
DROP ROLE regress_user_mvtest;
|
||||||
-- Concurrent refresh requires a unique index on the materialized
|
-- Concurrent refresh requires a unique index on the materialized
|
||||||
-- view. Test what happens if it's dropped during the refresh.
|
-- 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()
|
CREATE OR REPLACE FUNCTION mvtest_drop_the_index()
|
||||||
RETURNS bool AS $$
|
RETURNS bool AS $$
|
||||||
BEGIN
|
BEGIN
|
||||||
EXECUTE 'DROP INDEX IF EXISTS mvtest_drop_idx';
|
EXECUTE 'DROP INDEX IF EXISTS mvtest_mvschema.mvtest_drop_idx';
|
||||||
RETURN true;
|
RETURN true;
|
||||||
END;
|
END;
|
||||||
$$ LANGUAGE plpgsql;
|
$$ LANGUAGE plpgsql;
|
||||||
@ -588,6 +589,7 @@ CREATE UNIQUE INDEX mvtest_drop_idx ON drop_idx_matview (i);
|
|||||||
REFRESH MATERIALIZED VIEW CONCURRENTLY drop_idx_matview;
|
REFRESH MATERIALIZED VIEW CONCURRENTLY drop_idx_matview;
|
||||||
ERROR: could not find suitable unique index on materialized view
|
ERROR: could not find suitable unique index on materialized view
|
||||||
DROP MATERIALIZED VIEW drop_idx_matview; -- clean up
|
DROP MATERIALIZED VIEW drop_idx_matview; -- clean up
|
||||||
|
RESET search_path;
|
||||||
-- make sure that create WITH NO DATA works via SPI
|
-- make sure that create WITH NO DATA works via SPI
|
||||||
BEGIN;
|
BEGIN;
|
||||||
CREATE FUNCTION mvtest_func()
|
CREATE FUNCTION mvtest_func()
|
||||||
|
@ -114,3 +114,47 @@ SELECT COUNT(*) FROM pg_class WHERE relnamespace =
|
|||||||
0
|
0
|
||||||
(1 row)
|
(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
|
CREATE FUNCTION unwanted_grant() RETURNS void LANGUAGE sql AS
|
||||||
'GRANT regress_priv_group2 TO regress_sro_user';
|
'GRANT regress_priv_group2 TO regress_sro_user';
|
||||||
CREATE FUNCTION mv_action() RETURNS bool LANGUAGE sql AS
|
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
|
-- REFRESH of this MV will queue a GRANT at end of transaction
|
||||||
CREATE MATERIALIZED VIEW sro_mv AS SELECT mv_action() WITH NO DATA;
|
CREATE MATERIALIZED VIEW sro_mv AS SELECT mv_action() WITH NO DATA;
|
||||||
REFRESH MATERIALIZED VIEW sro_mv;
|
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
|
-- INSERT to this table will queue a GRANT at end of transaction
|
||||||
CREATE TABLE sro_trojan_table ();
|
CREATE TABLE sro_trojan_table ();
|
||||||
CREATE FUNCTION sro_trojan() RETURNS trigger LANGUAGE plpgsql AS
|
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
|
CREATE CONSTRAINT TRIGGER t AFTER INSERT ON sro_trojan_table
|
||||||
INITIALLY DEFERRED FOR EACH ROW EXECUTE PROCEDURE sro_trojan();
|
INITIALLY DEFERRED FOR EACH ROW EXECUTE PROCEDURE sro_trojan();
|
||||||
-- Now, REFRESH will issue such an INSERT, queueing the GRANT
|
-- Now, REFRESH will issue such an INSERT, queueing the GRANT
|
||||||
CREATE OR REPLACE FUNCTION mv_action() RETURNS bool LANGUAGE sql AS
|
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;
|
REFRESH MATERIALIZED VIEW sro_mv;
|
||||||
ERROR: cannot fire deferred trigger within security-restricted operation
|
ERROR: cannot fire deferred trigger within security-restricted operation
|
||||||
CONTEXT: SQL function "mv_action" statement 1
|
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"
|
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.
|
DETAIL: Only roles with the ADMIN option on role "regress_priv_group2" may grant this role.
|
||||||
CONTEXT: SQL function "unwanted_grant" statement 1
|
CONTEXT: SQL function "unwanted_grant" statement 1
|
||||||
SQL statement "SELECT unwanted_grant()"
|
SQL statement "SELECT public.unwanted_grant()"
|
||||||
PL/pgSQL function sro_trojan() line 1 at PERFORM
|
PL/pgSQL function public.sro_trojan() line 1 at PERFORM
|
||||||
SQL function "mv_action" statement 1
|
SQL function "mv_action" statement 1
|
||||||
-- REFRESH MATERIALIZED VIEW CONCURRENTLY use of eval_const_expressions()
|
-- REFRESH MATERIALIZED VIEW CONCURRENTLY use of eval_const_expressions()
|
||||||
SET SESSION AUTHORIZATION regress_sro_user;
|
SET SESSION AUTHORIZATION regress_sro_user;
|
||||||
CREATE FUNCTION unwanted_grant_nofail(int) RETURNS int
|
CREATE FUNCTION unwanted_grant_nofail(int) RETURNS int
|
||||||
IMMUTABLE LANGUAGE plpgsql AS $$
|
IMMUTABLE LANGUAGE plpgsql AS $$
|
||||||
BEGIN
|
BEGIN
|
||||||
PERFORM unwanted_grant();
|
PERFORM public.unwanted_grant();
|
||||||
RAISE WARNING 'owned';
|
RAISE WARNING 'owned';
|
||||||
RETURN 1;
|
RETURN 1;
|
||||||
EXCEPTION WHEN OTHERS THEN
|
EXCEPTION WHEN OTHERS THEN
|
||||||
|
@ -64,7 +64,7 @@ CLUSTER vaccluster;
|
|||||||
CREATE FUNCTION do_analyze() RETURNS VOID VOLATILE LANGUAGE SQL
|
CREATE FUNCTION do_analyze() RETURNS VOID VOLATILE LANGUAGE SQL
|
||||||
AS 'ANALYZE pg_am';
|
AS 'ANALYZE pg_am';
|
||||||
CREATE FUNCTION wrap_do_analyze(c INT) RETURNS INT IMMUTABLE LANGUAGE SQL
|
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));
|
CREATE INDEX ON vaccluster(wrap_do_analyze(i));
|
||||||
INSERT INTO vaccluster VALUES (1), (2);
|
INSERT INTO vaccluster VALUES (1), (2);
|
||||||
ANALYZE vaccluster;
|
ANALYZE vaccluster;
|
||||||
|
@ -233,10 +233,11 @@ DROP ROLE regress_user_mvtest;
|
|||||||
|
|
||||||
-- Concurrent refresh requires a unique index on the materialized
|
-- Concurrent refresh requires a unique index on the materialized
|
||||||
-- view. Test what happens if it's dropped during the refresh.
|
-- 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()
|
CREATE OR REPLACE FUNCTION mvtest_drop_the_index()
|
||||||
RETURNS bool AS $$
|
RETURNS bool AS $$
|
||||||
BEGIN
|
BEGIN
|
||||||
EXECUTE 'DROP INDEX IF EXISTS mvtest_drop_idx';
|
EXECUTE 'DROP INDEX IF EXISTS mvtest_mvschema.mvtest_drop_idx';
|
||||||
RETURN true;
|
RETURN true;
|
||||||
END;
|
END;
|
||||||
$$ LANGUAGE plpgsql;
|
$$ LANGUAGE plpgsql;
|
||||||
@ -247,6 +248,7 @@ CREATE MATERIALIZED VIEW drop_idx_matview AS
|
|||||||
CREATE UNIQUE INDEX mvtest_drop_idx ON drop_idx_matview (i);
|
CREATE UNIQUE INDEX mvtest_drop_idx ON drop_idx_matview (i);
|
||||||
REFRESH MATERIALIZED VIEW CONCURRENTLY drop_idx_matview;
|
REFRESH MATERIALIZED VIEW CONCURRENTLY drop_idx_matview;
|
||||||
DROP MATERIALIZED VIEW drop_idx_matview; -- clean up
|
DROP MATERIALIZED VIEW drop_idx_matview; -- clean up
|
||||||
|
RESET search_path;
|
||||||
|
|
||||||
-- make sure that create WITH NO DATA works via SPI
|
-- make sure that create WITH NO DATA works via SPI
|
||||||
BEGIN;
|
BEGIN;
|
||||||
|
@ -66,3 +66,35 @@ DROP SCHEMA test_ns_schema_renamed CASCADE;
|
|||||||
-- verify that the objects were dropped
|
-- verify that the objects were dropped
|
||||||
SELECT COUNT(*) FROM pg_class WHERE relnamespace =
|
SELECT COUNT(*) FROM pg_class WHERE relnamespace =
|
||||||
(SELECT oid FROM pg_namespace WHERE nspname = 'test_ns_schema_renamed');
|
(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
|
CREATE FUNCTION unwanted_grant() RETURNS void LANGUAGE sql AS
|
||||||
'GRANT regress_priv_group2 TO regress_sro_user';
|
'GRANT regress_priv_group2 TO regress_sro_user';
|
||||||
CREATE FUNCTION mv_action() RETURNS bool LANGUAGE sql AS
|
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
|
-- REFRESH of this MV will queue a GRANT at end of transaction
|
||||||
CREATE MATERIALIZED VIEW sro_mv AS SELECT mv_action() WITH NO DATA;
|
CREATE MATERIALIZED VIEW sro_mv AS SELECT mv_action() WITH NO DATA;
|
||||||
REFRESH MATERIALIZED VIEW sro_mv;
|
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
|
-- INSERT to this table will queue a GRANT at end of transaction
|
||||||
CREATE TABLE sro_trojan_table ();
|
CREATE TABLE sro_trojan_table ();
|
||||||
CREATE FUNCTION sro_trojan() RETURNS trigger LANGUAGE plpgsql AS
|
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
|
CREATE CONSTRAINT TRIGGER t AFTER INSERT ON sro_trojan_table
|
||||||
INITIALLY DEFERRED FOR EACH ROW EXECUTE PROCEDURE sro_trojan();
|
INITIALLY DEFERRED FOR EACH ROW EXECUTE PROCEDURE sro_trojan();
|
||||||
-- Now, REFRESH will issue such an INSERT, queueing the GRANT
|
-- Now, REFRESH will issue such an INSERT, queueing the GRANT
|
||||||
CREATE OR REPLACE FUNCTION mv_action() RETURNS bool LANGUAGE sql AS
|
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;
|
REFRESH MATERIALIZED VIEW sro_mv;
|
||||||
\c -
|
\c -
|
||||||
REFRESH MATERIALIZED VIEW sro_mv;
|
REFRESH MATERIALIZED VIEW sro_mv;
|
||||||
@ -1204,7 +1204,7 @@ SET SESSION AUTHORIZATION regress_sro_user;
|
|||||||
CREATE FUNCTION unwanted_grant_nofail(int) RETURNS int
|
CREATE FUNCTION unwanted_grant_nofail(int) RETURNS int
|
||||||
IMMUTABLE LANGUAGE plpgsql AS $$
|
IMMUTABLE LANGUAGE plpgsql AS $$
|
||||||
BEGIN
|
BEGIN
|
||||||
PERFORM unwanted_grant();
|
PERFORM public.unwanted_grant();
|
||||||
RAISE WARNING 'owned';
|
RAISE WARNING 'owned';
|
||||||
RETURN 1;
|
RETURN 1;
|
||||||
EXCEPTION WHEN OTHERS THEN
|
EXCEPTION WHEN OTHERS THEN
|
||||||
|
@ -49,7 +49,7 @@ CLUSTER vaccluster;
|
|||||||
CREATE FUNCTION do_analyze() RETURNS VOID VOLATILE LANGUAGE SQL
|
CREATE FUNCTION do_analyze() RETURNS VOID VOLATILE LANGUAGE SQL
|
||||||
AS 'ANALYZE pg_am';
|
AS 'ANALYZE pg_am';
|
||||||
CREATE FUNCTION wrap_do_analyze(c INT) RETURNS INT IMMUTABLE LANGUAGE SQL
|
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));
|
CREATE INDEX ON vaccluster(wrap_do_analyze(i));
|
||||||
INSERT INTO vaccluster VALUES (1), (2);
|
INSERT INTO vaccluster VALUES (1), (2);
|
||||||
ANALYZE vaccluster;
|
ANALYZE vaccluster;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user