pg_dump, pg_dumpall, pg_restore: Add --no-policies option.

Add --no-policies option to control row level security policy handling
in dump and restore operations. When this option is used, both CREATE
POLICY commands and ALTER TABLE ... ENABLE ROW LEVEL SECURITY commands
are excluded from dumps and skipped during restores.

This is useful in scenarios where policies need to be redefined in the
target system or when moving data between environments with different
security requirements.

Author: Nikolay Samokhvalov <nik@postgres.ai>
Reviewed-by: Greg Sabino Mullane <htamfids@gmail.com>
Reviewed-by: Jim Jones <jim.jones@uni-muenster.de>
Reviewed-by: newtglobal postgresql_contributors <postgresql_contributors@newtglobalcorp.com>
Discussion: https://postgr.es/m/CAM527d8kG2qPKvbfJ=OYJkT7iRNd623Bk+m-a4ngm+nyHYsHog@mail.gmail.com
This commit is contained in:
Tom Lane 2025-03-16 18:08:15 -04:00
parent 4489044239
commit cd3c45125d
9 changed files with 71 additions and 1 deletions

View File

@ -1105,6 +1105,15 @@ PostgreSQL documentation
</listitem>
</varlistentry>
<varlistentry>
<term><option>--no-policies</option></term>
<listitem>
<para>
Do not dump row security policies.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--no-publications</option></term>
<listitem>

View File

@ -441,6 +441,15 @@ exclude database <replaceable class="parameter">PATTERN</replaceable>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--no-policies</option></term>
<listitem>
<para>
Do not dump row security policies.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--no-publications</option></term>
<listitem>

View File

@ -723,6 +723,16 @@ PostgreSQL documentation
</listitem>
</varlistentry>
<varlistentry>
<term><option>--no-policies</option></term>
<listitem>
<para>
Do not output commands to restore row security policies, even if
the archive contains them.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--no-publications</option></term>
<listitem>

View File

@ -111,6 +111,7 @@ typedef struct _restoreOptions
int column_inserts;
int if_exists;
int no_comments; /* Skip comments */
int no_policies; /* Skip row security policies */
int no_publications; /* Skip publication entries */
int no_security_labels; /* Skip security label entries */
int no_subscriptions; /* Skip subscription entries */
@ -181,8 +182,9 @@ typedef struct _dumpOptions
int column_inserts;
int if_exists;
int no_comments;
int no_security_labels;
int no_policies; /* Skip row security policies */
int no_publications;
int no_security_labels;
int no_subscriptions;
int no_toast_compression;
int no_unlogged_table_data;

View File

@ -188,6 +188,7 @@ dumpOptionsFromRestoreOptions(RestoreOptions *ropt)
dopt->disable_dollar_quoting = ropt->disable_dollar_quoting;
dopt->dump_inserts = ropt->dump_inserts;
dopt->no_comments = ropt->no_comments;
dopt->no_policies = ropt->no_policies;
dopt->no_publications = ropt->no_publications;
dopt->no_security_labels = ropt->no_security_labels;
dopt->no_subscriptions = ropt->no_subscriptions;
@ -2966,6 +2967,12 @@ _tocEntryRequired(TocEntry *te, teSection curSection, ArchiveHandle *AH)
if (ropt->no_comments && strcmp(te->desc, "COMMENT") == 0)
return 0;
/* If it's a policy, maybe ignore it */
if (ropt->no_policies &&
(strcmp(te->desc, "POLICY") == 0 ||
strcmp(te->desc, "ROW SECURITY") == 0))
return 0;
/*
* If it's a publication or a table part of a publication, maybe ignore
* it.

View File

@ -500,6 +500,7 @@ main(int argc, char **argv)
{"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
{"no-comments", no_argument, &dopt.no_comments, 1},
{"no-data", no_argument, NULL, 19},
{"no-policies", no_argument, &dopt.no_policies, 1},
{"no-publications", no_argument, &dopt.no_publications, 1},
{"no-schema", no_argument, NULL, 20},
{"no-security-labels", no_argument, &dopt.no_security_labels, 1},
@ -1152,6 +1153,7 @@ main(int argc, char **argv)
ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
ropt->dump_inserts = dopt.dump_inserts;
ropt->no_comments = dopt.no_comments;
ropt->no_policies = dopt.no_policies;
ropt->no_publications = dopt.no_publications;
ropt->no_security_labels = dopt.no_security_labels;
ropt->no_subscriptions = dopt.no_subscriptions;
@ -1259,6 +1261,7 @@ help(const char *progname)
printf(_(" --load-via-partition-root load partitions via the root table\n"));
printf(_(" --no-comments do not dump comment commands\n"));
printf(_(" --no-data do not dump data\n"));
printf(_(" --no-policies do not dump row security policies\n"));
printf(_(" --no-publications do not dump publications\n"));
printf(_(" --no-schema do not dump schema\n"));
printf(_(" --no-security-labels do not dump security label assignments\n"));
@ -4035,6 +4038,7 @@ dumpLOs(Archive *fout, const void *arg)
void
getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
{
DumpOptions *dopt = fout->dopt;
PQExpBuffer query;
PQExpBuffer tbloids;
PGresult *res;
@ -4056,6 +4060,10 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
if (fout->remoteVersion < 90500)
return;
/* Skip if --no-policies was specified */
if (dopt->no_policies)
return;
query = createPQExpBuffer();
tbloids = createPQExpBuffer();

