Skip to content

Commit bb886b5

Browse files
committed
support rebuild-view-after-column-type-changed
1 parent ed23d32 commit bb886b5

File tree

4 files changed

+344
-1
lines changed

4 files changed

+344
-1
lines changed

CN/modules/ROOT/nav.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
* IvorySQL试验田
3333
** xref:v1.17/41.adoc[1、全局唯一索引]
3434
** xref:v1.17/42.adoc[2、新增无主键表默认支持逻辑复制]
35+
** xref:v1.17/43.adoc[3、修改列类型时自动重建依赖视图]
3536
* xref:v1.17/20.adoc[社区贡献指南]
3637
* xref:v1.17/21.adoc[工具参考]
3738
* xref:v1.17/22.adoc[FAQ]
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
:sectnums:
2+
:sectnumlevels: 5
3+
4+
:imagesdir: ./_images
5+
6+
= 修改列类型时自动重建依赖视图
7+
8+
== 功能介绍
9+
10+
在标准 PostgreSQL 中,若某列被视图所引用,执行 `ALTER TABLE ... ALTER COLUMN ... TYPE` 修改该列的数据类型时,数据库会直接报错:
11+
12+
----
13+
ERROR: cannot alter type of a column used by a view or rule
14+
----
15+
16+
用户必须手动删除所有依赖视图,完成列类型修改后再逐一重建,操作繁琐且容易出错,在存在多层视图依赖时尤为困难。
17+
18+
IvorySQL 对此行为进行了增强:执行列类型变更时,数据库会自动保存所有依赖视图(包括间接依赖的级联视图)的定义,在完成类型修改后按正确顺序重建这些视图
19+
,对用户完全透明。若重建过程中发生错误(例如视图使用了新类型不支持的操作符),整个 `ALTER TABLE` 操作将整体回滚,保证数据一致性。
20+
21+
该功能同时支持 PG 兼容模式与 Oracle 兼容模式。
22+
23+
== 语法
24+
25+
语法与标准 `ALTER TABLE` 完全一致,无需额外关键字:
26+
27+
[source,sql]
28+
----
29+
ALTER TABLE table_name ALTER COLUMN column_name TYPE new_type;
30+
----
31+
32+
参数说明:
33+
34+
- `table_name`:目标表名,可带 schema 前缀;
35+
- `column_name`:需要修改类型的列名;
36+
- `new_type`:目标数据类型,需与原类型兼容或可隐式转换。
37+
38+
== 测试用例
39+
40+
=== 单视图依赖:自动重建
41+
42+
[source,sql]
43+
----
44+
-- 创建基表
45+
CREATE TABLE t (a int, b text);
46+
47+
-- 创建依赖列 a 的视图
48+
CREATE VIEW v AS SELECT a, b FROM t;
49+
50+
-- 标准 PostgreSQL 此处会报错,IvorySQL 自动重建视图
51+
ALTER TABLE t ALTER COLUMN a TYPE bigint;
52+
53+
-- 验证视图仍然有效,且列类型已更新
54+
SELECT pg_typeof(a) FROM v LIMIT 1;
55+
-- 返回 bigint
56+
pg_typeof
57+
-----------
58+
(0 rows)
59+
60+
61+
\d v
62+
View "public.v"
63+
Column | Type | Collation | Nullable | Default
64+
--------+--------+-----------+----------+---------
65+
a | bigint | | |
66+
b | text | | |
67+
----
68+
69+
=== 级联视图依赖:按序自动重建
70+
71+
[source,sql]
72+
----
73+
-- 创建基表
74+
CREATE TABLE t (a int, b text);
75+
76+
-- 创建两层视图依赖:v2 依赖 v1,v1 依赖 t
77+
CREATE VIEW v1 AS SELECT a, b FROM t;
78+
CREATE VIEW v2 AS SELECT a FROM v1;
79+
80+
-- 修改列类型,自动按依赖顺序重建 v1、v2
81+
ALTER TABLE t ALTER COLUMN a TYPE bigint;
82+
83+
-- 验证两个视图均已正确重建
84+
SELECT pg_typeof(a) FROM v1 LIMIT 1;
85+
-- 返回 bigint
86+
pg_typeof
87+
-----------
88+
(0 rows)
89+
90+
SELECT pg_typeof(a) FROM v2 LIMIT 1;
91+
-- 返回 bigint
92+
pg_typeof
93+
-----------
94+
(0 rows)
95+
----
96+
97+
=== 保留视图选项:security_barrier
98+
99+
[source,sql]
100+
----
101+
-- 创建带 security_barrier 选项的视图
102+
CREATE VIEW v WITH (security_barrier) AS SELECT a, b FROM t;
103+
104+
ALTER TABLE t ALTER COLUMN a TYPE bigint;
105+
106+
-- 验证 security_barrier 选项在重建后被正确保留
107+
SELECT relname, reloptions FROM pg_class WHERE relname = 'v';
108+
-- reloptions: {security_barrier=true}
109+
relname | reloptions
110+
---------+-------------------------
111+
v | {security_barrier=true}
112+
(1 row)
113+
----
114+
115+
=== 保留视图选项:WITH CHECK OPTION
116+
117+
[source,sql]
118+
----
119+
-- 创建带 WITH LOCAL CHECK OPTION 的视图
120+
CREATE VIEW v AS SELECT a, b FROM t WHERE a > 0
121+
WITH LOCAL CHECK OPTION;
122+
123+
ALTER TABLE t ALTER COLUMN a TYPE bigint;
124+
125+
-- 验证 CHECK OPTION 在重建后被正确保留
126+
\d+ v
127+
View "public.v"
128+
Column | Type | Collation | Nullable | Default | Storage | Description
129+
--------+--------+-----------+----------+---------+----------+-------------
130+
a | bigint | | | | plain |
131+
b | text | | | | extended |
132+
View definition:
133+
SELECT t.a,
134+
t.b
135+
FROM t
136+
WHERE t.a > 0;
137+
Options: check_option=local
138+
----
139+
140+
=== 重建失败时整体回滚
141+
142+
[source,sql]
143+
----
144+
CREATE TABLE t (a int, b text);
145+
CREATE VIEW v AS SELECT a::integer + 1 AS a_plus FROM t;
146+
147+
-- 若新类型与视图中的表达式不兼容,整个操作回滚
148+
-- 例如将 a 改为 text 类型,视图中的 a::integer + 1 将无法执行
149+
ALTER TABLE t ALTER COLUMN a TYPE text;
150+
ERROR: operator does not exist: text + integer
151+
LINE 1: ALTER TABLE t ALTER COLUMN a TYPE text;
152+
^
153+
HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
154+
155+
-- 确认表结构与视图均未受影响
156+
\d t
157+
Table "public.t"
158+
Column | Type | Collation | Nullable | Default
159+
--------+---------+-----------+----------+---------
160+
a | integer | | |
161+
b | text | | |
162+
----
163+
164+
== 功能限制
165+
166+
. 若视图中使用了与新列类型不兼容的操作符或函数(例如对 `text` 类型列执行算术运算),重建将失败,整个 `ALTER TABLE` 操作回滚;
167+
. 仅支持视图(view)的自动重建,依赖该列的**规则(rule)**仍会报错;
168+
. 列类型变更需满足 PostgreSQL 类型转换规则,不支持任意两种类型之间的直接转换;
169+
. 视图重建按依赖拓扑顺序执行,循环依赖(通常由数据库约束避免)不在处理范围内;
170+
. 重建过程在同一事务内完成,期间依赖视图处于不可用状态,高并发场景下需注意对查询的影响。

