Re: [PATCH] Add pg_get_policy_ddl() function to reconstruct CREATE POLICY statement - Mailing list pgsql-hackers

From Akshay Joshi
Subject Re: [PATCH] Add pg_get_policy_ddl() function to reconstruct CREATE POLICY statement
Date
Msg-id CANxoLDccMKZXA7qWAu6bGXRqVGu_DNPFxP4ssQ5Q4yq9Hwiq-g@mail.gmail.com
Whole thread Raw
In response to Re: [PATCH] Add pg_get_policy_ddl() function to reconstruct CREATE POLICY statement  (jian he <jian.universality@gmail.com>)
Responses Re: [PATCH] Add pg_get_policy_ddl() function to reconstruct CREATE POLICY statement
List pgsql-hackers

On Wed, Oct 22, 2025 at 12:51 PM jian he <jian.universality@gmail.com> wrote:
On Thu, Oct 16, 2025 at 8:51 PM Akshay Joshi
<akshay.joshi@enterprisedb.com> wrote:
>
> Please find attached the v3 patch, which resolves all compilation errors and warnings.
>

drop table if exists t, ts, ts1;
create table t(a int);
CREATE POLICY p0 ON t FOR ALL TO PUBLIC USING (a % 2 = 1);
SELECT pg_get_policy_ddl('t', 'p0', false);

                          pg_get_policy_ddl
---------------------------------------------------------------------
  CREATE POLICY p0 ON t AS PERMISSIVE FOR ALL USING (((a % 2) = 1));
(1 row)

"TO PUBLIC" part is missing, maybe it's ok.

I used the logic below, which did not return PUBLIC as a role. I have added logic to default the TO clause to PUBLIC when no specific role name is provided 
valueDatum = heap_getattr(tuplePolicy,
Anum_pg_policy_polroles,
RelationGetDescr(pgPolicyRel),
&attrIsNull);
if (!attrIsNull)
{
ArrayType *policy_roles = DatumGetArrayTypePCopy(valueDatum);
int nitems = ARR_DIMS(policy_roles)[0];
Oid *roles = (Oid *) ARR_DATA_PTR(policy_roles);
     


SELECT pg_get_policy_ddl(-1, 'p0', false);
ERROR:  could not open relation with OID 4294967295
as I mentioned in a nearby thread [1], this should be NULL instead of ERROR.
[1] https://postgr.es/m/CACJufxGbE4uJWu1YuqdmOx+7PMBpHvX_fbRMmHu=r4SrsuW9tg@mail.gmail.com

Fixed in v4 patch. 

IMHO, get_formatted_string is not needed, most of the time, if pretty is true,
we append "\t" and "\n", for that we can simply do
```
  appendStringInfo(&buf, "CREATE POLICY %s ON %s ",
       quote_identifier(NameStr(*policyName)),
       generate_qualified_relation_name(policy_form->polrelid));
if (pretty)
    appendStringInfoString(buf, "\t\n");
```


The get_formatted_string function is needed. Instead of using multiple if statements for the pretty flag, it’s better to have a generic function. This will be useful if the pretty-format DDL implementation is accepted by the community, as it can be reused by other pg_get_<object>_ddl() DDL functions added in the future. 

in pg_get_triggerdef_worker, I found the below code pattern:
    /*
     * In non-pretty mode, always schema-qualify the target table name for
     * safety.  In pretty mode, schema-qualify only if not visible.
     */
    appendStringInfo(&buf, " ON %s ",
                     pretty ?
                     generate_relation_name(trigrec->tgrelid, NIL) :
                     generate_qualified_relation_name(trigrec->tgrelid));

maybe we can apply it too while construct query string:
"CREATE POLICY %s ON %s",

In my opinion, the table name should always be schema-qualified, which I have addressed in the v4 patch. The implementation of the pretty flag here differs from pg_get_triggerdef_worker, which is used only for the target table name. In my patch, the pretty flag adds \t and \n to each different clause (example AS, FOR, USING ...)
 
Attachment

pgsql-hackers by date:

Previous
From: Aleksander Alekseev
Date:
Subject: Re: [PATCH] Remove make_temptable_name_n()
Next
From: Fujii Masao
Date:
Subject: Re: Invalid primary_slot_name triggers warnings in all processes on reload