| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687 |
- package DB
- import (
- "strconv"
- "strings"
- "testing"
- "git.ycl.pub/yl32940/TsDB2/DB/core/types"
- )
- // TestParseModelMaxlenCap `maxlen` 声明超过单值上限的字符串列必须在建模阶段就被拒。
- //
- // 这一层是唯一能拦它的地方: 声明超过 MaxInlineColumnWidth 的列落动态列, 而动态列【不保留
- // 声明长度】(Flag 低 5 位必须为 0), 表一旦建出来, 那个 N 就不在盘上了 —— 事后再想校验
- // "这一列声明的容量兑现得了吗"已无据可查。放过去的后果正是声明侧闸门要拦的那种失败:
- // 建表成功、跑了一阵、某天写入某个大值时才撞 ErrHeapPageTooLarge, 用户看不出因果。
- func TestParseModelMaxlenCap(t *testing.T) {
- // 下面 tag 里的字面量必须与实现同步 (单值上限 = core.MaxBlobSize, 由 core 侧的
- // 编译期断言钉住 types 那一份)。对不上就在这里编译失败, 而不是变成一个"碰巧还过"的测试。
- const atCap, overCap = 16360, 16361
- var (
- _ = [1]struct{}{}[atCap-types.MaxStringSize] // 正好用满 = 上限
- _ = [1]struct{}{}[overCap-types.MaxStringSize-1] // 比上限多一个字节
- )
- find := func(t *testing.T, mi *ModelInfo, col string) FieldDef {
- t.Helper()
- for _, fd := range mi.Fields {
- if fd.ColName == col {
- return fd
- }
- }
- t.Fatalf("模型里没有列 %s", col)
- return FieldDef{}
- }
- // 正好用满: 动态列装得下, 必须放行 —— 而且必须落成【动态列 + 宽度码 0】:
- // 这个宽度码是行内布局的唯一依据, 若它被写成非 0, FieldSize 就会按档位算宽度,
- // 整行字段从此错位 (比拒绝声明危险得多)。
- t.Run("正好用满放行", func(t *testing.T) {
- type AtCap struct {
- BaseModel
- Full string `vrtx:"maxlen:16360"`
- }
- mi, err := ParseModel(&AtCap{})
- if err != nil {
- t.Fatalf("声明 %d 字节应当放行: %v", atCap, err)
- }
- fd := find(t, mi, "Full")
- if fd.FieldType != types.FieldType_Dynamicbyte {
- t.Errorf("超过 %d 字节的声明应落动态列, 得到 %s",
- types.MaxInlineColumnWidth, types.TypeNameOf(fd.FieldType))
- }
- if fd.Param() != 0 {
- t.Errorf("动态列的宽度码必须留在 0 (Flag 低 5 位), 得到 %d", fd.Param())
- }
- })
- // 多一个字节: 兑现不了, 必须拒。
- t.Run("超过一个字节就拒", func(t *testing.T) {
- type OverCap struct {
- BaseModel
- Big string `vrtx:"maxlen:16361"`
- }
- _, err := ParseModel(&OverCap{})
- if err == nil {
- t.Fatalf("声明 %d 字节必须被拒 (动态列装不下)", overCap)
- }
- // 报错要能直接定位: 哪个字段、用户写下的数、引擎能给的上限。
- for _, want := range []string{"Big", strconv.Itoa(overCap), strconv.Itoa(types.MaxStringSize)} {
- if !strings.Contains(err.Error(), want) {
- t.Errorf("错误信息里缺少 %q: %v", want, err)
- }
- }
- })
- // 闸门只管字符串列: 数值列的 maxlen 本来就被忽略 (用 Go 类型自动推断), 不该因此报错。
- t.Run("数值列不受影响", func(t *testing.T) {
- type NumWide struct {
- BaseModel
- N int64 `vrtx:"maxlen:16361"`
- }
- if _, err := ParseModel(&NumWide{}); err != nil {
- t.Errorf("数值列的 maxlen 应当被忽略, 不该报错: %v", err)
- }
- })
- }
|