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 addresses a security risk introduced in commit 60684dd834, where a role with MAINTAIN privileges on a table may be able to escalate privileges to the table owner. That commit is not yet part of any release, so no need to backpatch. Discussion: https://postgr.es/m/e44327179e5c9015c8dda67351c04da552066017.camel%40j-davis.com Reviewed-by: Greg Stark Reviewed-by: Nathan Bossart
This commit is contained in:
parent
9aee26a491
commit
05e1737351
@ -282,6 +282,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
|
||||||
{
|
{
|
||||||
|
@ -1066,6 +1066,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
|
||||||
{
|
{
|
||||||
|
@ -1475,6 +1475,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);
|
||||||
|
|
||||||
@ -3006,6 +3008,8 @@ 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();
|
||||||
|
SetConfigOption("search_path", GUC_SAFE_SEARCH_PATH, PGC_USERSET,
|
||||||
|
PGC_S_SESSION);
|
||||||
|
|
||||||
/* Set up initial progress report status */
|
/* Set up initial progress report status */
|
||||||
{
|
{
|
||||||
@ -3341,6 +3345,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);
|
||||||
|
|
||||||
@ -3601,6 +3607,8 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
|
|||||||
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)
|
||||||
{
|
{
|
||||||
|
@ -348,6 +348,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 (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
|
if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
|
||||||
|
@ -355,6 +355,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
|
||||||
|
@ -575,6 +575,8 @@ DefineIndex(Oid relationId,
|
|||||||
int root_save_nestlevel;
|
int root_save_nestlevel;
|
||||||
|
|
||||||
root_save_nestlevel = NewGUCNestLevel();
|
root_save_nestlevel = NewGUCNestLevel();
|
||||||
|
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
|
||||||
@ -1300,6 +1302,8 @@ DefineIndex(Oid relationId,
|
|||||||
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
|
||||||
@ -3753,6 +3757,8 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
|
|||||||
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 &&
|
||||||
|
@ -179,6 +179,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)
|
||||||
|
@ -2172,6 +2172,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,15 +109,11 @@ $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);
|
||||||
|);
|
|);
|
||||||
$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' ],
|
||||||
|
@ -201,6 +201,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.
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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