diff --git a/doc/src/sgml/ref/create_materialized_view.sgml b/doc/src/sgml/ref/create_materialized_view.sgml index 0ed764b353394137afd73c9a013e031e197ae79c..b742e17ac828a64f816650e7c8c78c3f67bffd78 100644 --- a/doc/src/sgml/ref/create_materialized_view.sgml +++ b/doc/src/sgml/ref/create_materialized_view.sgml @@ -105,7 +105,9 @@ CREATE MATERIALIZED VIEW <replaceable>table_name</replaceable> <listitem> <para> A <xref linkend="sql-select">, <link linkend="sql-table">TABLE</link>, - or <xref linkend="sql-values"> command. + or <xref linkend="sql-values"> command. This query will run within a + security-restricted operation; in particular, calls to functions that + themselves create temporary tables will fail. </para> </listitem> </varlistentry> diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c index 2bfe5fba8775631afb378b8591b536c3472b074b..a3509d8c2a3242efa7896fb0a777e5928b239d6e 100644 --- a/src/backend/commands/createas.c +++ b/src/backend/commands/createas.c @@ -33,6 +33,7 @@ #include "commands/prepare.h" #include "commands/tablecmds.h" #include "commands/view.h" +#include "miscadmin.h" #include "parser/parse_clause.h" #include "rewrite/rewriteHandler.h" #include "storage/smgr.h" @@ -69,7 +70,11 @@ ExecCreateTableAs(CreateTableAsStmt *stmt, const char *queryString, { Query *query = (Query *) stmt->query; IntoClause *into = stmt->into; + bool is_matview = (into->viewQuery != NULL); DestReceiver *dest; + Oid save_userid = InvalidOid; + int save_sec_context = 0; + int save_nestlevel = 0; List *rewritten; PlannedStmt *plan; QueryDesc *queryDesc; @@ -90,12 +95,28 @@ ExecCreateTableAs(CreateTableAsStmt *stmt, const char *queryString, { ExecuteStmt *estmt = (ExecuteStmt *) query->utilityStmt; + Assert(!is_matview); /* excluded by syntax */ ExecuteQuery(estmt, into, queryString, params, dest, completionTag); return; } Assert(query->commandType == CMD_SELECT); + /* + * For materialized views, lock down security-restricted operations and + * arrange to make GUC variable changes local to this command. This is + * not necessary for security, but this keeps the behavior similar to + * REFRESH MATERIALIZED VIEW. Otherwise, one could create a materialized + * view not possible to refresh. + */ + if (is_matview) + { + GetUserIdAndSecContext(&save_userid, &save_sec_context); + SetUserIdAndSecContext(save_userid, + save_sec_context | SECURITY_RESTRICTED_OPERATION); + save_nestlevel = NewGUCNestLevel(); + } + /* * Parse analysis was done already, but we still have to run the rule * rewriter. We do not do AcquireRewriteLocks: we assume the query either @@ -160,6 +181,15 @@ ExecCreateTableAs(CreateTableAsStmt *stmt, const char *queryString, FreeQueryDesc(queryDesc); PopActiveSnapshot(); + + if (is_matview) + { + /* Roll back any GUC changes */ + AtEOXact_GUC(false, save_nestlevel); + + /* Restore userid and security context */ + SetUserIdAndSecContext(save_userid, save_sec_context); + } } /* diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c index 2ffdca31f6ba35e2c95d75fcba5bf850f7a20aa3..1c383baf68750808320ebc5e9925b122c802a639 100644 --- a/src/backend/commands/matview.c +++ b/src/backend/commands/matview.c @@ -122,6 +122,9 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString, RewriteRule *rule; List *actions; Query *dataQuery; + Oid save_userid; + int save_sec_context; + int save_nestlevel; Oid tableSpace; Oid OIDNewHeap; DestReceiver *dest; @@ -191,6 +194,16 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString, */ CheckTableNotInUse(matviewRel, "REFRESH MATERIALIZED VIEW"); + /* + * Switch to the owner's userid, so that any functions are run as that + * user. Also lock down security-restricted operations and arrange to + * make GUC variable changes local to this command. + */ + GetUserIdAndSecContext(&save_userid, &save_sec_context); + SetUserIdAndSecContext(matviewRel->rd_rel->relowner, + save_sec_context | SECURITY_RESTRICTED_OPERATION); + save_nestlevel = NewGUCNestLevel(); + /* * Tentatively mark the matview as populated or not (this will roll back * if we fail later). @@ -217,6 +230,12 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString, RecentXmin, ReadNextMultiXactId()); RelationCacheInvalidateEntry(matviewOid); + + /* Roll back any GUC changes */ + AtEOXact_GUC(false, save_nestlevel); + + /* Restore userid and security context */ + SetUserIdAndSecContext(save_userid, save_sec_context); } /*