Doris-INSERT-UPDATE-问题定位
案例1
问题描述
以问题单 #48164 为例:
定义decimal(m),加载超过精度数值,执行未报错 与mysql规则不同
1 | -- 定义decimal(m),加载超过精度数值,执行未报错, 定义decimal(m,d),加载超过精度数值,执行报错 ; myslq以上两种都执行报错 |
注意:虽然单子中没有文字说明,但加载操作实际是在严格模式下进行的
问题定位
- 执行下相同sql, 看下执行结果

由执行结果可以看出,1234567890123 被截断为 1234567890 了,所以才加载成功了
- 由于fe和be都有可能处理数据,所以先确定数据是否是在be侧进行处理的
- 编译debug版be,通过 gdb attach <doris_be_pid> 进行调试be
在 be/src/vec/exprs/vliteral.cpp 中 VLiteral::execute 函数中打上断点
1 | b be/src/vec/exprs/vliteral.cpp:63 |
所有 column 的构建都会通过 VLiteral, 在不清楚数据处理流程的情况下,都可以打这个断点,并且这里也可以 bt 打印堆栈,方便理清代码处理流程
- 然后打印VLiteral的成员函数 value(), 就可以看到从fe侧传递过来的数值是什么

由上图,gdb 调试结果可以看到,value() 的结果是 “1234567890”, 这说明数据是在 fe 侧被截断的
为什么 9999999990.1 加载就会正常报错呢?同样可以查看下

value() 的结果为 “9999999990.1” , _expr_name 的结果为 “Decimal(11, 1)”,
说明 fe 侧对小数没有直接处理和判断是否符合精刻度要求,而是原值传递,判断是否符合要求是在 be 侧进行处理的
案例2
问题描述
1 | -- boolean类型,插入非0 1的整型和小数,3.5处理与mysql不同 |
问题定位
- 和案例1一样,gdb 调试,看从fe传递下来的数据是什么样的

由上图可以看出,数据没有被修改,但数据的类型是int8,而不是boolean
- 查看堆栈

通过堆栈可以看出,是 VCastExpr::open 调用的,说明存在 cast 转换,切换到该栈帧, 打印 _expr_name 为 “(CAST Int8(Int8) TO UInt8)”,则验证了猜想,insert的结果是通过cast转换而来
同样,查看 insert into lgp_lgp_2 select 2,4.3; 执行结果怎么来的


可以清楚的看到 4.3 是通过 “(CAST Decimal(2, 1)(Decimal(2, 1)) TO UInt8)” 转换为0的