View File

@ -101,6 +101,7 @@ static int no_table_access_method = 0;
static int no_tablespaces = 0;
static int use_setsessauth = 0;
static int no_comments = 0;
static int no_policies = 0;
static int no_publications = 0;
static int no_security_labels = 0;
static int no_data = 0;
@ -173,6 +174,7 @@ main(int argc, char *argv[])
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
{"no-comments", no_argument, &no_comments, 1},
{"no-data", no_argument, &no_data, 1},
{"no-policies", no_argument, &no_policies, 1},
{"no-publications", no_argument, &no_publications, 1},
{"no-role-passwords", no_argument, &no_role_passwords, 1},
{"no-schema", no_argument, &no_schema, 1},
@ -457,6 +459,8 @@ main(int argc, char *argv[])
appendPQExpBufferStr(pgdumpopts, " --no-comments");
if (no_data)
appendPQExpBufferStr(pgdumpopts, " --no-data");
if (no_policies)
appendPQExpBufferStr(pgdumpopts, " --no-policies");
if (no_publications)
appendPQExpBufferStr(pgdumpopts, " --no-publications");
if (no_security_labels)
@ -681,6 +685,7 @@ help(void)
printf(_(" --load-via-partition-root load partitions via the root table\n"));
printf(_(" --no-comments do not dump comment commands\n"));
printf(_(" --no-data do not dump data\n"));
printf(_(" --no-policies do not dump row security policies\n"));
printf(_(" --no-publications do not dump publications\n"));
printf(_(" --no-role-passwords do not dump passwords for roles\n"));
printf(_(" --no-schema do not dump schema\n"));

View File

@ -74,6 +74,7 @@ main(int argc, char **argv)
static int use_setsessauth = 0;
static int no_comments = 0;
static int no_data = 0;
static int no_policies = 0;
static int no_publications = 0;
static int no_schema = 0;
static int no_security_labels = 0;
@ -129,6 +130,7 @@ main(int argc, char **argv)
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
{"no-comments", no_argument, &no_comments, 1},
{"no-data", no_argument, &no_data, 1},
{"no-policies", no_argument, &no_policies, 1},
{"no-publications", no_argument, &no_publications, 1},
{"no-schema", no_argument, &no_schema, 1},
{"no-security-labels", no_argument, &no_security_labels, 1},
@ -385,6 +387,7 @@ main(int argc, char **argv)
opts->noTablespace = outputNoTablespaces;
opts->use_setsessauth = use_setsessauth;
opts->no_comments = no_comments;
opts->no_policies = no_policies;
opts->no_publications = no_publications;
opts->no_security_labels = no_security_labels;
opts->no_subscriptions = no_subscriptions;
@ -505,6 +508,7 @@ usage(const char *progname)
printf(_(" --no-data do not restore data\n"));
printf(_(" --no-data-for-failed-tables do not restore data of tables that could not be\n"
" created\n"));
printf(_(" --no-policies do not restore row level security policies\n"));
printf(_(" --no-publications do not restore publications\n"));
printf(_(" --no-schema do not restore schema\n"));
printf(_(" --no-security-labels do not restore security labels\n"));

View File

@ -579,6 +579,14 @@ my %pgdump_runs = (
'postgres',
],
},
no_policies => {
dump_cmd => [
'pg_dump', '--no-sync',
'--file' => "$tempdir/no_policies.sql",
'--no-policies',
'postgres',
],
},
no_privs => {
dump_cmd => [
'pg_dump', '--no-sync',
@ -803,6 +811,7 @@ my %full_runs = (
no_toast_compression => 1,
no_large_objects => 1,
no_owner => 1,
no_policies => 1,
no_privs => 1,
no_statistics => 1,
no_table_access_method => 1,
@ -1328,6 +1337,7 @@ my %tests = (
unlike => {
exclude_dump_test_schema => 1,
exclude_test_table => 1,
no_policies => 1,
only_dump_measurement => 1,
},
},
@ -2948,6 +2958,7 @@ my %tests = (
unlike => {
exclude_dump_test_schema => 1,
exclude_test_table => 1,
no_policies => 1,
only_dump_measurement => 1,
},
},
@ -2969,6 +2980,7 @@ my %tests = (
unlike => {
exclude_dump_test_schema => 1,
exclude_test_table => 1,
no_policies => 1,
only_dump_measurement => 1,
},
},
@ -2990,6 +3002,7 @@ my %tests = (
unlike => {
exclude_dump_test_schema => 1,
exclude_test_table => 1,
no_policies => 1,
only_dump_measurement => 1,
},
},
@ -3011,6 +3024,7 @@ my %tests = (
unlike => {
exclude_dump_test_schema => 1,
exclude_test_table => 1,
no_policies => 1,
only_dump_measurement => 1,
},
},
@ -3032,6 +3046,7 @@ my %tests = (
unlike => {
exclude_dump_test_schema => 1,
exclude_test_table => 1,
no_policies => 1,
only_dump_measurement => 1,
},
},
@ -3053,6 +3068,7 @@ my %tests = (
unlike => {
exclude_dump_test_schema => 1,
exclude_test_table => 1,
no_policies => 1,
only_dump_measurement => 1,
},
},