Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CN/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
** xref:v1.17/18.adoc[8、内置数据类型与内置函数]
** xref:v1.17/19.adoc[9、新增Oracle兼容模式的端口与IP]
** xref:v1.17/41.adoc[10、全局唯一索引]
** xref:v1.17/42.adoc[11、ALTER TABLE 修改列类型时自动重建依赖视图]
* xref:v1.17/20.adoc[社区贡献指南]
* xref:v1.17/21.adoc[工具参考]
* xref:v1.17/22.adoc[FAQ]
170 changes: 170 additions & 0 deletions CN/modules/ROOT/pages/v1.17/42.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
:sectnums:
:sectnumlevels: 5

:imagesdir: ./_images

= ALTER TABLE 修改列类型时自动重建依赖视图

== 功能介绍

在标准 PostgreSQL 中,若某列被视图所引用,执行 `ALTER TABLE ... ALTER COLUMN ... TYPE` 修改该列的数据类型时,数据库会直接报错:

----
ERROR: cannot alter type of a column used by a view or rule
----

用户必须手动删除所有依赖视图,完成列类型修改后再逐一重建,操作繁琐且容易出错,在存在多层视图依赖时尤为困难。

IvorySQL 对此行为进行了增强:执行列类型变更时,数据库会自动保存所有依赖视图(包括间接依赖的级联视图)的定义,在完成类型修改后按正确顺序重建这些视图
,对用户完全透明。若重建过程中发生错误(例如视图使用了新类型不支持的操作符),整个 `ALTER TABLE` 操作将整体回滚,保证数据一致性。

该功能同时支持 PG 兼容模式与 Oracle 兼容模式。

== 语法

语法与标准 `ALTER TABLE` 完全一致,无需额外关键字:

[source,sql]
----
ALTER TABLE table_name ALTER COLUMN column_name TYPE new_type;
----

参数说明:

- `table_name`:目标表名,可带 schema 前缀;
- `column_name`:需要修改类型的列名;
- `new_type`:目标数据类型,需与原类型兼容或可隐式转换。

== 测试用例

=== 单视图依赖:自动重建

[source,sql]
----
-- 创建基表
CREATE TABLE t (a int, b text);

-- 创建依赖列 a 的视图
CREATE VIEW v AS SELECT a, b FROM t;

-- 标准 PostgreSQL 此处会报错,IvorySQL 自动重建视图
ALTER TABLE t ALTER COLUMN a TYPE bigint;

-- 验证视图仍然有效,且列类型已更新
SELECT pg_typeof(a) FROM v LIMIT 1;
-- 返回 bigint
pg_typeof
-----------
(0 rows)


\d v
View "public.v"
Column | Type | Collation | Nullable | Default
--------+--------+-----------+----------+---------
a | bigint | | |
b | text | | |
----

=== 级联视图依赖:按序自动重建

[source,sql]
----
-- 创建基表
CREATE TABLE t (a int, b text);

-- 创建两层视图依赖:v2 依赖 v1,v1 依赖 t
CREATE VIEW v1 AS SELECT a, b FROM t;
CREATE VIEW v2 AS SELECT a FROM v1;

-- 修改列类型,自动按依赖顺序重建 v1、v2
ALTER TABLE t ALTER COLUMN a TYPE bigint;

-- 验证两个视图均已正确重建
SELECT pg_typeof(a) FROM v1 LIMIT 1;
-- 返回 bigint
pg_typeof
-----------
(0 rows)

SELECT pg_typeof(a) FROM v2 LIMIT 1;
-- 返回 bigint
pg_typeof
-----------
(0 rows)
----

=== 保留视图选项:security_barrier

[source,sql]
----
-- 创建带 security_barrier 选项的视图
CREATE VIEW v WITH (security_barrier) AS SELECT a, b FROM t;

ALTER TABLE t ALTER COLUMN a TYPE bigint;

-- 验证 security_barrier 选项在重建后被正确保留
SELECT relname, reloptions FROM pg_class WHERE relname = 'v';
-- reloptions: {security_barrier=true}
relname | reloptions
---------+-------------------------
v | {security_barrier=true}
(1 row)
----

=== 保留视图选项:WITH CHECK OPTION

