# 2BP01 — dependent_objects_still_exist（依赖对象仍存在）

> PostgreSQL SQLSTATE 2BP01：依赖对象 DROP 的诊断与有边界修复。
---

# 2BP01 — dependent_objects_still_exist（依赖对象仍存在）

## 速览 {#at-a-glance}

`2BP01` 表示 DROP 或相关目录操作要移除的对象仍被其他数据库对象依赖。正确处理是先理解依赖关系，决定依赖对象应保留还是删除，再重试原操作。

<!-- BEGIN SQLSTATE FACTS: generated by scripts/generate.py; do not edit -->

| 字段 | 值 |
| --- | --- |
| SQLSTATE | `2BP01` |
| 条件名 | `dependent_objects_still_exist` |
| 状态 | `有效` |
| 已知存在于 | `7.4` |
| 锁定快照 | `9.0.23, 9.1.24, 9.2.24, 9.3.25, 9.4.26, 9.5.25, 9.6.24, 10.23, 11.22, 12.22, 13.23, 14.24, 15.19, 16.15, 17.11, 18.6, 19beta3` |
| 宏 | `ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST` |
| 别名 | `—` |

<!-- source facts: data/errcodes/2BP01.json -->
<!-- END SQLSTATE FACTS -->

## 含义 {#meaning}

依赖遍历器会在对象仍被其他对象需要时发出 `2BP01`。代表路径中视图依赖表，因此 `DROP TABLE` 不能执行。主报文、DETAIL 和 CASCADE 提示都根据对象描述和依赖图动态组装。`2BP01` 讨论的是依赖对象；依赖权限描述符的 `2B000` 是另一种条件。

## 诊断 {#diagnosis}

同时保存 SQLSTATE、主报文、DETAIL 和 HINT。选定路径的 DETAIL 会指出依赖视图。选择修复前检查视图定义和依赖元数据；`pg_depend` 与 `pg_get_viewdef()` 可以说明对象为什么仍被保留。在选定的显式 `BEGIN` 块中，收到该 ERROR 后连接会在 `ROLLBACK` 前处于 `INERROR`；自动提交语句没有需要保留的外层事务。不能在失败的显式块中继续查询目录来完成可靠诊断。

## 处理 {#response}

先回滚失败的显式事务。如果视图确实可以删除，先删视图，再删表；如果视图属于模式契约，就保留它并改写迁移方案。`CASCADE` 是删除依赖对象的明确请求，可能超过预期变更，因此不能把 HINT 自动当成执行指令。完成有边界的修复后，重新执行完整 DDL 计划并核对仍应存在的对象。

## 报文 {#messages}

选定源码分支的模板为 `cannot drop %s because other objects depend on it`，DETAIL 是动态内部文本，HINT 为 `Use DROP ... CASCADE to drop the dependent objects too.`。对象描述和依赖列表都是运行时值，不要把 DETAIL 当成固定的单对象模板，也不要假设所有 2BP01 路径都使用同一措辞。

## 代表案例 {#case}

运行器从 `verify/cases/2BP01/snippets.json`（SHA-256 `899e4fd9fb002fc293bd9efee0204e4f2622968c6d9460ad05eb9a0ebd3bac69`）读取下面的依赖序列；失败 DROP 使用显式 `BEGIN`/`ROLLBACK`，修复先删已知视图再删表，完全不使用 CASCADE。见[公开案例导出](../../data/cases/2bp01.json)和[结构化证据](../../data/evidence/2bp01.json)。

<!-- BEGIN SQLSTATE SNIPPET: dependent_object_drop_recovery -->

```sql
CREATE TABLE base_items(id integer PRIMARY KEY, payload text NOT NULL);
CREATE VIEW dependent_view AS SELECT id, payload FROM base_items;
BEGIN;
DROP TABLE base_items;
ROLLBACK;
DROP VIEW dependent_view;
DROP TABLE base_items;
SELECT to_regclass('base_items'), to_regclass('dependent_view');
```
<!-- END SQLSTATE SNIPPET -->

运行器会在私有 schema 中为 registry 名称加限定名。最后两个 `to_regclass` 都返回 null，证明删除的是预期对象，而不是对未知依赖图静默级联。

选定案例在 PostgreSQL 18.6 和 10.21 观察到 `2BP01`。`DROP TABLE` 的 DETAIL 指出依赖视图并给出 CASCADE 提示；显式事务进入 `INERROR`，`ROLLBACK` 恢复为 `IDLE`，随后先删视图再删表完成修复。

## 版本 {#versions}

目录从早期历史边界到正式快照都记录了该条件。18.6 固定源码还包括依赖、共享依赖、角色、权限、类型表和表空间等分支；运行案例只覆盖 18.6 与 10.21 的普通视图到表依赖。不能据此推断所有分支的 CASCADE 都安全。

## 相关 {#related}

可对照[2B000 依赖权限描述符仍存在](../2b000/)和[42P01 表不存在](../42p01/)。

## 来源 {#sources}

- [`src.errcodes.18.6`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/errcodes.txt)（SHA-256 `6e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba`）
- [`src.dependency.18.6`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/catalog/dependency.c#L1148-L1154)（SHA-256 `1878f848dae03e08424a47a09508f3443227ad67c4bc5e0aba3ec9655d015b74`）
- [`DROP TABLE 官方文档`](https://www.postgresql.org/docs/18/sql-droptable.html) · 本地调用扫描 `src.calls.REL_18_6`（SHA-256 `9ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf`）
