Force View
1. 目的
-
Force View 提供 Oracle 兼容的
CREATE [OR REPLACE] FORCE VIEW与ALTER VIEW … COMPILE行为,允许开发者先落地视图占位,再在依赖补齐后恢复正常执行。 -
系统将原始 SQL 及标识符大小写模式写入专属目录项,依赖恢复时可自动或手动编译为普通视图,且保持 Oracle 风格的告警与错误提示。
2. 实现说明
PG在删除基表时,如果有视图依赖于此基表,则不允许删除,需要使用cascade 关键字全部删除;Oracle删除基表时,允许直接删除基表,而保留force view并将force view 转为无效状态,且创建普通视图后,也可以删除此视图的基表,但把视图转为无效状态。
为了支持新的语法,需要增加对应的语法规则。且FORCE VIEW的状态在多个session之间是共享的,新增一张系统表用来存储FORCE VIEW的相关信息。
2.1. 语法与解析入口
2.1.1. Force View 语法支持
-
src/backend/oracle_parser/ora_gram.y注册 Force View 关键字。 -
语法阶段为
ViewStmt→force赋值,并在AlterTableStmt阶段生成AT_ForceViewCompile选项。 -
解析阶段保留
ViewStmt→stmt_literal,后续占位时需要复用原始文本。
/* Insert or update the pg_force_view catalog as needed */
if (need_store)
{
......
StoreForceViewQuery(address.objectId, stmt->replace, ident_case, stmt->stmt_literal ? stmt->stmt_literal : queryString);
}
2.2. Force View 元数据
2.2.1. pg_force_view 目录
-
src/include/catalog/pg_force_view.h定义目录表,字段包含视图 OID (fvoid)、标识符大小写模式 (ident_case)、原始 SQL 文本 (source)。 -
唯一索引
pg_force_view_fvoid_index搭配 syscacheFORCEVIEWOID(src/include/catalog/syscache_info.h)实现按视图 OID 查找。 -
目录表开启 TOAST,长 SQL 文本不会被截断,可覆盖复杂迁移脚本。
CATALOG(pg_force_view,9120,ForceViewRelationId)
{
/* oid of force view */
Oid fvoid;
/* see IDENT_CASE__xxx constants below */
char ident_case;
#ifdef CATALOG_VARLEN /* variable-length fields start here */
/* sql definition */
text source;
#endif
} FormData_pg_force_view;
2.3. 创建与替换流程
2.3.1. 普通 view
-
DefineView()在解析成功后调用DefineVirtualRelation()写入pg_class、pg_attribute等结构。 -
StoreViewQuery()生成_RETURN规则并维护依赖关系。 -
该路径不会触及
pg_force_view,视图完成后立即可用。
2.3.2. Force view
-
CreateForceVirtualPlaceholder()(src/backend/commands/view.c)负责生成或复用占位视图: -
若视图不存在,调用
DefineVirtualRelation()建立基础对象,但不写入_RETURN规则。 -
若已有 Force View,复用当前记录,更新列定义或清理旧元数据。
-
若已有普通视图且声明了
OR REPLACE,调用make_view_invalid()失效原视图,再写入新的占位定义。 -
StoreForceViewQuery()将stmt_literal与当前ivorysql.identifier_case_switch持久化到pg_force_view,以便后续恢复大小写语义。 -
视图占位完成后向客户端返回
WARNING: View created with compilation errors,提示仍处于不可用状态。
2.4. 依赖失效与回退
2.5. 自动与主动编译
2.5.1. 自动编译触发点
-
parse_relation.c的addRangeTableEntry()和parse_clause.c的目标关系打开逻辑在判定 Force View 后调用compile_force_view()。 -
该函数重新执行
raw_parser与parse_analyze,成功则再安装_RETURN规则,失败直接终止当前语句。