ODB中PostgreSQL NUMERIC映射C++ int的value_trait报错排查
问题原因
你实现的value_trait<int, id_numeric>存在核心错误:PostgreSQL的NUMERIC类型在ODB参数传递中采用文本格式(字符串形式),而非二进制int的内存表示。你直接用memcpy将int的二进制值写入buffer,数据库收到的是无法解析的二进制数据,因此判定数据长度不足,抛出08P01错误。
修正后的value_trait实现
正确的处理逻辑是:在set_image中将int转换为字符串,把字符串的字节内容写入buffer;在set_value中将buffer中的字符串转换回int:
namespace odb { namespace pgsql { template <> struct value_traits<int, id_numeric> { using image_type = details::buffer; using query_type = int; static void set_image(image_type& image, std::size_t& size, bool& is_null, const int& value) { is_null = false; std::string s = std::to_string(value); size = s.size(); // 使用字符串实际长度作为数据大小 if (size > image.capacity()) { image.capacity(size); } std::memcpy(image.data(), s.data(), size); // 拷贝字符串的字节内容 } static void set_value(int& value, const image_type& image, std::size_t size, bool is_null) { if (is_null) { value = 0; return; } try { // 将buffer字节转为字符串,再转换为int std::string s(image.data(), size); value = std::stoi(s); } catch (const std::exception& e) { throw std::runtime_error("Failed to convert NUMERIC to int: " + std::string(e.what())); } } }; } }
额外注意事项
- 确保
PersonId类正确映射(name, birthday)复合主键,ODB能正常将其序列化为数据库主键字段。 - 由于
NUMERIC(3)的取值范围是-999到999,远小于int的默认范围,可在set_image中添加范围检查,避免插入超出字段限制的值。
内容的提问来源于stack exchange,提问作者PietFisch
相关产品推荐
相关产品推荐

