Files
胡飞 2f8338d373 fix(db): 设计表不再读成空表,各引擎自增标记也不再丢
MSSQL 打开设计表后字段栏是空的:tiberius 对可空列返回的是变长类型
(Bitn / Intn / Floatn / DatetimeOffsetn / Null),connection.rs 的
extract_cell 只建模了定长变体,这些一律落到兜底分支产出 Undecoded,
metadata_read 撞上 Undecoded 直接 Err,整份列清单于是被
load_table_structure 的 .ok() 静默吞掉——界面上只剩一张空表,没有任何提示。
真机确证:可空 bit 列(is_nullable)native=Bitn,解出 Undecoded;同一张表里
bit NOT NULL 的 is_identity 是定长 Bit,解出 Decoded(Bool) 正常。

- 补齐变长类型解码,并把「类型 → 解码目标」抽成
  MssqlScalarDecoder::for_column_type 这类可单测的纯映射;Udt / SSVariant
  在驱动层就是 todo!(),继续如实留在 Undecoded,不伪装成值
- 同一链路上的 is_unique 恒为 false:bit 解回来是 "true" / "false",
  代码只比 "1"
- 上述失败原本都被静默吞掉,现在加载失败会推窗口通知(新增 i18n 键
  Table.load_structure_failed)

自增信息(IDENTITY / AUTO_INCREMENT / serial)此前在元数据层根本没有来源,
设计器只能从类型字符串猜,MSSQL 的 bigint 里看不出任何痕迹,必然丢失。

- ColumnInfo 新增 is_auto_increment(#[serde(default)],缺省即非自增),
  各引擎如实上报:MSSQL is_identity、MySQL EXTRA、PostgreSQL
  pg_get_serial_sequence(serial 与 PG10+ identity 都覆盖,老版本也能跑)、
  SQLite 单列 INTEGER 主键即 rowid 别名(INT 与联合主键不算)、
  DuckDB DEFAULT nextval(...)、Oracle all_tab_identity_cols(12c+,
  旧库查询失败只记日志、不因自增元数据拖垮列清单)、ClickHouse 显式无此概念
- wire schema 与 IPC 映射同步加字段,外部驱动也能带上来
- 设计器改为元数据优先、SQLite 兜底、类型解析最后(column_is_auto_increment),
  列编辑器的勾选框与生成的列定义共用同一份判断,不再各写一遍

测试:新增 MSSQL 真实测试目录(real_databases 下此前没有 mssql)与
real_mssql.rs,断言可空 bit / DATETIMEOFFSET 列与唯一索引;MySQL、PostgreSQL
的真实用例补自增断言;SQLite、DuckDB、设计器补单测。

验证:cargo test -p db --lib 1332 passed、--features builtin-duckdb 1349
passed;-p db_view 841 passed;-p extension-protocol 全绿;
cargo check --workspace --all-targets 无错误;真机 MSSQL(env 驱动)与真机
PostgreSQL 的 real_* 用例全过;clippy 无新增告警、rustfmt 合规(未顺带改动
既存的格式偏差)。反向验证:把五处修复分别改回旧行为,对应测试均如期失败。
2026-09-28 10:37:30 +08:00
..