> ## 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 是不同的数据库，其用户的需求通常也不同。

<h2 id="capabilities-specific-to-villagesql">
  VillageSQL 特有的功能
</h2>

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

* **密钥环访问**——`vsql::preview::keyring` 允许扩展从服务器的密钥环中读取密钥。
* **扩展私有文件存储**——`vsql::preview::storage` 为扩展提供了一个受管理的磁盘位置。PostgreSQL 扩展自行管理其文件，没有相应的服务器端 API。
* **备用协议处理程序**——[#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 上的逻辑解码及其订阅机制覆盖了类似的领域，这是一种服务于相似目的的不同设计。

<h2 id="how-to-read-the-tables">
  如何阅读这些表格
</h2>

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

每一个未标记为**可用**的行都链接到跟踪和讨论该项工作的 GitHub Issue。

任何通过预览功能标记为**可用**的项都需要 `vsql_allow_preview_extensions = ON`——请参阅[预览功能](/docs/zh/mysql-8.4/stable/preview-capabilities)。

<h2 id="c-and-rust">
  C++ 和 Rust
</h2>

您可以使用 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  | 是       | 尚不支持——[rust-sdk#37](https://github.com/villagesql/vsql-rust-sdk/issues/37) |
| 语句完成事件     | 是       | 尚不支持——[rust-sdk#37](https://github.com/villagesql/vsql-rust-sdk/issues/37) |
| 身份验证方法     | 是       | 尚不支持——[rust-sdk#37](https://github.com/villagesql/vsql-rust-sdk/issues/37) |
| 扩展私有存储     | 是       | 尚不支持——[rust-sdk#37](https://github.com/villagesql/vsql-rust-sdk/issues/37) |

<h2 id="pluggable-interfaces">
  可插拔接口
</h2>

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

| PostgreSQL 接口         | 作用                             | VillageSQL                                                                                                                                                                                                                                                                       |
| --------------------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `_PG_init`、`_PG_fini` | 在模块加载时运行设置，在卸载时运行清理            | **可用**——扩展构建器上的 `on_init()` 和 `on_deinit()`                                                                                                                                                                                                                                      |
| 自定义数据类型和运算符           | 注册一个具有自身存储和比较行为的新基础类型          | **可用**——请参阅 [C++ 中的自定义类型](/docs/zh/mysql-8.4/stable/custom-types)                                                                                                                                                                                                                     |
| 聚合函数                  | 注册一个用户定义的聚合                    | **可用**——`make_aggregate_func`，请参阅 [C++ 开发](/docs/zh/mysql-8.4/stable/development)                                                                                                                                                                                                     |
| 自定义配置变量               | 定义运维人员可以在运行时更改的设置，以及他们可以读取的计数器 | **可用**——`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)                                                                                                                                                                                                          |

与 `_PG_init` 不同，`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))。

<h2 id="hook-variables">
  钩子变量
</h2>

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

<h3 id="parsing-and-ddl">
  解析和 DDL
</h3>

| 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) |

<h3 id="planner">
  规划器
</h3>

| 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) |

<h3 id="executor">
  执行器
</h3>

| 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`，执行后阶段                          |
| `ExecutorCheckPerms_hook` | 批准或拒绝语句所需的表和列权限       | 计划中——[#314](https://github.com/villagesql/villagesql-server/issues/314) |

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

<h3 id="explain">
  EXPLAIN
</h3>

| 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) |

<h3 id="authentication-and-security">
  身份验证和安全
</h3>

| PostgreSQL 钩子                                                                | 作用                           | VillageSQL                                                              |
| ---------------------------------------------------------------------------- | ---------------------------- | ----------------------------------------------------------------------- |
| `ClientAuthentication_hook`                                                  | 参与身份验证，并观察其结果                | **部分可用**——请参阅下文                                                         |
| `check_password_hook`                                                        | 在设置密码时强制执行密码策略               | 计划中——[#456](https://github.com/villagesql/villagesql-server/issues/456) |
| `ldap_password_hook`                                                         | 替换 `ldap` 身份验证方法所使用的 LDAP 绑定 | **可用**——使用 `vsql::preview::auth` 实现该方法本身                                |
| `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()` 允许身份验证插件在解析出外部身份后为会话分配角色，而 `auto_grant_roles()` 注册一个回调，根据令牌的声明自动授予角色。两者都声明在 `villagesql/sdk/include/villagesql/preview/auth.h` 中。

<h3 id="logging">
  日志记录
</h3>

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

<h3 id="startup-and-shared-memory">
  启动和共享内存
</h3>

| 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) |

<h3 id="function-manager">
  函数管理器
</h3>

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

<h2 id="tell-us-what-you-need">
  告诉我们您需要什么
</h2>

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