EN/modules/ROOT/nav.adoc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
* IvorySQL Experimental Features
3333
** xref:v1.17/41.adoc[1、Global Unique Index]
3434
** xref:v1.17/42.adoc[2、Default Logical Replication Support for Tables Without Primary Key]
35+
** xref:v1.17/43.adoc[3、Rebuild View After Column Type Changed]
3536
* xref:v1.17/20.adoc[Community contribution]
3637
* xref:v1.17/21.adoc[Tool Reference]
37-
* xref:v1.17/22.adoc[FAQ]
38+
* xref:v1.17/22.adoc[FAQ]
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
:sectnums:
2+
:sectnumlevels: 5
3+
4+
:imagesdir: ./_images
5+
6+
= Rebuild View After Column Type Changed
7+
8+
== Feature Overview
9+
10+
In standard PostgreSQL, if a column is referenced by a view, attempting to change its data type via `ALTER TABLE ... ALTER COLUMN ... TYPE` results
11+
in an immediate error:
12+
13+
----
14+
ERROR: cannot alter type of a column used by a view or rule
15+
----
16+
17+
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
18+
error-prone process that becomes particularly difficult when multiple levels of cascaded view dependencies exist.
19+
20+
IvorySQL enhances this behavior: when a column type change is executed, the database automatically saves the definitions of all dependent views
21+
(including indirectly dependent cascaded views), and after completing the type change, rebuilds those views in the correct dependency order —
22+
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
23+
entire `ALTER TABLE` operation is rolled back, ensuring data consistency.
24+
25+
This feature is supported in both PG-compatible mode and Oracle-compatible mode.
26+
27+
== Syntax
28+
29+
The syntax is identical to the standard `ALTER TABLE` — no additional keywords are required:
30+
31+
[source,sql]
32+
----
33+
ALTER TABLE table_name ALTER COLUMN column_name TYPE new_type;
34+
----
35+
36+
Parameter description:
37+
38+
- `table_name`: The target table name, optionally schema-qualified;
39+
- `column_name`: The name of the column whose type is to be changed;
40+
- `new_type`: The target data type, which must be compatible with the original type or implicitly castable.
41+
42+
== Test Cases
43+
44+
=== Single View Dependency: Automatic Rebuild
45+
46+
[source,sql]
47+
----
48+
-- Create the base table
49+
CREATE TABLE t (a int, b text);
50+
51+
-- Create a view that references column a
52+
CREATE VIEW v AS SELECT a, b FROM t;
53+
54+
-- Standard PostgreSQL would error here; IvorySQL rebuilds the view automatically
55+
ALTER TABLE t ALTER COLUMN a TYPE bigint;
56+
57+
-- Verify the view is still valid and the column type has been updated
58+
SELECT pg_typeof(a) FROM v LIMIT 1;
59+
-- Returns: bigint
60+
61+
\d v
62+
View "public.v"
63+
Column | Type | Collation | Nullable | Default
64+
--------+--------+-----------+----------+---------
65+
a | bigint | | |
66+
b | text | | |
67+
----
68+
69+
=== Cascaded View Dependencies: Ordered Automatic Rebuild
70+
71+
[source,sql]
72+
----
73+
-- Create the base table
74+
CREATE TABLE t (a int, b text);
75+
76+
-- Create two levels of view dependency: v2 depends on v1, v1 depends on t
77+
CREATE VIEW v1 AS SELECT a, b FROM t;
78+
CREATE VIEW v2 AS SELECT a FROM v1;
79+
80+
-- Change the column type; v1 and v2 are automatically rebuilt in dependency order
81+
ALTER TABLE t ALTER COLUMN a TYPE bigint;
82+
83+
-- Verify both views have been correctly rebuilt
84+
SELECT pg_typeof(a) FROM v1 LIMIT 1;
85+
-- Returns: bigint
86+
pg_typeof
87+
-----------
88+
(0 rows)
89+
90+
SELECT pg_typeof(a) FROM v2 LIMIT 1;
91+
-- Returns: bigint
92+
pg_typeof
93+
-----------
94+
(0 rows)
95+
----
96+
97+
=== Preserving View Options: security_barrier
98+
99+
[source,sql]
100+
----
101+
-- Create a view with the security_barrier option
102+
CREATE VIEW v WITH (security_barrier) AS SELECT a, b FROM t;
103+
104+
ALTER TABLE t ALTER COLUMN a TYPE bigint;
105+
106+
-- Verify the security_barrier option is correctly preserved after rebuild
107+
SELECT relname, reloptions FROM pg_class WHERE relname = 'v';
108+
-- reloptions: {security_barrier=true}
109+
relname | reloptions
110+
---------+-------------------------
111+
v | {security_barrier=true}
112+
(1 row)
113+
----
114+
115+
=== Preserving View Options: WITH CHECK OPTION
116+
117+
[source,sql]
118+
----
119+
-- Create a view with WITH LOCAL CHECK OPTION
120+
CREATE VIEW v AS SELECT a, b FROM t WHERE a > 0
121+
WITH LOCAL CHECK OPTION;
122+
123+
ALTER TABLE t ALTER COLUMN a TYPE bigint;
124+
125+
-- Verify the CHECK OPTION is correctly preserved after rebuild
126+
\d+ v
127+
View "public.v"
128+
Column | Type | Collation | Nullable | Default | Storage | Description
129+
--------+--------+-----------+----------+---------+----------+-------------
130+
a | bigint | | | | plain |
131+
b | text | | | | extended |
132+
View definition:
133+
SELECT t.a,
134+
t.b
135+
FROM t
136+
WHERE t.a > 0;
137+
Options: check_option=local
138+
----
139+
140+
=== Full Rollback on Rebuild Failure
141+
142+
[source,sql]
143+
----
144+
CREATE TABLE t (a int, b text);
145+
CREATE VIEW v AS SELECT a::integer + 1 AS a_plus FROM t;
146+
147+
-- If the new type is incompatible with expressions in the view, the entire operation rolls back.
148+
-- For example, changing a to type text makes the expression a::integer + 1 invalid.
149+
ALTER TABLE t ALTER COLUMN a TYPE text;
150+
-- ERROR: operator does not exist: text + integer
151+
-- HINT: ...
152+
-- ROLLBACK
153+
154+
-- Confirm that the table structure and view are both unaffected
155+
\d t
156+
Table "public.t"
157+
Column | Type | Collation | Nullable | Default
158+
--------+---------+-----------+----------+---------
159+
a | integer | | |
160+
b | text | | |
161+
----
162+
163+
== Limitations
164+
165+
. 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
166+
entire `ALTER TABLE` operation will be rolled back;
167+
. Only **views** are automatically rebuilt; **rules** that depend on the affected column will still cause an error;
168+
. The column type change must satisfy PostgreSQL's type casting rules; arbitrary conversions between unrelated types are not supported;
169+
. Views are rebuilt in topological dependency order; circular dependencies (normally prevented by the database) are not handled;
170+
. The rebuild process runs within the same transaction, meaning dependent views are unavailable during the operation — this may affect concurrent
171+
queries in high-concurrency environments.

0 commit comments

Comments
 (0)