[source,sql]
----
-- 创建带 WITH LOCAL CHECK OPTION 的视图
CREATE VIEW v AS SELECT a, b FROM t WHERE a > 0
WITH LOCAL CHECK OPTION;

ALTER TABLE t ALTER COLUMN a TYPE bigint;

-- 验证 CHECK OPTION 在重建后被正确保留
\d+ v
View "public.v"
Column | Type | Collation | Nullable | Default | Storage | Description
--------+--------+-----------+----------+---------+----------+-------------
a | bigint | | | | plain |
b | text | | | | extended |
View definition:
SELECT t.a,
t.b
FROM t
WHERE t.a > 0;
Options: check_option=local
----

=== 重建失败时整体回滚

[source,sql]
----
CREATE TABLE t (a int, b text);
CREATE VIEW v AS SELECT a::integer + 1 AS a_plus FROM t;

-- 若新类型与视图中的表达式不兼容,整个操作回滚
-- 例如将 a 改为 text 类型,视图中的 a::integer + 1 将无法执行
ALTER TABLE t ALTER COLUMN a TYPE text;
ERROR: operator does not exist: text + integer
LINE 1: ALTER TABLE t ALTER COLUMN a TYPE text;
^
HINT: No operator matches the given name and argument types. You might need to add explicit type casts.

-- 确认表结构与视图均未受影响
\d t
Table "public.t"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
a | integer | | |
b | text | | |
----

== 功能限制

. 若视图中使用了与新列类型不兼容的操作符或函数(例如对 `text` 类型列执行算术运算),重建将失败,整个 `ALTER TABLE` 操作回滚;
. 仅支持视图(view)的自动重建,依赖该列的**规则(rule)**仍会报错;
. 列类型变更需满足 PostgreSQL 类型转换规则,不支持任意两种类型之间的直接转换;
. 视图重建按依赖拓扑顺序执行,循环依赖(通常由数据库约束避免)不在处理范围内;
. 重建过程在同一事务内完成,期间依赖视图处于不可用状态,高并发场景下需注意对查询的影响。
3 changes: 2 additions & 1 deletion EN/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
** xref:v1.17/18.adoc[8、Built-in data types and built-in functions]
** xref:v1.17/19.adoc[9、Added Oracle compatibility mode ports and IP]
** xref:v1.17/41.adoc[10、Global Unique Index]
** xref:v1.17/42.adoc[11、Auto-Rebuild Dependent Views on ALTER TABLE Column Type Change]
* xref:v1.17/20.adoc[Community contribution]
* xref:v1.17/21.adoc[Tool Reference]
* xref:v1.17/22.adoc[FAQ]
* xref:v1.17/22.adoc[FAQ]
171 changes: 171 additions & 0 deletions EN/modules/ROOT/pages/v1.17/42.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
:sectnums:
:sectnumlevels: 5

:imagesdir: ./_images

= Auto-Rebuild Dependent Views on ALTER TABLE Column Type Change

== Feature Overview

In standard PostgreSQL, if a column is referenced by a view, attempting to change its data type via `ALTER TABLE ... ALTER COLUMN ... TYPE` results
in an immediate error:

----
ERROR: cannot alter type of a column used by a view or rule
----

Users are required to manually drop all dependent views, perform the column type change, and then recreate each view one by one — a tedious and
error-prone process that becomes particularly difficult when multiple levels of cascaded view dependencies exist.

IvorySQL enhances this behavior: when a column type change is executed, the database automatically saves the definitions of all dependent views
(including indirectly dependent cascaded views), and after completing the type change, rebuilds those views in the correct dependency order —
entirely transparent to the user. If an error occurs during rebuilding (for example, a view uses an operator not supported by the new type), the
entire `ALTER TABLE` operation is rolled back, ensuring data consistency.

This feature is supported in both PG-compatible mode and Oracle-compatible mode.

== Syntax

The syntax is identical to the standard `ALTER TABLE` — no additional keywords are required:

[source,sql]
----
ALTER TABLE table_name ALTER COLUMN column_name TYPE new_type;
----

Parameter description:

