diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 76f8c51b6d..830d5f404a 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -3619,6 +3619,7 @@ void getPolicies(Archive *fout, TableInfo tblinfo[], int numTables) { PQExpBuffer query; + PQExpBuffer tbloids; PGresult *res; PolicyInfo *polinfo; int i_oid; @@ -3634,15 +3635,17 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables) j, ntups; + /* No policies before 9.5 */ if (fout->remoteVersion < 90500) return; query = createPQExpBuffer(); + tbloids = createPQExpBuffer(); /* - * First, check which tables have RLS enabled. We represent RLS being - * enabled on a table by creating a PolicyInfo object with null polname. + * Identify tables of interest, and check which ones have RLS enabled. */ + appendPQExpBufferChar(tbloids, '{'); for (i = 0; i < numTables; i++) { TableInfo *tbinfo = &tblinfo[i]; @@ -3651,9 +3654,23 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables) if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY)) continue; + /* It can't have RLS or policies if it's not a table */ + if (tbinfo->relkind != RELKIND_RELATION && + tbinfo->relkind != RELKIND_PARTITIONED_TABLE) + continue; + + /* Add it to the list of table OIDs to be probed below */ + if (tbloids->len > 1) /* do we have more than the '{'? */ + appendPQExpBufferChar(tbloids, ','); + appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid); + + /* Is RLS enabled? (That's separate from whether it has policies) */ if (tbinfo->rowsec) { /* + * We represent RLS being enabled on a table by creating a + * PolicyInfo object with null polname. + * * Note: use tableoid 0 so that this object won't be mistaken for * something that pg_depend entries apply to. */ @@ -3673,15 +3690,18 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables) polinfo->polwithcheck = NULL; } } + appendPQExpBufferChar(tbloids, '}'); /* - * Now, read all RLS policies, and create PolicyInfo objects for all those - * that are of interest. + * Now, read all RLS policies belonging to the tables of interest, and + * create PolicyInfo objects for them. (Note that we must filter the + * results server-side not locally, because we dare not apply pg_get_expr + * to tables we don't have lock on.) */ pg_log_info("reading row-level security policies"); printfPQExpBuffer(query, - "SELECT oid, tableoid, pol.polrelid, pol.polname, pol.polcmd, "); + "SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, "); if (fout->remoteVersion >= 100000) appendPQExpBuffer(query, "pol.polpermissive, "); else @@ -3691,7 +3711,9 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables) " pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(rolname) from pg_catalog.pg_roles WHERE oid = ANY(pol.polroles)), ', ') END AS polroles, " "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, " "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck " - "FROM pg_catalog.pg_policy pol"); + "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n" + "JOIN pg_catalog.pg_policy pol ON (src.tbloid = pol.polrelid)", + tbloids->data); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -3715,13 +3737,6 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables) Oid polrelid = atooid(PQgetvalue(res, j, i_polrelid)); TableInfo *tbinfo = findTableByOid(polrelid); - /* - * Ignore row security on tables not to be dumped. (This will - * result in some harmless wasted slots in polinfo[].) - */ - if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY)) - continue; - polinfo[j].dobj.objType = DO_POLICY; polinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid)); @@ -3756,6 +3771,7 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables) PQclear(res); destroyPQExpBuffer(query); + destroyPQExpBuffer(tbloids); } /*