dsh-db-tool 1.8.9 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +49 -0
- package/README.md +18 -8
- package/README_EN.md +18 -8
- package/client/README.md +49 -13
- package/client/client.js +152 -31
- package/docs/sidebar-right-migration.md +477 -0
- package/package.json +7 -7
- package/skills/db-admin/SKILL.md +155 -10
- package/vendor/sqlserver-driver.cjs +1046 -747
package/skills/db-admin/SKILL.md
CHANGED
|
@@ -11,8 +11,52 @@ description: 通过 dsh-db-tool 插件操作 9 种数据库(MySQL、PostgreSQL
|
|
|
11
11
|
|
|
12
12
|
- 每次调用必须带 `action`;除 `list_connections` 外都必须带 `conn_id`(先 `list_connections` 拿到连接 id)。
|
|
13
13
|
- 参数以 snake_case 为主,兼容 camelCase(`conn_id`/`connId` 均可)。
|
|
14
|
-
-
|
|
14
|
+
- 工具整体超时 **90 秒**;慢查询/大脚本超时按失败处理,需拆小重试。
|
|
15
|
+
- 工具返回 `{text, isError}`:`text` 是 JSON 文本——成功时是结果对象;失败时形如 `{"ok":false,"error":"...","code":"..."}`。`isError=true` 仅用于被拒/失败;`NEEDS_CONFIRMATION` 不是失败(`isError=false`),但 `text` 中 `code` 为该值,见下文确认流程。
|
|
15
16
|
- `query`/`execute`/`run_script` 都接受可选 `challenge_id`,用于危险操作确认后的重试。
|
|
17
|
+
- 工具只有 6 个 action。**表名搜索、连接导出/导入、数据传输、事务控制都没有对应 action**,它们是侧边栏(HTTP API)能力,见「侧边栏五个面板与辅助能力」。
|
|
18
|
+
|
|
19
|
+
### 错误码与处置(共 8 个)
|
|
20
|
+
|
|
21
|
+
| code | 含义 | 正确处置 |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| `UNAUTHORIZED_PROJECT` | 项目路径为空,或当前项目未授权该连接 | 引导用户在侧边栏「项目授权」面板为当前项目勾选 ro/rw;不要重试原调用 |
|
|
24
|
+
| `READ_ONLY` | ro 授权下收到写操作(含 `run_script`、控制台事务) | 告知需升级为 rw;**不要反复重试** |
|
|
25
|
+
| `NEEDS_CONFIRMATION` | 危险操作待确认,返回含 `challengeId` | 向用户说明后带同一 `challenge_id` 重试该语句 |
|
|
26
|
+
| `INVALID_CHALLENGE` | challenge 不存在、已用过、已过期(5 分钟)或语句已变更 | 重新原样发起调用取得新 challenge,再走完整确认流程 |
|
|
27
|
+
| `NOT_FOUND` | 连接不存在、事务会话已失效、传输任务不存在 | 重新 `list_connections` / 重新 `begin` / 查历史 |
|
|
28
|
+
| `INVALID_ARGUMENT` | 参数缺失或非法:超上限、`writeMode` 非法、口令不足 8 位、sqlite 开事务、事务指定库等 | 按错误消息改参数后重试;原样重试无意义 |
|
|
29
|
+
| `DRIVER_ERROR` | 数据库/驱动侧失败;ro 模式 query 闸门拒绝也用它(消息以 `DRIVER_ERROR:` 开头) | 按消息修 SQL、连接串或权限;**这不是需要确认的操作** |
|
|
30
|
+
| `SCRIPT_TIMEOUT` | `run_script` 超时被强杀(脚本 60s / 工具 90s 两层) | 缩小脚本工作量或分批;同样脚本重试必然再超时 |
|
|
31
|
+
|
|
32
|
+
### 硬性上限与配额
|
|
33
|
+
|
|
34
|
+
| 项 | 值 | 说明 |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| `preview` limit | 1..50,默认 10 | 超出服务端钳制 |
|
|
37
|
+
| `preview` offset | ≥0,默认 0 | 翻页 |
|
|
38
|
+
| 表名搜索 limit(侧边栏) | 1..200,默认 100 | 工具无此 action |
|
|
39
|
+
| 审计 limit | 1..500,默认 50 | |
|
|
40
|
+
| 传输历史 limit | 1..200,默认 50 | |
|
|
41
|
+
| 传输日志 limit | 1..2000,默认 200 | |
|
|
42
|
+
| Redis 单次 `SCAN` 最多键 | 200 | 达上限返回 `truncated` |
|
|
43
|
+
| Redis 集合类读取(hgetall/lrange/smembers/zrange) | 500 行 | |
|
|
44
|
+
| Redis 键清单(表列表) | 500 | |
|
|
45
|
+
| Redis `preview` | ≤50 | |
|
|
46
|
+
| MongoDB `find` | limit ≤50,默认 20 | 超出自动钳制 |
|
|
47
|
+
| MongoDB `aggregate` 读结果 | 500 行 | |
|
|
48
|
+
| Oracle / 达梦 结果集 | 500 行 | 超限 `truncated` |
|
|
49
|
+
| 脚本执行 | 60s | worker 与 vm 两层同值 |
|
|
50
|
+
| 工具整体 | 90s | |
|
|
51
|
+
| HTTP 请求体 | 2MB | 超限 `INVALID_ARGUMENT` |
|
|
52
|
+
| 导出口令 | ≥8 位 | 服务端强制 |
|
|
53
|
+
| 单连接并发事务会话 | 4 | 超限 `INVALID_ARGUMENT` |
|
|
54
|
+
| 全局并发传输任务 | 8 | |
|
|
55
|
+
| 单任务表数 | 1000 | 且表名不可重复 |
|
|
56
|
+
| 传输 `batchSize` | ≤5000,默认 1000 | |
|
|
57
|
+
| 传输 `tableConcurrency` | ≤16,默认 4 | |
|
|
58
|
+
| 传输 `shardConcurrency` | ≤32,默认 4 | 单表单片数 ≤32 |
|
|
59
|
+
| 事务空闲回收 | 5 分钟 | 扫描周期 30s,回收即回滚并审计 |
|
|
16
60
|
|
|
17
61
|
## 六个 action
|
|
18
62
|
|
|
@@ -24,7 +68,7 @@ description: 通过 dsh-db-tool 插件操作 9 种数据库(MySQL、PostgreSQL
|
|
|
24
68
|
DatabaseManager({ action: "list_connections" })
|
|
25
69
|
```
|
|
26
70
|
|
|
27
|
-
|
|
71
|
+
任何任务开始前先调用它确定可用连接;返回为空说明当前项目未授权任何连接,应引导用户在侧边栏「项目授权」面板为项目路径授 ro 或 rw。
|
|
28
72
|
|
|
29
73
|
### 2. query — 执行查询(只读意图)
|
|
30
74
|
|
|
@@ -61,19 +105,20 @@ DatabaseManager({ action: "schema", conn_id: "c1", database: "shop", table: "use
|
|
|
61
105
|
- 表列表返回 `TableInfo[]`:`{name, type?, comment?, database?}`(Redis 的 type 为 hash|list|set|zset|string|stream)。
|
|
62
106
|
- PostgreSQL/GaussDB 为「数据库 → 模式(schema) → 表」三层语义,支持跨库浏览(Navicat 行为):`database` 参数传 `"库名.schema"` 即可浏览连接库之外的库(如 `gycwd.public`,服务端自动用同一凭据开指向该库的连接);只传 schema 名(如 `public`)则查连接自身库。`listSchemas(database)` 的参数是**纯库名**。不确定 schema 时先执行 `SELECT nspname FROM pg_catalog.pg_namespace WHERE nspname NOT LIKE 'pg\_%' AND nspname <> 'information_schema'`。
|
|
63
107
|
- 列结构返回 `ColumnInfo[]`:`{name, dataType, nullable, key?, default?, comment?}`。
|
|
108
|
+
- 找不到表名时不要盲目逐库遍历:已知表名问「在哪张表」时先 `database` 逐个试,或引导用户用侧边栏的跨库表名搜索(见下文),模型侧没有等价 action。
|
|
64
109
|
|
|
65
110
|
### 5. preview — 预览表数据
|
|
66
111
|
|
|
67
112
|
```
|
|
68
|
-
DatabaseManager({ action: "preview", conn_id: "c1", table: "users", limit: 20, database: "shop" })
|
|
113
|
+
DatabaseManager({ action: "preview", conn_id: "c1", table: "users", limit: 20, offset: 0, database: "shop" })
|
|
69
114
|
```
|
|
70
115
|
|
|
71
|
-
- `table` 必填;`limit`
|
|
72
|
-
- 返回 `{columns, rows, rowCount, truncated?}`;`truncated: true`
|
|
116
|
+
- `table` 必填;`limit` 1..50(默认 10,服务端强制截断);`offset` ≥0(翻页);`database` 可选。
|
|
117
|
+
- 返回 `{columns, rows, rowCount, truncated?}`;`truncated: true` 表示还有更多行,翻下一页请递增 `offset`。
|
|
73
118
|
|
|
74
119
|
### 6. run_script — 沙箱脚本 / Redis 命令 / Mongo 文档(需 rw,危险句柄触发确认)
|
|
75
120
|
|
|
76
|
-
`code` 是一段 JS 脚本,在**子进程隔离沙箱**中执行(无 require/process/fs/网络,60 秒超时)。沙箱注入两个句柄,均走完整 guard/challenge
|
|
121
|
+
`code` 是一段 JS 脚本,在**子进程隔离沙箱**中执行(无 require/process/fs/网络,60 秒超时)。沙箱注入两个句柄,均走完整 guard/challenge/审计链路:
|
|
77
122
|
|
|
78
123
|
- `db.query(sql, params)` — 只读查询,返回结果对象;
|
|
79
124
|
- `db.execute(statement, params)` — 写执行,危险语句在沙箱内以异常抛出 `NEEDS_CONFIRMATION` JSON,需按确认流程携 `challenge_id` 重试。
|
|
@@ -84,6 +129,11 @@ DatabaseManager({ action: "preview", conn_id: "c1", table: "users", limit: 20, d
|
|
|
84
129
|
DatabaseManager({ action: "run_script", conn_id: "c1", code: "return (await db.query('SELECT count(*) AS n FROM users', [])).rows" })
|
|
85
130
|
```
|
|
86
131
|
|
|
132
|
+
两条硬约束:
|
|
133
|
+
|
|
134
|
+
- **恒需 rw**:`run_script` 在授权校验处就要求 rw,连纯只读的 Redis/Mongo 脚本也一样——没有「只读脚本通道」。ro 连接只能用 `query`(Redis/Mongo 的 `query` 可直接传命令 JSON)。
|
|
135
|
+
- **一个脚本里最多只有第一条危险语句能被确认执行**:脚本内所有 `db.query`/`db.execute` 共用同一份 `challenge_id` 入参,而 challenge 一次性——第一条危险语句消费掉它,后续危险语句必然 `INVALID_CHALLENGE`。不要把多条需要确认的写语句塞进同一个脚本;多步确认请逐条 `execute`(每条各自确认),或用侧边栏控制台事务。
|
|
136
|
+
|
|
87
137
|
Redis 与 MongoDB 没有 SQL,`code` 直接传**命令数组 / BSON 命令文档**的 JSON 文本(此时脚本体即该 JSON):
|
|
88
138
|
|
|
89
139
|
```
|
|
@@ -91,7 +141,7 @@ DatabaseManager({ action: "run_script", conn_id: "redis1", code: '["GET","user:1
|
|
|
91
141
|
DatabaseManager({ action: "run_script", conn_id: "mongo1", code: '{"find":"users","filter":{"age":{"$gt":18}}}' })
|
|
92
142
|
```
|
|
93
143
|
|
|
94
|
-
|
|
144
|
+
这两种库的 `query` 与 `execute` 也直接接受命令 JSON(读命令走 `query`、写命令走 `execute`),是按语言区分的两条通道;`run_script` 则是唯一能做「多步组合」的入口。
|
|
95
145
|
|
|
96
146
|
## 九库方言速查
|
|
97
147
|
|
|
@@ -132,11 +182,33 @@ DatabaseManager({ action: "run_script", conn_id: "mongo1", code: '{"find":"users
|
|
|
132
182
|
|
|
133
183
|
- 覆盖 SQL Server 2008/2008R2 → 2022 与 Azure SQL Database;SQL Server 2005(9.x)及更早版本不支持、未验证;`tdsVersion=8_0`(TDS 8.0)与 `encrypt='strict'`(严格加密)也不支持——SQL Server 2022 用默认 `7_4` 即可正常连接。方言与元数据只使用 2005+ 通用写法(元数据走 `sys.*` catalog views)。
|
|
134
184
|
- **认证**:仅 SQL 认证(user/password);**不支持 Windows 集成认证,也不支持 Azure AD 认证**——需要这两类认证时本工具不可用。
|
|
135
|
-
- **连接形态**:`sqlserver://user:password@host:port/db`,支持 query 参数 `encrypt` / `trustServerCertificate` / `tdsVersion` / `instanceName` / `useUTC`(参数名大小写不敏感);`tdsVersion` 默认 `7_4`,可配 `7_3_A` / `7_3_B` / `7_2` / `7_1
|
|
136
|
-
|
|
185
|
+
- **连接形态**:`sqlserver://user:password@host:port/db`,支持 query 参数 `encrypt` / `trustServerCertificate` / `tdsVersion` / `tlsMinVersion` / `instanceName` / `useUTC`(参数名大小写不敏感);`tdsVersion` 默认 `7_4`,可配 `7_3_A` / `7_3_B` / `7_2` / `7_1`;`instanceName` 与端口互斥(命名实例改由 SQL Server Browser 解析)。**不接受** ADO.NET 键值连接串(`Server=...;Database=...`)。
|
|
186
|
+
- **默认与覆盖**:`encrypt=true` + `trustServerCertificate=false` + `tdsVersion=7_4` + `useUTC=true`(同 mssql 官方默认)。URL query 与分字段表单**同口径**,两处都能覆盖上述四项(含 `tlsMinVersion`);非法布尔值直接报错,不静默回退。
|
|
187
|
+
|
|
188
|
+
### TLS 握手失败:两类根因,解法互不通用
|
|
189
|
+
|
|
190
|
+
| 报错特征 | 根因 | 处置(按优先级) |
|
|
191
|
+
|---|---|---|
|
|
192
|
+
| `self signed certificate` / `unable to verify` / `CERT_` 家族 | 证书校验阶段失败(自签、链断、主机名不符、已过期) | ① `?trustServerCertificate=true`;② 服务器未强制加密时 `?encrypt=false`(强制加密时反而报「服务器要求加密」) |
|
|
193
|
+
| `UNSUPPORTED_PROTOCOL` / `no protocols available` / `alert protocol version`(含 `SSL routines ... UNSUPPORTED`) | 协议版本协商阶段失败:客户端与服务端无共同 TLS 版本,**证书校验根本没执行** | ① 服务端启用 TLS 1.2(2008 R2 SP3 装 KB4057113、2008 SP4 装 KB4057114,重启实例);② 暂时不能动服务端时,客户端下探 `?tlsMinVersion=TLSv1` |
|
|
194
|
+
|
|
195
|
+
**不要拿证书类参数治协议版本类**:`trustServerCertificate=true` / `encrypt=false` 只影响证书校验,对 `UNSUPPORTED_PROTOCOL` 没有任何作用,试错只会白跑一轮。两类判据互斥,报错消息里已按族给出中文根因;看到 `TCP 已连通但 TLS ...` 说明网络与端口都没问题,不要再查主机/防火墙。
|
|
196
|
+
|
|
197
|
+
### `tlsMinVersion` 参数
|
|
198
|
+
|
|
199
|
+
| 取值 | 含义 |
|
|
200
|
+
|---|---|
|
|
201
|
+
| `TLSv1` | 最低 TLS 1.0(2008/2008R2 只支持 1.0 时用) |
|
|
202
|
+
| `TLSv1.1` | 最低 TLS 1.1 |
|
|
203
|
+
| `TLSv1.2` | 最低 TLS 1.2(等同不设置时的 Node 默认下限) |
|
|
204
|
+
|
|
205
|
+
- 不设置即沿用 Node 默认下限 TLSv1.2;取值**区分大小写、不做归一化**,非法值直接报中文错误(不静默回退,避免用户以为已下探)。
|
|
206
|
+
- **不支持 `TLSv1.3`**:底层 tedious 在未指定上限时把 `maxVersion` 封顶为 TLSv1.2,设 1.3 会变成 min > max,握手必然失败(`ERR_SSL_NO_PROTOCOLS_AVAILABLE`)。
|
|
207
|
+
- 只开下限、不提供 ciphers / maxVersion 开关;不要填 OpenSSL 专有 cipher 串(BoringSSL 下会抛 `INVALID_COMMAND`)。
|
|
208
|
+
- 例:`sqlserver://sa:pwd@10.0.0.5:1433/shop?tlsMinVersion=TLSv1`
|
|
137
209
|
- **分页自动分流**:适配器探测 `SERVERPROPERTY('ProductMajorVersion')`,2012+ 用 `OFFSET/FETCH`,2008/2008R2 降级 `ROW_NUMBER() OVER (ORDER BY (SELECT NULL))` 子查询——生成 SQL 时不需要自己补 `TOP`/`ROW_NUMBER`。
|
|
138
210
|
- **传输边界**:写入为参数化多行 `VALUES` INSERT(TDS 单语句 2100 参数上限、`VALUES` 单语句 1000 行上限,每语句行数取两者最小值)。传输分页按目标库版本分流:2012+ 用 `OFFSET/FETCH`,**2008/2008R2 降级可用**——有序游标(keyset/range)用 `SELECT TOP (n) ... ORDER BY key`,无分片键的 offset 全序与 `keyAt` 切块用 `ROW_NUMBER() OVER (...)` 子查询;版本探测失败按 0 走保守降级。已知限制:目标表已存在且该列是 IDENTITY 时,写入显式值会报错 544(当前不自动 `SET IDENTITY_INSERT ON`);传输自动建表不生成 IDENTITY 列。
|
|
139
|
-
-
|
|
211
|
+
- **真机验证**:真机用例组由环境变量 `DBT_TEST_SQLSERVER_URL` 门控(`tests/adapters-sql/sqlserver.test.ts`,未设置则整体 skip);错误中文映射、参数默认值与 TLS 分族诊断由 Fake 驱动离线用例覆盖。
|
|
140
212
|
- 只读(ro)强度弱于 MySQL/PG,原因见下文「只读(ro)模式下的正确姿势」。
|
|
141
213
|
|
|
142
214
|
## 危险操作确认流程(NEEDS_CONFIRMATION)
|
|
@@ -156,8 +228,80 @@ DatabaseManager({ action: "run_script", conn_id: "mongo1", code: '{"find":"users
|
|
|
156
228
|
|
|
157
229
|
Challenge 属性:**一次性**(用过即失效)、绑定语句 hash(改语句后失效)、5 分钟过期。过期或无效会返回 `INVALID_CHALLENGE`,此时重新发起调用、走完整确认流程。**严禁**未经用户确认就重试;也**不要**为绕过确认而改写语句。
|
|
158
230
|
|
|
231
|
+
一次 challenge 只能覆盖一条语句——`run_script` 里多条危险语句必然在第二条起报 `INVALID_CHALLENGE`,多步写请逐条 `execute`。
|
|
232
|
+
|
|
159
233
|
会触发确认的典型操作:DDL(CREATE/ALTER/DROP/TRUNCATE)、所有 DML 写(INSERT/UPDATE/DELETE)、维护命令、Redis 危险命令(FLUSHALL、CONFIG 等)与写命令、Mongo 写 op(drop、deleteMany、updateMany 等)、以及部分危险读(如 Redis `KEYS *`)。SQL Server 另有:专属危险首词 `BACKUP`(DATABASE/LOG)、`RESTORE`、`DBCC`、`RECONFIGURE`、`BULK INSERT`、`SHUTDOWN`、`xp_cmdshell` 与其他 `xp_*`、`sp_configure`;`SELECT ... INTO <表|#临时表>`(T-SQL 建表副作用)与 `WITH ... (DELETE|UPDATE|INSERT)` 也判危险需确认;其中 `SELECT 1 INTO @t`(表变量/变量赋值)放行、`INSERT INTO ...` 仍按 DML 口径。注意一般 `EXEC sp_*`(非 `sp_configure`/`xp_*`)**未**单列危险,不会因此触发确认。另外这一层是「确认」语义;**ro 授权下** `SELECT ... INTO`、`WITH` 写体与 `OPENQUERY`/`OPENROWSET`/`OPENDATASOURCE` 会被适配器闸门**直接拒绝**(返回错误,无确认可走)。
|
|
160
234
|
|
|
235
|
+
## 侧边栏五个面板与辅助能力
|
|
236
|
+
|
|
237
|
+
侧边栏 tab 共 **5 个面板**(中英双语),用户问「在哪儿操作」时按下表指路;这些能力多数没有对应的工具 action。
|
|
238
|
+
|
|
239
|
+
| 面板 | 能力 | 底层 HTTP API(模型不可直接调用) |
|
|
240
|
+
|---|---|---|
|
|
241
|
+
| 连接管理 | 新增/编辑/删除连接、保存前测试草稿、连通性测试、导出/导入 | `/api/connections*`、`/api/test-draft` |
|
|
242
|
+
| 项目授权 | 为当前项目路径逐连接勾选 ro/rw、撤销 | `/api/grants` |
|
|
243
|
+
| 数据浏览 | 库/模式/表三级树、跨库表名搜索、数据预览网格 | `/api/databases`、`/api/schemas`、`/api/schema`、`/api/tables`、`/api/search-tables`、`/api/preview` |
|
|
244
|
+
| SQL 控制台 | 多标签编辑器、逐条执行、`GO`/`GO n` 批分隔、事务、结果网格(50 行/页,CSV/JSON 导出) | `/api/query`、`/api/execute`、`/api/console/*`、`/api/audit` |
|
|
245
|
+
| 数据传输 | 表数据搬运、实时进度;含「传输历史」「传输日志」两个子标签 | `/api/transfer/start`、`/api/transfer/{id}`、`/api/transfer/live`、`/api/transfer-history`、`/api/transfer-log` |
|
|
246
|
+
|
|
247
|
+
### 跨库表名搜索(仅在数据浏览面板)
|
|
248
|
+
|
|
249
|
+
按关键字模糊搜表名,ro 即可,命中项带 `database` 便于定位跳转。它**不是工具 action**,模型侧没有等价入口,只能引导用户去面板搜索,或自己逐库调 `schema`。
|
|
250
|
+
|
|
251
|
+
真实分流(不存在的实现不会「尽力而为」,直接返回空):
|
|
252
|
+
|
|
253
|
+
| 库 | 实现方式 |
|
|
254
|
+
|---|---|
|
|
255
|
+
| MySQL / PostgreSQL / GaussDB | 适配器原生实现(一条 `information_schema` 模糊查询;pg 系可跨库) |
|
|
256
|
+
| SQLite / MongoDB | 回退「逐库 `listTables` + 内存过滤」(并发 8,个别库无权限不影响整体) |
|
|
257
|
+
| **Redis / Oracle / 达梦 / SQL Server** | **恒返回空**(无实现且语义不兼容:Redis 忽略库名会重复返回同一批键,Oracle/达梦 的库层语义是 owner) |
|
|
258
|
+
|
|
259
|
+
limit 1..200(默认 100)。搜不到时不要断言「表不存在」,换 `schema` 逐库确认。
|
|
260
|
+
|
|
261
|
+
### 连接导出 / 导入
|
|
262
|
+
|
|
263
|
+
| 操作 | 请求体 | 返回 |
|
|
264
|
+
|---|---|---|
|
|
265
|
+
| 导出 | `{passphrase}` | `{json, count}` |
|
|
266
|
+
| 导入 | `{json, passphrase}` | `{imported, skipped, errors}` |
|
|
267
|
+
|
|
268
|
+
- 整包加密:scrypt(N=16384, r=8, p=1)派生密钥 + AES-256-GCM,文件打开无明文;口令**服务端强制 ≥8 位**。
|
|
269
|
+
- 导入时 **id 冲突一律进 `skipped`、不覆盖已有连接**,可重复导入(幂等)。
|
|
270
|
+
- 口令错误与密文损坏统一报 `INVALID_ARGUMENT`(不区分原因,防口令探测)。
|
|
271
|
+
- 导出/导入**不需要项目授权**(属连接管理范围);审计只记条数,不落口令与密文内容。
|
|
272
|
+
|
|
273
|
+
### 数据传输(侧边栏「数据传输」面板)
|
|
274
|
+
|
|
275
|
+
| 写入模式 | 语义 |
|
|
276
|
+
|---|---|
|
|
277
|
+
| `insert`(默认) | 追加;目标表已存在则整表失败(不覆盖已有数据) |
|
|
278
|
+
| `ignore` | 冲突行跳过 |
|
|
279
|
+
| `replace` | 冲突行覆盖(依赖主键) |
|
|
280
|
+
| `truncate` | 先清空目标表再全量写入,**清空不可恢复** |
|
|
281
|
+
|
|
282
|
+
- 授权要求:源端 ro 即可,目标端需 rw。
|
|
283
|
+
- 目标表不存在时按源表结构自动建表;`overwriteStructure` 可覆盖结构。
|
|
284
|
+
- **Redis 不支持传输**:读端与写端都返回「数据传输暂不支持」,源或目标任一端是 Redis 都无法搬运。
|
|
285
|
+
- 并行降级:目标 SQLite 单写者 → 表级并发钳 1、分片共享同一 writer(写入天然串行);源 Oracle/达梦 走专用单连接读 → 表内不分片(表级并行仍生效)。
|
|
286
|
+
- 并发与批量:`tableConcurrency` ≤16 默认 4、`shardConcurrency` ≤32 默认 4、`batchSize` ≤5000 默认 1000、单表分片 ≤32;失败分片重试 1 次——重试的幂等性依赖 `ignore`/`replace`,`insert` 模式重试可能产生重复行。
|
|
287
|
+
- 上限:全局并发任务 8、单任务表数 1000、表名不可重复(重复即 `INVALID_ARGUMENT`)。
|
|
288
|
+
- 启动需危险确认(challenge 绑定「源→目标 + 表清单 + 模式 + 定位」,改任一字段即失效)。
|
|
289
|
+
- 结果查看:运行中看「实时进度」,终态进「传输历史」(limit ≤200,可按项目清除),全过程事件进「传输日志」(limit ≤2000)。
|
|
290
|
+
- 模型侧没有 transfer action,**不要伪造传输进度或结果**;只能引导用户在面板操作并读取其反馈。
|
|
291
|
+
|
|
292
|
+
### 控制台事务
|
|
293
|
+
|
|
294
|
+
| 步骤 | 行为 |
|
|
295
|
+
|---|---|
|
|
296
|
+
| 开始 | 需 rw 且**未选库**;返回 `sessionToken`,绑定一条粘性连接 |
|
|
297
|
+
| 执行 | 语义等同 `execute`:危险语句逐条走确认(一个 challenge 一条语句) |
|
|
298
|
+
| 提交/回滚 | 销毁会话并 close 适配器;token 随即失效 |
|
|
299
|
+
|
|
300
|
+
- **只有 rw 且未选库才能 begin**:ro 直接 `READ_ONLY`;带 `database` 入参被显式拒绝(粘性事务绑定连接默认库,跨库会静默跑错库)。
|
|
301
|
+
- **SQLite 无事务通道**:`begin` 报 `INVALID_ARGUMENT`(连接类型不支持控制台事务会话)。
|
|
302
|
+
- 单连接并发事务会话 ≤4;空闲 5 分钟自动回滚并审计(扫描周期 30s);token 失效后再 `exec` 报 `NOT_FOUND`(已提交/回滚或空闲回收)。
|
|
303
|
+
- 撤销授权或 rw→ro 降级会立即回收该连接的全部事务会话并回滚未提交事务。
|
|
304
|
+
|
|
161
305
|
## 安全规范(必须遵守)
|
|
162
306
|
|
|
163
307
|
- **永远使用参数绑定**:`sql: "SELECT * FROM users WHERE id = ?"` + `params: [42]`。**禁止字符串拼接**用户输入进 SQL。
|
|
@@ -170,4 +314,5 @@ Challenge 属性:**一次性**(用过即失效)、绑定语句 hash(改
|
|
|
170
314
|
- ro 授权下 execute/写类 run_script 会返回 `READ_ONLY`——**不要反复重试**,直接告知用户需要在侧边栏把授权升级为 rw。
|
|
171
315
|
- 探索数据用 `query` + `schema` + `preview` 组合即可完成绝大多数只读任务;批量导出优先分页(LIMIT/OFFSET 或 SCAN/fetch)而非一次性大查询。
|
|
172
316
|
- Redis ro 下用 `SCAN` 而非 `KEYS`;Mongo ro 下只允许 find/count 类 op。
|
|
317
|
+
- 结果集有行数上限(Oracle/达梦 500、Mongo aggregate 500、Redis 集合读 500、preview 50),要完整数据请分页推进并检查 `truncated`。
|
|
173
318
|
- **SQL Server 的 ro 强度弱于 MySQL/PG**:SQL Server 没有等价的会话级只读语句。ro 下适配器 query 闸门有五道:① 首词白名单(select/with/show/describe/desc/explain/use/set/help/table);② 拒绝多语句(词法级:顶层分号之后出现任何内容即拒);③ 拒绝 `SELECT ... INTO`(token 级,字符串/方括号标识符/注释内的 into 不误伤);④ 拒绝 `WITH ... (INSERT|UPDATE|DELETE|MERGE)`;⑤ 拒绝 `OPENQUERY`/`OPENROWSET`/`OPENDATASOURCE`(远端/外部数据源执行任意语句、无法审计,连合法只读远端查询也一律拒)。服务层另拦 execute,guard 层对同样两类「读头写体」还会要求确认。**不要把 ro 连接当成数据库侧的只读隔离**;需要强隔离请换数据库侧只读账号。
|