Обсуждение: [PATCH] no table rewrite when set column type to constrained domain

Поиск
Список
Период
Сортировка

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

От
jian he
Дата:
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.

Вложения

Re: [PATCH] no table rewrite when set column type to constrained domain

От
jian he
Дата:
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;

Вложения

Re: [PATCH] no table rewrite when set column type to constrained domain

От
jian he
Дата:
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

Вложения