> ## Documentation Index
> Fetch the complete documentation index at: https://villagesql.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 与 PostgreSQL 相比的 VEF 覆盖范围

> 本页将 VillageSQL 扩展框架与 PostgreSQL 的扩展框架进行比较，展示 VEF 目前支持哪些接口和钩子，以及剩余工作的跟踪位置。

VillageSQL 扩展框架 (VEF) 以一种明确定义的方式，让扩展能够访问数据库的内部工作机制。PostgreSQL 拥有所有开源数据库中最成熟的扩展框架，因此本页以它作为参照点，让您了解 VEF 当前和计划中的功能。

您应该将本页视为一个快照，而不是最终状态。VEF 会随每个版本发生变化。精确匹配 PostgreSQL 的钩子功能并不是目标。MySQL 和 PostgreSQL 是不同的数据库，其用户的需求通常也不同。

## VillageSQL 特有的功能

VEF 提供的某些内容在下面的表格中没有可比较的对象，这或者是因为 MySQL 的构建方式不同，或者是因为 VillageSQL 扩展作者需要一些 PostgreSQL 并未提供给其自身扩展的东西。

* **密钥环访问**——`vsql::preview::keyring` 允许扩展从服务器的密钥环中读取密钥。
* **InnoDB 页存储**——`vsql::preview::storage` 允许扩展创建 InnoDB 段，并通过缓冲池读写其页面，同时带有重做日志记录。
* **备用协议处理程序**——[#299](https://github.com/villagesql/villagesql-server/issues/299) 将允许扩展通过 MySQL 线路协议之外的方式为客户端提供服务。

另有两项功能因 MySQL 的构建方式而被列入计划。二进制日志写入和刷新观察 ([#297](https://github.com/villagesql/villagesql-server/issues/297)) 以及复制通道观察 ([#341](https://github.com/villagesql/villagesql-server/issues/341)) 都会读取 MySQL 的二进制日志及其多源复制通道。PostgreSQL 通过 WAL 上的逻辑解码及其订阅机制覆盖了类似的领域，这是一种服务于相似目的的不同设计。

## 如何阅读这些表格

| 状态 | 含义 |
| - | - |
| **可用** | 您今天就可以在扩展中执行此操作。该行给出了提供此能力的功能或 SDK 函数。 |
| **部分可用** | 其中一部分目前可用。该行或表格下方的说明会指出缺少什么。 |
| **进行中** | 部分工作已经落地。链接的 Issue 承载了其余部分。 |
| **计划中** | 尚不可用。链接的 Issue 跟踪该项工作。 |

每一个未标记为**可用**的行都链接到跟踪和讨论该项工作的 GitHub Issue，链接位于该行中或表格下方的说明中。

任何通过预览功能标记为**可用**的项都需要 `vsql_allow_preview_extensions = ON`——请参阅[预览功能](https://villagesql.com/docs/zh/extensions/build/preview-capabilities.md)。`vsql::preview::auth` 和 `vsql::preview::statement_event` 还仅对基于开发版 ABI（`-DVSQL_USE_DEV_ABI=ON`）构建的扩展可用。

## C++ 和 Rust

您可以使用 C++ 或 Rust 编写 VillageSQL 扩展。VEF 是服务器端的能力，而每个 SDK 都是它之上的绑定；Rust 绑定较新，因此目前有少数功能仅能从 C++ 访问。

| 功能 | C++ SDK | Rust SDK |
| - | - | - |
| 标量函数 (VDF) | 是 | 是 |
| 自定义类型 | 是 | 是 |
| 系统变量和状态变量 | 是 | 是 |
| 后台工作器 | 是 | 是 |
| 密钥环访问 | 是 | 是 |
| 聚合函数 | 是 | 是 |
| 加载和卸载回调 | 是 | 尚不支持——[rust-sdk#13](https://github.com/villagesql/vsql-rust-sdk/issues/13) |
| 从扩展运行 SQL | 是 | 是 |
| 语句完成事件 | 是（仅限开发版 ABI） | 尚不支持——[rust-sdk#37](https://github.com/villagesql/vsql-rust-sdk/issues/37) |
| 身份验证方法 | 是（仅限开发版 ABI） | 尚不支持——[rust-sdk#37](https://github.com/villagesql/vsql-rust-sdk/issues/37) |
| InnoDB 页存储 | 是 | 尚不支持——[rust-sdk#37](https://github.com/villagesql/vsql-rust-sdk/issues/37) |

## 可插拔接口

最知名的 PostgreSQL 扩展是构建在这些接口之上的，而不是构建在下文的钩子之上。它们也是 VEF 覆盖得最完整的框架部分，因此请从这里开始。

| PostgreSQL 接口 | 作用 | VillageSQL |
| - | - | - |
| `_PG_init`、`_PG_fini` | 在模块加载时运行设置，在卸载时运行清理 | **可用**——扩展构建器上的 `on_init()` 和 `on_deinit()`，位于开发版 ABI 头文件中（`-DVSQL_USE_DEV_ABI=ON`） |
| 自定义数据类型和运算符 | 注册一个具有自身存储和比较行为的新基础类型 | **可用**——请参阅[自定义类型](https://villagesql.com/docs/zh/sdk/cpp/custom-types.md) |
| 聚合函数 | 注册一个用户定义的聚合 | **可用**——`make_aggregate_func`，请参阅[开发指南](https://villagesql.com/docs/zh/sdk/cpp/development.md) |
| 自定义配置变量 | 定义运维人员可以在运行时更改的设置，以及他们可以读取的计数器 | **可用**——`vsql::sys_var` 用于设置，`vsql::status_var` 用于计数器 |
| 后台工作器 | 在服务器内部运行一个长期存在的进程，并具有数据库访问权限 | **可用**——`vsql::preview::thread_worker` |
| SPI（从服务器内部运行 SQL） | 从扩展代码执行 SQL | **部分可用**——`vsql::preview::sql_query`，具有下文所述的限制 |
| 返回结果集的函数 | 从函数返回一个结果集 | 计划中——[#549](https://github.com/villagesql/villagesql-server/issues/549) |
| 用 C 编写的过程 | 将某个操作公开为 `CALL`，而不是标量函数 | 计划中——[#596](https://github.com/villagesql/villagesql-server/issues/596) |
| 索引访问方法 | 注册一个完整的索引类型，包含构建、维护和搜索 | 进行中——[#264](https://github.com/villagesql/villagesql-server/issues/264)、[#265](https://github.com/villagesql/villagesql-server/issues/265)、[#266](https://github.com/villagesql/villagesql-server/issues/266)、[#268](https://github.com/villagesql/villagesql-server/issues/268) |
| 自定义扫描提供程序 | 向执行器添加由扩展定义的节点 | 计划中——[#276](https://github.com/villagesql/villagesql-server/issues/276) |
| 表访问方法 | 替换行存储、可见性和 vacuum 行为 | 计划中——[#290](https://github.com/villagesql/villagesql-server/issues/290)、[#291](https://github.com/villagesql/villagesql-server/issues/291)、[#292](https://github.com/villagesql/villagesql-server/issues/292) |
| 外部数据包装器 | 将外部系统公开为表，支持谓词下推和写入 | 计划中——[#277](https://github.com/villagesql/villagesql-server/issues/277)、[#278](https://github.com/villagesql/villagesql-server/issues/278)、[#279](https://github.com/villagesql/villagesql-server/issues/279)、[#280](https://github.com/villagesql/villagesql-server/issues/280) |
| 逻辑解码输出插件 | 消费行变更流 | 计划中——[#283](https://github.com/villagesql/villagesql-server/issues/283)、[#284](https://github.com/villagesql/villagesql-server/issues/284)、[#285](https://github.com/villagesql/villagesql-server/issues/285) |
| 用于扩展状态的系统视图 | 将扩展状态发布为可查询的表 | 计划中——[#271](https://github.com/villagesql/villagesql-server/issues/271) |
| 过程式语言 | 为存储例程添加语言运行时 | 计划中——[#342](https://github.com/villagesql/villagesql-server/issues/342) |

`on_init()` 和 `on_deinit()` 在扩展所声明的功能处于可用状态时运行：`on_init()` 在服务器填充这些功能之后运行，`on_deinit()` 在服务器清除它们之前运行，因此钩子可以读取已注册的系统变量。它们也适合本地设置，例如选择特定于 CPU 的函数指针。

`vsql::preview::sql_query` 有三项限制，会影响任何围绕 SPI 构建的扩展。语句不接受绑定参数，因此必须手动转义值 ([#627](https://github.com/villagesql/villagesql-server/issues/627))。扩展获得的是单个会话，而不是并发会话 ([#626](https://github.com/villagesql/villagesql-server/issues/626))。并且它不能从 VDF 内部调用 ([#597](https://github.com/villagesql/villagesql-server/issues/597))。

## 钩子变量

钩子是服务器在语句执行过程中将控制权交给扩展的一个点，让扩展能够读取或改变服务器即将执行的操作。PostgreSQL 将一组固定的钩子声明为全局函数指针；下面的表格涵盖了所有这些钩子，并按每个钩子触发所处的查询处理阶段进行分组。

### 解析和 DDL

| PostgreSQL 钩子 | 作用 | VillageSQL |
| - | - | - |
| `post_parse_analyze_hook` | 在解析分析之后检查或重写语句 | 计划中——[#701](https://github.com/villagesql/villagesql-server/issues/701) |
| `ProcessUtility_hook` | 在 DDL 和其他实用语句运行之前拦截、阻止或重定向它们 | 计划中——[#272](https://github.com/villagesql/villagesql-server/issues/272) |
| `object_access_hook`、`object_access_hook_str` | 在目录对象被创建、修改、删除或访问时收到通知 | 计划中——[#270](https://github.com/villagesql/villagesql-server/issues/270) |

### 规划器

| PostgreSQL 钩子 | 作用 | VillageSQL |
| - | - | - |
| `planner_hook` | 包装或替换某条语句的规划器 | 计划中——[#275](https://github.com/villagesql/villagesql-server/issues/275) |
| `set_rel_pathlist_hook` | 为单个表添加或移除候选扫描路径 | 计划中——[#275](https://github.com/villagesql/villagesql-server/issues/275) |
| `set_join_pathlist_hook` | 添加或移除候选连接路径 | 计划中——[#275](https://github.com/villagesql/villagesql-server/issues/275) |
| `join_search_hook` | 替换连接顺序搜索本身 | 计划中——[#275](https://github.com/villagesql/villagesql-server/issues/275) |
| `create_upper_paths_hook` | 为扫描之后的阶段（例如分组和排序）添加路径 | 计划中——[#275](https://github.com/villagesql/villagesql-server/issues/275) |
| `get_relation_info_hook` | 调整规划器看到的关系和索引元数据 | 计划中——[#268](https://github.com/villagesql/villagesql-server/issues/268) |
| `get_relation_stats_hook`、`get_index_stats_hook` | 为某个列或索引提供统计信息，以替代目录中的统计信息 | 计划中——[#274](https://github.com/villagesql/villagesql-server/issues/274) |
| `get_attavgwidth_hook` | 为成本估算提供平均列宽 | 计划中——[#274](https://github.com/villagesql/villagesql-server/issues/274) |

### 执行器

| PostgreSQL 钩子 | 作用 | VillageSQL |
| - | - | - |
| `ExecutorStart_hook` | 在查询开始执行之前运行 | 计划中——[#702](https://github.com/villagesql/villagesql-server/issues/702) |
| `ExecutorRun_hook` | 包装行的产生过程，用于掩码、转换或按行记账 | 计划中——[#289](https://github.com/villagesql/villagesql-server/issues/289) |
| `ExecutorFinish_hook` | 在最后一行之后、拆除之前运行 | 计划中——[#287](https://github.com/villagesql/villagesql-server/issues/287) |
| `ExecutorEnd_hook` | 观察已完成的语句及其执行统计信息 | **可用**——`vsql::preview::statement_event`，执行后阶段（仅限开发版 ABI） |
| `ExecutorCheckPerms_hook` | 批准或拒绝语句所需的表和列权限 | 计划中——[#314](https://github.com/villagesql/villagesql-server/issues/314) |

需要按算子级别细节的 PostgreSQL 扩展，通过在节点级别包装 `ExecutorRun_hook` 来获得它。在 VEF 中，这是单独的工作，跟踪于 [#340](https://github.com/villagesql/villagesql-server/issues/340)。

### EXPLAIN

| PostgreSQL 钩子 | 作用 | VillageSQL |
| - | - | - |
| `ExplainOneQuery_hook` | 替换或扩展语句的解释方式 | 计划中——[#317](https://github.com/villagesql/villagesql-server/issues/317) |
| `explain_per_plan_hook` | 为每个被解释的计划添加一次扩展输出 | 计划中——[#317](https://github.com/villagesql/villagesql-server/issues/317) |
| `explain_per_node_hook` | 为每个计划节点添加扩展输出 | 计划中——[#317](https://github.com/villagesql/villagesql-server/issues/317) |
| `explain_get_index_name_hook` | 覆盖输出中显示的索引名称 | 计划中——[#317](https://github.com/villagesql/villagesql-server/issues/317) |
| `explain_validate_options_hook` | 接受由扩展定义的 `EXPLAIN` 选项 | 计划中——[#317](https://github.com/villagesql/villagesql-server/issues/317) |

### 身份验证和安全

| PostgreSQL 钩子 | 作用 | VillageSQL |
| - | - | - |
| `ClientAuthentication_hook` | 参与身份验证，并观察其结果 | **部分可用**——请参阅下文；身份验证功能仅限开发版 ABI |
| `check_password_hook` | 在设置密码时强制执行密码策略 | 计划中——[#456](https://github.com/villagesql/villagesql-server/issues/456) |
| `ldap_password_hook` | 替换 `ldap` 身份验证方法所使用的 LDAP 绑定 | **可用**——使用 `vsql::preview::auth` 实现该方法本身（仅限开发版 ABI） |
| `openssl_tls_init_hook` | 在启动时调整服务器的 TLS 上下文 | 计划中——[#458](https://github.com/villagesql/villagesql-server/issues/458) |
| `row_security_policy_hook_permissive`、`row_security_policy_hook_restrictive` | 根据会话向查询添加行过滤谓词 | 计划中——[#315](https://github.com/villagesql/villagesql-server/issues/315) |

PostgreSQL 扩展将 `ClientAuthentication_hook` 用于两种不同的工作，而 VEF 覆盖了其中一种。扩展可以通过 `vsql::preview::auth` 功能实现自己的身份验证方法，`vsql-oauth2` 就是基于此构建的。它还不能观察并非由自己处理的身份验证的结果，而 PostgreSQL 的 `auth_delay` 和失败登录跟踪器正是这样工作的。这部分是 [#464](https://github.com/villagesql/villagesql-server/issues/464)。

PostgreSQL 通过 `pg_ident.conf` 而不是钩子，将外部身份映射到数据库账户。VEF 通过同一个 `vsql::preview::auth` 功能覆盖了这一点：`set_active_roles()` 允许身份验证插件在解析出外部身份后为会话暂存角色，而 `roles_mode()` 注册一个在每次登录时重新查询的回调，由它决定服务器是仅激活暂存的角色、同时授予这些角色，还是同步账户的授权以与之匹配（运维人员固定的 `DEFAULT ROLE` 在同步后仍会保留）。两者都声明在 `villagesql/sdk/include/villagesql/preview/auth.h` 中。

### 日志记录

| PostgreSQL 钩子 | 作用 | VillageSQL |
| - | - | - |
| `emit_log_hook` | 在每条日志消息写入之前查看它，并对其进行过滤或重新路由 | 计划中——[#316](https://github.com/villagesql/villagesql-server/issues/316) |

### 启动和共享内存

| PostgreSQL 钩子 | 作用 | VillageSQL |
| - | - | - |
| `shmem_request_hook` | 在启动期间请求共享内存 | 计划中——[#282](https://github.com/villagesql/villagesql-server/issues/282) |
| `shmem_startup_hook` | 在共享内存存在后对其进行初始化 | 计划中——[#282](https://github.com/villagesql/villagesql-server/issues/282) |

### 函数管理器

| PostgreSQL 钩子 | 作用 | VillageSQL |
| - | - | - |
| `fmgr_hook`、`needs_fmgr_hook` | 在每次函数调用前后运行代码，用于审计或沙箱化 | 计划中——[#287](https://github.com/villagesql/villagesql-server/issues/287) |

## 告诉我们您需要什么

我们根据扩展作者的需求来确定这项工作的优先级。如果上面的某一项阻碍了您想要构建的扩展，请为其 Issue 点赞 👍，并在评论中描述您的用例。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.