Thread

  1. [PATCH] no table rewrite when set column type to constrained domain

    jian he <jian.universality@gmail.com> — 2025-07-09T18:00:15Z

    hi.
    
    the attached patch is to implement the $subject feature.
    i was mainly intrigued by the discussion in
    https://www.postgresql.org/message-id/20190226061450.GA1665944@rfd.leadboat.com
    
    the main gotcha is struct NewColumnValue.
    we do ``palloc0(sizeof(NewColumnValue));`` in ATExecAddColumn,
    ATExecSetExpression, ATPrepAlterColumnType.
    
    ATExecAddColumn:  Adding a new column with domain with constraints will cause
                      table rewrite.
    ATExecSetExpression: for stored generated column will cause table rewrite, we do
                         not support domain over virtual generated columns now.
    ATPrepAlterColumnType: we only do table rewriting occasionally.
    see ATColumnChangeRequiresRewrite.
    
    If table rewrite is required, then there is nothing we can do. so
    we only need to focus on ATPrepAlterColumnType.
    we can add a new boolean field, coerce_to_domain, to NewColumnValue. this field
    is set to true only when changing an existing column's type to a constrained
    domain. In such cases, a table scan is enough—no table rewrite is needed.
    coerce_to_domain will set to false, if table rewrite is required.
    
  2. Re: [PATCH] no table rewrite when set column type to constrained domain

    jian he <jian.universality@gmail.com> — 2025-08-26T03:26:16Z

    On Thu, Jul 10, 2025 at 2:00 AM jian he <jian.universality@gmail.com> wrote:
    >
    > we can add a new boolean field, coerce_to_domain, to NewColumnValue. this field
    > is set to true only when changing an existing column's type to a constrained
    > domain. In such cases, a table scan is enough—no table rewrite is needed.
    > coerce_to_domain will set to false, if table rewrite is required.
    
    I realized that "coerce_to_domain" is not so good in this context.
    maybe there are other scenarios, we added a NewColumnValue and we also
    only need table scan.
    so I changed it to scan_only.
    
    
    /*
     * ....
     * If scan_only is true, it means only a table scan is required.
     * Currently, this is supported only by the ALTER COLUMN SET DATA TYPE command,
     * where the column's data type is being changed to a constrained domain.
     */
    typedef struct NewColumnValue
    {
        AttrNumber    attnum;         /* which column */
        Expr       *expr;                    /* expression to compute */
        ExprState  *exprstate;         /* execution state */
        bool        is_generated;       /* is it a GENERATED expression? */
        bool        scan_only;           /* table scan only */
    } NewColumnValue;
    
  3. Re: [PATCH] no table rewrite when set column type to constrained domain

    jian he <jian.universality@gmail.com> — 2025-12-15T07:06:40Z

    On Tue, Aug 26, 2025 at 11:26 AM jian he <jian.universality@gmail.com> wrote:
    >
    > typedef struct NewColumnValue
    > {
    >     AttrNumber    attnum;         /* which column */
    >     Expr       *expr;                    /* expression to compute */
    >     ExprState  *exprstate;         /* execution state */
    >     bool        is_generated;       /* is it a GENERATED expression? */
    >     bool        scan_only;           /* table scan only */
    > } NewColumnValue;
    
    I changed scan_only to need_compute.
    
    + *
    + * If need_compute is true, we will evaluate the new column value in Phase 3.
    + * Currently, this is only used in ALTER COLUMN SET DATA TYPE
    command, where the
    + * column’s data type is being changed to a constrained domain, and all the
    + * domain's constraints are non-volatile. In case table rewrite, we also set it
    + * to true.
      */
     typedef struct NewColumnValue
     {
    @@ -238,6 +244,7 @@ typedef struct NewColumnValue
         Expr       *expr;            /* expression to compute */
         ExprState  *exprstate;        /* execution state */
         bool        is_generated;    /* is it a GENERATED expression? */
    +    bool        need_compute;    /* compute this new expression in Phase 3 */
     } NewColumnValue;
    
    I use domain over domain for regress tests.
    I also constrained the no–table-rewrite behavior to cases where the coercion is
    to a domain type and all constraints of the new domain are non-volatile.
    
    Demo:
    
    CREATE DOMAIN domain1 AS INT CHECK(VALUE > 1) NOT NULL;
    CREATE DOMAIN domain11 AS domain1 CHECK(VALUE > 1) NOT NULL;
    CREATE DOMAIN domain21 AS domain1 CHECK(VALUE > random(min=>10,
    max=>10)) NOT NULL;
    CREATE DOMAIN domain3 AS INT8;
    CREATE TABLE t22(a INT, b INT);
    INSERT INTO t22 VALUES(-2, -1);
    
    -- no table rewrite, but fail at domain constraint check
    ALTER TABLE t22 ALTER COLUMN a SET DATA TYPE domain11 USING a::domain11;
    -- no table rewrite, but fail at domain constraint check
    ALTER TABLE t22 ALTER COLUMN b SET DATA TYPE domain11 USING b::domain11;
    
    -- table rewrite
    ALTER TABLE t22 ALTER COLUMN a SET DATA TYPE domain21;
    ALTER TABLE t22 ALTER COLUMN b SET DATA TYPE domain3;
    ALTER TABLE t22 ALTER COLUMN a SET DATA TYPE domain1 USING (a+0)::domain1;
    
    
    
    --
    jian
    https://www.enterprisedb.com
    
  4. Re: [PATCH] no table rewrite when set column type to constrained domain

    solai v <solai.cdac@gmail.com> — 2026-05-14T09:18:12Z

    Hi,
    I tested the latest v6 patch on current master with a few different
    scenarios.For the simple int to constrained-domain type change
    case,the scan-only patch was used and the relfilenode stayed unchanged
    before and after ALTER TABLE ,so the rewrite was avoided as expected.
     I also tried USING expression cases,invalid domain values,and NULL
    values.The behavior looked correct in those cases as well.
    I tested with both small tables and a 1M row table.
    
    Regards,
    Solai