用如下函数替换原有同名函数,弥补了原函数不能处理非常大的HUGEINT值的缺陷。让DeepSeek利用已有hugeint转换的字符串,结合scale插入小数点,避免除法运算。
c
// 将decimal数据转换为字符串
void decimal_to_string_format(uint8_t width, uint8_t scale, void* data, int type, char* buffer, size_t buffer_size) {
if (data == NULL || buffer == NULL || buffer_size == 0) {
return;
}
// 根据类型获取整数值
int64_t int_value = 0;
switch (type) {
case DUCKDB_TYPE_TINYINT: // int8_t
int_value = *(int8_t*)data;
break;
case DUCKDB_TYPE_SMALLINT: // int16_t
int_value = *(int16_t*)data;
break;
case DUCKDB_TYPE_INTEGER: // int32_t
int_value = *(int32_t*)data;
break;
case DUCKDB_TYPE_BIGINT: // int64_t
int_value = *(int64_t*)data;
break;
case DUCKDB_TYPE_HUGEINT: // int128_t
{
duckdb_hugeint huge_val = *(duckdb_hugeint*)data;
// 简化处理:如果upper为0,只使用lower部分
if (huge_val.upper == 0) {
int_value = *(int64_t*)data;
break;
} else {
// 对于非常大的HUGEINT值,用hugeint返回的字符串
int128_t u128a = ((int128_t)UINT64_MAX + 1) * huge_val.upper + huge_val.lower;
char a[100];
int128_to_string_safe(u128a, a, sizeof(a));
if (scale == 0) {
snprintf(buffer, buffer_size, "%s", a);
} else {
size_t len = strlen(a);
if (scale >= len) {
// 小数位数大于等于数字总长度,需要在前面补0
// 例如: "123" scale=5 -> "0.00123"
snprintf(buffer, buffer_size, "0.%0*s%s",
scale - len, "0",
a);
} else {
// 正常情况,在合适位置插入小数点
// 例如: "12345" scale=2 -> "123.45"
size_t decimal_pos = len - scale;
// 复制整数部分
strncpy(buffer, a, decimal_pos);
// 添加小数点
buffer[decimal_pos] = '.';
// 复制小数部分
strncpy(buffer + decimal_pos + 1, a + decimal_pos, scale);
// 添加结束符
buffer[len + 1] = '\0';
}
}
}
}
return;
default:
// 无效类型
snprintf(buffer, buffer_size, "decimal(%d,%d,invalid_type,%d)", width, scale, type);
return;
}
// 处理负号
int is_negative = (int_value < 0);
uint64_t abs_value = is_negative ? (uint64_t)(-int_value) : (uint64_t)int_value;
if (scale == 0) {
// 整数情况,直接输出
snprintf(buffer, buffer_size, "%s%lu", is_negative ? "-" : "", abs_value);
} else {
// 计算10^scale
uint64_t divisor = 1;
for (int i = 0; i < scale; i++) {
divisor *= 10;
}
// 分离整数部分和小数部分
uint64_t integer_part = abs_value / divisor;
uint64_t fractional_part = abs_value % divisor;
// 构建格式字符串,确保小数部分有正确的位数(前导零)
char format[32];
snprintf(format, sizeof(format), "%%s%%lu.%%0%dlu", scale);
// 格式化输出
snprintf(buffer, buffer_size, format, is_negative ? "-" : "", integer_part, fractional_part);
}
}
这样改造以后,就可以处理各种大小的decimal数据了,与duckdb的输出一致。
root@66d4e20ec1d7:/par/luadbi# lua ../duck.lua
-15
2025-09-25 12:26:55.123456
-1234567890123456789012345
-12345678900020250922.12345
root@66d4e20ec1d7:/par/luadbi# ../duckdb141 lua_duckdb -c "from table_1"
┌───────┬────────────────────────────┬────────────────────────────┬─────────────────────────────┐
│ id │ column1 │ column2 │ column3 │
│ int32 │ timestamp │ int128 │ decimal(34,5) │
├───────┼────────────────────────────┼────────────────────────────┼─────────────────────────────┤
│ -15 │ 2025-09-25 12:26:55.123456 │ -1234567890123456789012345 │ -12345678900020250922.12345 │
└───────┴────────────────────────────┴────────────────────────────┴─────────────────────────────┘
root@66d4e20ec1d7:/par/luadbi# lua ../duck.lua
-15
2025-09-25 12:26:55.123456
-1234567890123456789012345
-345.00000
root@66d4e20ec1d7:/par/luadbi# ../duckdb141 lua_duckdb -c "from table_1"
┌───────┬────────────────────────────┬────────────────────────────┬───────────────┐
│ id │ column1 │ column2 │ column3 │
│ int32 │ timestamp │ int128 │ decimal(34,5) │
├───────┼────────────────────────────┼────────────────────────────┼───────────────┤
│ -15 │ 2025-09-25 12:26:55.123456 │ -1234567890123456789012345 │ -345.00000 │
└───────┴────────────────────────────┴────────────────────────────┴───────────────┘
root@66d4e20ec1d7:/par/luadbi# lua ../duck.lua
-15
2025-09-25 12:26:55.123456
-1234567890123456789012345
-12345678900.03450
root@66d4e20ec1d7:/par/luadbi# ../duckdb141 lua_duckdb -c "from table_1"
┌───────┬────────────────────────────┬────────────────────────────┬────────────────────┐
│ id │ column1 │ column2 │ column3 │
│ int32 │ timestamp │ int128 │ decimal(34,5) │
├───────┼────────────────────────────┼────────────────────────────┼────────────────────┤
│ -15 │ 2025-09-25 12:26:55.123456 │ -1234567890123456789012345 │ -12345678900.03450 │
└───────┴────────────────────────────┴────────────────────────────┴────────────────────┘
测试脚本如下
lua
DBI = require "DBI"
dbd, err = DBI.Connect( 'DuckDB', 'lua_duckdb', 'dbuser', 'password' )
assert(dbd, err)
dbd:autocommit(true)
statement = dbd:prepare( "create or replace table table_1 as select -15 id, timestamp'2025-09-25 12:26:55.123456'column1, '-1234567890123456789012345'::hugeint column2,'-12345678900.0345'::decimal(34,5) column3 ;" )
statement:execute()
statement = assert(dbd:prepare( "select * from table_1 where id = $1;" ))
statement:execute( -15 )
for row in statement:rows(true) do
print(row['id'])
print(row['column1'])
print(row['column2'])
print(row['column3'])
end