GlareDB最近将它的软件包发布到了 crates.io,并给出了示例。
我新建了一个rust项目,
cargo new gldbe --vcs none
Creating binary (application) `gldbe` package
note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
export PATH=/par/mold240/bin:$PATH
export CARGO_INCREMENTAL=1
cargo build --release
error: could not find `Cargo.toml` in `/par` or any parent directory
cd gldbe
cargo build --release
让DeepSeek把示例注释翻译成中文,并加入处理查询的CLI界面函数。然后把代码复制粘贴到项目的main.rs中。
编译出错了。
error: failed to run custom build command for `glaredb_proto v25.6.3`
Caused by:
process didn't exit successfully: `/par/gldbe/target/release/build/glaredb_proto-ee8a4e4c2c6ac941/build-script-build` (exit status: 1)
--- stdout
Could not find `protoc`. If `protoc` is installed, try setting the `PROTOC` environment variable to the path of the `protoc` binary. To install it on Debian, run `apt-get install protobuf-compiler`. It is also available at https://github.com/protocolbuffers/protobuf/releases For more information: https://docs.rs/prost-build/#sourcing-protoc
warning: build failed, waiting for other jobs to finish...
从https://github.1git.de/protocolbuffers/protobuf/releases/download/v31.1/protoc-31.1-linux-x86_64.zip下载protoc的二进制包,并把protoc文件解压到/par, 再将/par加入搜索路径PATH环境变量。
export PATH=/par:/par/mold240/bin:$PATH
注意不要下载错误的版本,我一开始误下载了aarch-64版本,结果报错:
Caused by:
process didn't exit successfully: `/par/gldbe/target/release/build/glaredb_proto-ee8a4e4c2c6ac941/build-script-build` (exit status: 1)
--- stdout
failed to invoke protoc (hint: https://docs.rs/prost-build/#sourcing-protoc): (path: protoc): Exec format error (os error 8)
再次编译,又有一个错误,问题出在新增的cli_interface函数中。
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `tokio`
--> src/main.rs:33:54
|
33 | fn cli_interface(engine: SingleUserEngine, tokio_rt: tokio::runtime::Runtime) -> Result<(), Box<dyn Error>> {
| ^^^^^ use of unresolved module or unlinked crate `tokio`
|
= help: if you wanted to use a crate named `tokio`, use `cargo add tokio` to add it to your `Cargo.toml`
error[E0107]: missing generics for struct `SingleUserEngine`
--> src/main.rs:33:26
|
33 | fn cli_interface(engine: SingleUserEngine, tokio_rt: tokio::runtime::Runtime) -> Result<(), Box<dyn Error>> {
| ^^^^^^^^^^^^^^^^ expected 2 generic arguments
|
note: struct defined here, with 2 generic parameters: `P`, `R`
--> /usr/local/cargo/registry/src/mirrors.tuna.tsinghua.edu.cn-4dc01642fd091eda/glaredb_core-25.6.3/src/engine/single_user.rs:19:12
|
19 | pub struct SingleUserEngine<P: PipelineRuntime, R: SystemRuntime> {
| ^^^^^^^^^^^^^^^^ - -
help: add missing generic arguments
|
33 | fn cli_interface(engine: SingleUserEngine<P, R>, tokio_rt: tokio::runtime::Runtime) -> Result<(), Box<dyn Error>> {
| ++++++
Some errors have detailed explanations: E0107, E0433.
把cli_interface函数体代码从函数中摘出来,直接放在main函数中,编译就通过了。(从注释可以看到)
use std::error::Error;
use glaredb_core::{
arrays::format::pretty::{components::PRETTY_COMPONENTS, table::PrettyTable},
engine::single_user::SingleUserEngine,
};
use glaredb_rt_native::runtime::{
NativeSystemRuntime, ThreadedNativeExecutor, new_tokio_runtime_for_io,
};
fn main() -> Result<(), Box<dyn Error>> {
// 创建一个用于远程IO(对象存储)的tokio运行时。如果已经存在tokio运行时,可以跳过此步骤。
// 应该将现有tokio运行时的句柄传递给NativeSystemRuntime。
let tokio_rt = new_tokio_runtime_for_io()?;
// 创建一个用于执行查询的'执行器'。`try_new`会创建一个使用所有线程的线程池。
// 也可以使用`try_new_with_num_threads`作为替代方案。
let executor = ThreadedNativeExecutor::try_new()?;
// 创建一个用于访问外部数据(如文件系统、HTTP客户端等)的'运行时'。
let runtime = NativeSystemRuntime::new(tokio_rt.handle().clone());
// 数据库引擎的简单包装器,包含一个连接到该数据库引擎的会话。
let engine = SingleUserEngine::try_new(executor, runtime.clone())?;
// 注册所有默认扩展(parquet, csv等)。或者可以使用单独的`ext_` crate有选择地注册扩展。
glaredb_ext_default::register_all(&engine.engine)?;
// 启动CLI界面
//cli_interface(engine, tokio_rt)?;
//Ok(())
//}
/// 实现一个简单的CLI界面,允许用户输入SQL查询并查看结果
//fn cli_interface(engine: SingleUserEngine, tokio_rt: tokio::runtime::Runtime) -> Result<(), Box<dyn Error>> {
use std::io::{self, Write};
println!("GlareDB CLI (输入.exit退出)");
loop {
print!("gldbe> ");
io::stdout().flush()?;
let mut input = String::new();
io::stdin().read_line(&mut input)?;
// 去除前后空白字符
let input = input.trim();
// 检查退出命令
if input.eq_ignore_ascii_case(".exit") {
break;
}
// 跳过空输入
if input.is_empty() {
continue;
}
// 执行查询并显示结果
let (batches, schema) = tokio_rt.block_on(async {
let mut q_res = engine
.session()
.query(input)
.await?;
let batches = q_res.output.collect().await?;
Ok::<_, Box<dyn Error>>((batches, q_res.output_schema))
})?;
let table = PrettyTable::try_new(&schema, &batches, 100, None, PRETTY_COMPONENTS)?;
println!("{table}");
}
Ok(())
}
以下是执行效果, 很简陋,也很实用,没有什么多余的功能,各人可以在此基础上发挥。
target/release/gldbe
GlareDB CLI (输入.exit退出)
gldbe> .timer on
Error: Expected a SQL statement, got Period
target/release/gldbe
GlareDB CLI (输入.exit退出)
gldbe> select 1 a,'abc' b;
┌───────┬──────┐
│ a │ b │
│ Int32 │ Utf8 │
├───────┼──────┤
│ 1 │ abc │
└───────┴──────┘
gldbe> select * from '/par/foods.csv' limit 4;
┌────────────┬──────────┬─────────┬──────────┐
│ category │ calories │ fats_g │ sugars_g │
│ Utf8 │ Int64 │ Float64 │ Int64 │
├────────────┼──────────┼─────────┼──────────┤
│ vegetables │ 45 │ 0.5 │ 2 │
│ seafood │ 150 │ 5 │ 0 │
│ meat │ 100 │ 5 │ 0 │
│ fruit │ 60 │ 0 │ 11 │
└────────────┴──────────┴─────────┴──────────┘
gldbe> .exit