From bb5c49af0379c6225b458704c5850f48619f3c46 Mon Sep 17 00:00:00 2001 From: Steven Niu Date: Wed, 1 Apr 2026 13:40:13 +0800 Subject: [PATCH] docs(v1.17): rebuild view after column type changed --- CN/modules/ROOT/nav.adoc | 1 + CN/modules/ROOT/pages/v1.17/42.adoc | 170 +++++++++++++++++++++++++++ EN/modules/ROOT/nav.adoc | 3 +- EN/modules/ROOT/pages/v1.17/42.adoc | 171 ++++++++++++++++++++++++++++ 4 files changed, 344 insertions(+), 1 deletion(-) create mode 100644 CN/modules/ROOT/pages/v1.17/42.adoc create mode 100644 EN/modules/ROOT/pages/v1.17/42.adoc diff --git a/CN/modules/ROOT/nav.adoc b/CN/modules/ROOT/nav.adoc index 9cbb16e..3bf1bce 100644 --- a/CN/modules/ROOT/nav.adoc +++ b/CN/modules/ROOT/nav.adoc @@ -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] diff --git a/CN/modules/ROOT/pages/v1.17/42.adoc b/CN/modules/ROOT/pages/v1.17/42.adoc new file mode 100644 index 0000000..8c6f6b9 --- /dev/null +++ b/CN/modules/ROOT/pages/v1.17/42.adoc @@ -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 类型转换规则,不支持任意两种类型之间的直接转换; +. 视图重建按依赖拓扑顺序执行,循环依赖(通常由数据库约束避免)不在处理范围内; +. 重建过程在同一事务内完成,期间依赖视图处于不可用状态,高并发场景下需注意对查询的影响。 \ No newline at end of file diff --git a/EN/modules/ROOT/nav.adoc b/EN/modules/ROOT/nav.adoc index 0a6fa95..774d4b7 100644 --- a/EN/modules/ROOT/nav.adoc +++ b/EN/modules/ROOT/nav.adoc @@ -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] \ No newline at end of file +* xref:v1.17/22.adoc[FAQ] diff --git a/EN/modules/ROOT/pages/v1.17/42.adoc b/EN/modules/ROOT/pages/v1.17/42.adoc new file mode 100644 index 0000000..df0c47f --- /dev/null +++ b/EN/modules/ROOT/pages/v1.17/42.adoc @@ -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. \ No newline at end of file