DeepSeek修改4行在duckdb自定义客户端中显示格式化表格结果

前文提到,DuckDB的动态链接库没有格式化输出,这个说法是错误的。今天阅读头文件query_result.hpp时看到,有一个ToBox函数。但是自己调用时总是设不对参数,又把这个任务交给了DeepSeek,一举成功,以下是对话。

我:

我在duckdb头文件query_result.hpp中看到 //! Converts the QueryResult to a box-rendered string
DUCKDB_API virtual string ToBox(ClientContext &context, const BoxRendererConfig &config);如何在我们的程序中调用这个函数实现格式化输出结果?

DeepSeek:

要在你的程序中调用 ToBox 方法实现类似 DuckDB CLI 的格式化表格输出,你需要按照以下步骤操作:

1. 首先包含必要的头文件

#include "duckdb/main/query_result.hpp"
#include "duckdb/common/box_renderer.hpp"

2. 修改你的查询执行代码

在你的 executeQuery 函数中(或类似执行查询的地方),替换原有的 result->Print() 调用:

auto executeQuery = [&](const std::string& query) {
    try {
        auto result = conn_->Query(query);
        
        if (result->HasError()) {
            std::cerr << "Error: " << result->GetError() << std::endl;
        } else {
            // 获取当前客户端上下文
            auto &context = *conn_->context;
            
            // 创建默认的 BoxRenderer 配置
            BoxRendererConfig config;
            
            // 调用 ToBox 方法获取格式化字符串
            std::string box_output = result->ToBox(context, config);
            
            // 输出结果
            std::cout << box_output << std::endl;
        }
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }
};

3. 自定义表格样式(可选)

你可以通过修改 BoxRendererConfig 来自定义输出样式:

BoxRendererConfig config;
config.border = true;       // 显示边框
config.header = true;       // 显示表头
config.limit = 50;          // 最大显示行数
config.max_width = 80;      // 最大宽度(字符)
config.max_col_width = 20;  // 单列最大宽度
config.null_value = "NULL"; // NULL值的显示方式

std::string box_output = result->ToBox(context, config);

4. 完整示例

以下是整合到你的交互式 shell 中的完整示例:

void interactiveShell() {
    // ... 其他代码保持不变 ...

    auto executeQuery = [&]() {
        // ... 之前的特殊命令处理代码 ...

        // 执行普通SQL查询
        try {
            auto start = std::chrono::high_resolution_clock::now();
            auto result = conn_->Query(query);
            auto end = std::chrono::high_resolution_clock::now();
            
            if (result->HasError()) {
                std::cerr << "Error: " << result->GetError() << std::endl;
            } else {
                // 使用 ToBox 格式化输出
                auto &context = *conn_->context;
                BoxRendererConfig config;
                config.border = true;
                std::cout << result->ToBox(context, config) << std::endl;
            }
            
            if (timing_enabled_) {
                std::chrono::duration<double> elapsed = end - start;
                std::cout << "[Time: " << std::fixed << std::setprecision(3) 
                          << elapsed.count() << "s]" << std::endl;
            }
        } catch (const std::exception& e) {
            std::cerr << "Error: " << e.what() << std::endl;
        }
        
        query.clear();
    };

    // ... 后续代码 ...
}

5. 输出示例

执行 SELECT * FROM table 后,输出会变成类似这样:

┌───────┬────────────┬────────┐
│  id   │    name    │  age   │
├───────┼────────────┼────────┤
│    1  │ Alice      │     25 │
│    2  │ Bob        │     30 │
│    3  │ Charlie    │     35 │
└───────┴────────────┴────────┘

注意事项

  1. 确保你的 DuckDB 版本支持 ToBox 方法(v0.6.0 及以上版本)
  2. 对于非常大的结果集,考虑添加行数限制
  3. 如果列内容过长,可以调整 max_col_width 或启用 wrap_text 选项
  4. 要处理 NULL 值的特殊显示,可以设置 null_value 属性

这样修改后,你的程序将拥有和 DuckDB 命令行客户端相同的漂亮表格输出效果。

以上代码,除了config.border = true报错duckcmdb.cpp:318:24: error: 'struct duckdb::BoxRendererConfig' has no member named 'border'以外,一切正常。另外,他的回答显示的表格格式与实际输出不同,应该是用早期版本(但晚于v0.6.0)的duckdb训练的。
以下是示例输出,因为ToBox给出了输出字符串,想要输出前面不含数据类型的表格也很容易,只要将第2个换行和第三个换行之间的内容去掉即可。

duckdb> select 1 a;
┌───────┐
│   a   │
│ int32 │
├───────┤
│     1 │
└───────┘
duckdb> select r_regionkey,r_name from region;
┌─────────────┬─────────────┐
│ r_regionkey │   r_name    │
│    int32    │   varchar   │
├─────────────┼─────────────┤
│           0 │ AFRICA      │
│           1 │ AMERICA     │
│           2 │ ASIA        │
│           3 │ EUROPE      │
│           4 │ MIDDLE EAST │
└─────────────┴─────────────┘

题外话,前文的删除行尾换行bug也已解决。只要将script += line;修改为script += line + "\n";因为std::getline(file, line)不会保存换行符到line中。line.erase(line.find_last_not_of("\r\n") + 1);同样是多余的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值