Files
sap-cli-skill/references/error-handling.md
T
吴让宇 a58275aa51 docs(rules): 补 ADT Data Preview SQL 方言实测约束
真机侦察(S4T / NW 7.40)确认 data preview freestyle 解析器只接受窄 SQL 子集:
- 选择列必须逗号分隔;WHERE 不支持 =,只支持 IN / LIKE
- 现状 --where 'F=X' 会 400 并抛未捕获堆栈(非友好报错)

新增:错误速查 3 行 + 方言/元数据表对照小节(DD02T/DD40T/DD04T/DD01T + TADIR);
sap-tool-constraints 规则 9 + 自检项 10。references/ 与 .claude/rules/ 已同步。

顺带记录:info 的传输请求恒为 (无法获取)——E071 查询用的 = 在该方言必 400,异常被吞。
2026-09-11 01:17:21 +08:00

152 lines
6.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 错误处理流程
sap-cli 命令失败时的标准处理流程。严格按顺序执行。
## 通用流程
```
命令失败
1. 诊断根因(使用方式错误 or 代码/环境问题?)
2. 使用方式错误 → 修正参数后重试
3. sap-cli 限制 → 报告失败,不绕过
4. SAP 系统限制 → 穷尽自动化方案
5. 确认无法自动化 → 请求用户 SAP GUI 操作
```
## 步骤 1:诊断根因
检查以下项目:
| 检查项 | 方法 |
|--------|------|
| 命令参数是否正确 | 对照 `python main.py --help` 和 SKILL.md 验证参数 |
| 文件是否存在、内容是否为空 | `cat``ls` 检查 |
| 传输请求号是否正确 | `python main.py transport info --corr_nr DEVK901XXX` |
| 网络连接是否正常 | `python main.py config show` 验证配置 |
| 对象是否存在于 SAP | `python main.py info --name XXX --type class` |
## 步骤 2:使用方式错误
修正后重试。常见修正:
- 缺少 `--corr_nr` → 加上传输请求号
- 对象名大小写错误 → sap-cli 会自动处理,但路径要注意
- 文件路径错误 → 检查相对/绝对路径
- 对象类型不匹配 → 用 `python main.py --help` 确认支持的类型
## 步骤 3sap-cli 限制
如果确认不是使用方式问题,**如实报告错误信息**,不要尝试绕过 sap-cli:
```
❌ 错误做法:写 Python requests 脚本绕过
❌ 错误做法:用 curl 直接调 ADT 端点
❌ 错误做法:导入 ADTClient 调内部方法
✅ 正确做法:报告失败,说明原因
```
## 步骤 4:穷尽自动化方案(SAP 系统限制时)
遇到 SAP 系统限制时,按以下顺序穷尽自动化方案:
### 方案 A:调整 sap-cli 参数重试
- 尝试不同的 `--corr_nr`
- 尝试 `--dry-run` 预览后执行
- 检查是否有残留锁(`show-table` 查看 SM12 相关信息)
### 方案 BABAP 报表 workaround
通过 `run-program` 执行辅助报表:
```bash
# 清除残留锁
python main.py sync --type report --name ZSAPILOT_CLEAR_LOCKS --path <file> --corr_nr DEVK901XXX
python main.py run-program --name ZSAPILOT_CLEAR_LOCKS
```
### 方案 Cdelete + recreate
如果对象需要完全重写:
```bash
python main.py delete --name ZMY_CLASS --type class
python main.py sync --name ZMY_CLASS --type class --path <file> --corr_nr DEVK901XXX
```
注意:delete 可能因传输请求绑定而失败(HTTP 423),此时需要用户在 SE09 操作。
### 方案 Dactivate 单独重试
```bash
python main.py activate --name ZMY_CLASS --type class --corr_nr DEVK901XXX
```
NW 7.40 的 double-activate 已内置在 sap-cli 中。如果 activate 仍然失败,**不要再尝试其他激活策略**,直接报告给用户。
## 步骤 5:请求用户 SAP GUI 操作
**只在确认所有自动化方案穷尽后**才请求用户操作。
### 必须一次性给出完整操作清单
当需要用户在 SAP GUI 操作时,**绝不能渐进式发现问题**:
- ❌ 错误:先让用户加字段 A,测试后发现缺字段 B,又让用户加字段 B
- ✅ 正确:先做全面对比分析(`show-table` vs 代码中的字段引用),一次性给出完整变更清单
### 系统表操作的 4 步授权流程
如果需要操作系统表(唯一的例外情况):
1. **解释原因** — 为什么需要操作系统表
2. **列出具体操作** — 表名 + 操作类型(如 `DELETE FROM SEOCLASS WHERE ...`
3. **说明风险和替代方案** — 可能的副作用、有没有不操作系统表的替代方案
4. **等待用户确认** — 得到明确授权后才执行
## 常见失败场景速查
| 错误 | 常见原因 | 处理方式 |
|------|----------|----------|
| HTTP 406 (info 查 DDIC) | NW 7.40 不支持 DDIC 专属媒体类型;`application/xml` 同样 406,只有 `*/*` 可用 | 工具已内置 `*/*` 回退,无需手工处理 |
| HTTP 406 (Lock DDIC) | NW 7.40 不支持 DDIC 对象 ADT Lock | 报告用户,SE09 处理 |
| HTTP 403 (Locked) | 残留 enqueue lock | 先尝试 `run-program` 清锁报表,不行才 SM12 |
| HTTP 400 (SaveFailure) | 类 DEFINITION 与 SAP 不一致 | 检查本地 vs SAP 的 DEFINITION 差异 |
| HTTP 423 (Transport lock) | 对象绑定在传输请求中 | 报告用户,SE09 处理 |
| 激活失败仍 inactive | NW 7.40 ADT 限制 | sap-cli 已内置 double-activate,仍失败则报告用户去 SE09 |
| `WITH EMPTY KEY` 运行 dump | NW 7.40 不支持 | 修改为 `WITH NON-UNIQUE KEY``WITH DEFAULT KEY` |
| HTTP 400 (Data Preview) `A Boolean expression was expected in <字段>=` | ADT Data Preview freestyle SQL **不支持 `=` 比较**(实测:`WHERE f='x'`→400`WHERE f IN ('x')`→200 | 改用 `IN (...)``LIKE '...'`,不要用 `=` |
| HTTP 400 (Data Preview) `elements in the SELECT LIST list must be separated using commas` | 选择列必须逗号分隔(`SELECT a b` 报错) | 写成 `SELECT a, b FROM t` |
| `info` 的「传输请求」恒为 `(无法获取)` | `_query_transport_request``=` + 单引号查 E071,在该方言下必然 400(异常被吞,故静默失败) | 改为 `WHERE object IN ('...') AND obj_name IN ('...')` |
## ADT Data Preview SQL 方言(NW 7.40 实测,2026-09-11
用于补 ZMM_BIP 系列等元数据时,本系统 `/sap/bc/adt/datapreview/freestyle` 的 SQL 解析器只接受很窄的子集:
| 能力 | 实测结果 |
|------|----------|
| `SELECT f1, f2 FROM t`(逗号分隔) | ✅ 200 |
| `WHERE f IN ('a','b')` | ✅ 200 |
| `WHERE f LIKE 'ZMM%'` | ✅ 200 |
| `WHERE f = 'a'` | ❌ 400 `A Boolean expression was expected` |
| `SELECT f1 f2`(无逗号) | ❌ 400 要求逗号分隔 |
| 无 WHERE 全表 | ✅ 200(但行数受行数参数与授权限制) |
**可用的元数据来源(本机实测)**
| 对象类型 | 描述表(键, 语言, 文本) | 开发包来源 |
|----------|--------------------------|------------|
| 结构 / 表 | `DD02T``TABNAME`/`DDLANGUAGE`/`DDTEXT` | `TADIR``OBJECT='TABL'` |
| 表类型 | `DD40T``TYPENAME`/`DDLANGUAGE`/`DDTEXT` | `TADIR``OBJECT='TTYP'` |
| 数据元素 | `DD04T``ROLLNAME`/`DDLANGUAGE`/`DDTEXT` | `TADIR``OBJECT='DTEL'` |
| 域 | `DD01T``DOMNAME`/`DDLANGUAGE`/`DDTEXT` | `TADIR``OBJECT='DOMA'` |
| 类 | ADT 已直接提供 | `TADIR``OBJECT='CLAS'` |
- 描述文本的语言不统一:同一批 ZMM_BIP 结构里有的只有 `DDLANGUAGE='1'`,有的只有 `'E'`;补全时必须按「登录语言 → `E``1` → 首行」回退,不能硬取一种。
- **ZMM_BIP 系列 9 个 DDIC 对象在 `TADIR` 里查不到任何行**(结构与表类型均无注册)→ 无法从系统取得开发包,也意味着未登记对象目录(传输/对象清单角度需注意)。