- `table_name`: The target table name, optionally schema-qualified;
- `column_name`: The name of the column whose type is to be changed;
- `new_type`: The target data type, which must be compatible with the original type or implicitly castable.

== Test Cases

=== Single View Dependency: Automatic Rebuild

[source,sql]
----
-- Create the base table
CREATE TABLE t (a int, b text);

-- Create a view that references column a
CREATE VIEW v AS SELECT a, b FROM t;

-- Standard PostgreSQL would error here; IvorySQL rebuilds the view automatically
ALTER TABLE t ALTER COLUMN a TYPE bigint;

-- Verify the view is still valid and the column type has been updated
SELECT pg_typeof(a) FROM v LIMIT 1;
-- Returns: bigint

\d v
View "public.v"
Column | Type | Collation | Nullable | Default
--------+--------+-----------+----------+---------
a | bigint | | |
b | text | | |
----

=== Cascaded View Dependencies: Ordered Automatic Rebuild

[source,sql]
----
-- Create the base table
CREATE TABLE t (a int, b text);

-- Create two levels of view dependency: v2 depends on v1, v1 depends on t
CREATE VIEW v1 AS SELECT a, b FROM t;
CREATE VIEW v2 AS SELECT a FROM v1;

-- Change the column type; v1 and v2 are automatically rebuilt in dependency order
ALTER TABLE t ALTER COLUMN a TYPE bigint;

-- Verify both views have been correctly rebuilt
SELECT pg_typeof(a) FROM v1 LIMIT 1;
-- Returns: bigint
pg_typeof
-----------
(0 rows)

SELECT pg_typeof(a) FROM v2 LIMIT 1;
-- Returns: bigint
pg_typeof
-----------
(0 rows)
----

=== Preserving View Options: security_barrier

[source,sql]
----
-- Create a view with the security_barrier option
CREATE VIEW v WITH (security_barrier) AS SELECT a, b FROM t;

ALTER TABLE t ALTER COLUMN a TYPE bigint;

-- Verify the security_barrier option is correctly preserved after rebuild
SELECT relname, reloptions FROM pg_class WHERE relname = 'v';
-- reloptions: {security_barrier=true}
relname | reloptions
---------+-------------------------
v | {security_barrier=true}
(1 row)
----

=== Preserving View Options: WITH CHECK OPTION

[source,sql]
----
-- Create a view with WITH LOCAL CHECK OPTION
CREATE VIEW v AS SELECT a, b FROM t WHERE a > 0
WITH LOCAL CHECK OPTION;

ALTER TABLE t ALTER COLUMN a TYPE bigint;

-- Verify the CHECK OPTION is correctly preserved after rebuild
\d+ v
View "public.v"
Column | Type | Collation | Nullable | Default | Storage | Description
--------+--------+-----------+----------+---------+----------+-------------
a | bigint | | | | plain |
b | text | | | | extended |
View definition:
SELECT t.a,
t.b
FROM t
WHERE t.a > 0;
Options: check_option=local
----

=== Full Rollback on Rebuild Failure

[source,sql]
----
CREATE TABLE t (a int, b text);
CREATE VIEW v AS SELECT a::integer + 1 AS a_plus FROM t;

-- If the new type is incompatible with expressions in the view, the entire operation rolls back.
-- For example, changing a to type text makes the expression a::integer + 1 invalid.
ALTER TABLE t ALTER COLUMN a TYPE text;
-- ERROR: operator does not exist: text + integer
-- HINT: ...
-- ROLLBACK

-- Confirm that the table structure and view are both unaffected
\d t
Table "public.t"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
a | integer | | |
b | text | | |
----

== Limitations

. If a view uses an operator or function incompatible with the new column type (e.g., arithmetic on a `text` column), the rebuild will fail and the
entire `ALTER TABLE` operation will be rolled back;
. Only **views** are automatically rebuilt; **rules** that depend on the affected column will still cause an error;
. The column type change must satisfy PostgreSQL's type casting rules; arbitrary conversions between unrelated types are not supported;
. Views are rebuilt in topological dependency order; circular dependencies (normally prevented by the database) are not handled;
. The rebuild process runs within the same transaction, meaning dependent views are unavailable during the operation — this may affect concurrent
queries in high-concurrency environments.
Loading