Rust调用libpq访问PostgreSQL

本文涉及的产品
云原生数据库 PolarDB MySQL 版,通用型 2核8GB 50GB
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
简介: Rust调用libpq访问PostgreSQL

Rust可以通过外来函数接口(FFI)访问C、C++编写的函数,因此我们可以通过PostgreSQL的libpq库访问PostgreSQL,本文旨在讲述方法及原理,因此例子代码没做任何封装,也没做错误处理。

libpq相关的常量、结构、函数声明均在libpq-fe.h中定义,我们需要先转换成rust的语法。这里先转换一些本例需要用到的。事实上我们是不需要手工转换的,Rust有提供bindgen工具帮助我们转换,只需要执行cargo install bindgen-cli安装,然后运行bindgen即可。

libpq相关声明 - lib_pq.rs

#![allow(non_camel_case_types)]#![allow(warnings)]pubtypeOid= ::std::os::raw::c_uint;
pubtypepg_int64= ::std::os::raw::c_long;
pubconstCONNECTION_OK: ConnStatusType=0;
pubconstCONNECTION_BAD: ConnStatusType=1;
pubconstCONNECTION_STARTED: ConnStatusType=2;
pubconstCONNECTION_MADE: ConnStatusType=3;
pubconstCONNECTION_AWAITING_RESPONSE: ConnStatusType=4;
pubconstCONNECTION_AUTH_OK: ConnStatusType=5;
pubconstCONNECTION_SETENV: ConnStatusType=6;
pubconstCONNECTION_SSL_STARTUP: ConnStatusType=7;
pubconstCONNECTION_NEEDED: ConnStatusType=8;
pubconstCONNECTION_CHECK_WRITABLE: ConnStatusType=9;
pubconstCONNECTION_CONSUME: ConnStatusType=10;
pubconstCONNECTION_GSS_STARTUP: ConnStatusType=11;
pubconstCONNECTION_CHECK_TARGET: ConnStatusType=12;
pubconstCONNECTION_CHECK_STANDBY: ConnStatusType=13;
pubtypeConnStatusType= ::std::os::raw::c_uint;
pubconstPGRES_POLLING_FAILED: PostgresPollingStatusType=0;
pubconstPGRES_POLLING_READING: PostgresPollingStatusType=1;
pubconstPGRES_POLLING_WRITING: PostgresPollingStatusType=2;
pubconstPGRES_POLLING_OK: PostgresPollingStatusType=3;
pubconstPGRES_POLLING_ACTIVE: PostgresPollingStatusType=4;
pubtypePostgresPollingStatusType= ::std::os::raw::c_uint;
pubconstPGRES_EMPTY_QUERY: ExecStatusType=0;
pubconstPGRES_COMMAND_OK: ExecStatusType=1;
pubconstPGRES_TUPLES_OK: ExecStatusType=2;
pubconstPGRES_COPY_OUT: ExecStatusType=3;
pubconstPGRES_COPY_IN: ExecStatusType=4;
pubconstPGRES_BAD_RESPONSE: ExecStatusType=5;
pubconstPGRES_NONFATAL_ERROR: ExecStatusType=6;
pubconstPGRES_FATAL_ERROR: ExecStatusType=7;
pubconstPGRES_COPY_BOTH: ExecStatusType=8;
pubconstPGRES_SINGLE_TUPLE: ExecStatusType=9;
pubconstPGRES_PIPELINE_SYNC: ExecStatusType=10;
pubconstPGRES_PIPELINE_ABORTED: ExecStatusType=11;
pubtypeExecStatusType= ::std::os::raw::c_uint;
pubconstPQTRANS_IDLE: PGTransactionStatusType=0;
pubconstPQTRANS_ACTIVE: PGTransactionStatusType=1;
pubconstPQTRANS_INTRANS: PGTransactionStatusType=2;
pubconstPQTRANS_INERROR: PGTransactionStatusType=3;
pubconstPQTRANS_UNKNOWN: PGTransactionStatusType=4;
pubtypePGTransactionStatusType= ::std::os::raw::c_uint;
pubconstPQERRORS_TERSE: PGVerbosity=0;
pubconstPQERRORS_DEFAULT: PGVerbosity=1;
pubconstPQERRORS_VERBOSE: PGVerbosity=2;
pubconstPQERRORS_SQLSTATE: PGVerbosity=3;
pubtypePGVerbosity= ::std::os::raw::c_uint;
#[repr(C)]#[derive(Debug, Copy, Clone)]pubstructpg_conn {
_unused: [u8; 0],
}
pubtypePGconn=pg_conn;
#[repr(C)]#[derive(Debug, Copy, Clone)]pubstructpg_result {
_unused: [u8; 0],
}
pubtypePGresult=pg_result;
#[repr(C)]#[derive(Debug, Copy, Clone)]pubstructpg_cancel {
_unused: [u8; 0],
}
pubtypePGcancel=pg_cancel;
//本例我们使用了以下函数//告诉Rust需要连接libpq#[link(name = "pq")]extern"C" {
pubfnPQconnectdb(conninfo: *const ::std::os::raw::c_char) ->*mutPGconn;
pubfnPQstatus(conn: *constPGconn) ->ConnStatusType;
pubfnPQresultStatus(res: *constPGresult) ->ExecStatusType;
pubfnPQexec(conn: *mutPGconn, query: *const ::std::os::raw::c_char) ->*mutPGresult;
pubfnPQnfields(res: *constPGresult) -> ::std::os::raw::c_int;
pubfnPQntuples(res: *constPGresult) -> ::std::os::raw::c_int;
pubfnPQclear(res: *mutPGresult);
pubfnPQfinish(conn: *mutPGconn);
pubfnPQerrorMessage(conn: *constPGconn) ->*mut ::std::os::raw::c_char;
pubfnPQfname(
res: *constPGresult,
field_num: ::std::os::raw::c_int,
    ) ->*mut ::std::os::raw::c_char;
pubfnPQgetvalue(
res: *constPGresult,
tup_num: ::std::os::raw::c_int,
field_num: ::std::os::raw::c_int,
    ) ->*mut ::std::os::raw::c_char;
}

main.rs -- 访问pg

usestd::ffi::{CString};
usestd::ffi::CStr;
usestd::process::{exit};
usecrate::lib_pq::{
CONNECTION_OK,
PGRES_TUPLES_OK,
PGconn,
PQclear,
PQconnectdb,
PQerrorMessage,
PQexec, PQfinish,
PQfname,
PQgetvalue,
PQnfields,
PQntuples,
PQresultStatus,
PQstatus};
//声明lib_pq模块modlib_pq;
fnexit_nicely(conn: *mutPGconn) {
unsafe {PQfinish(conn)};
exit(1);
}
fnmain() {
//数据库连接字符串lets=CString::new("dbname=postgres user=postgres password=xxxxxx host=localhost").unwrap();
//建立连接,调用外部函数需要用unsafe包装letconn=unsafe { PQconnectdb(s.as_ptr()) };
//检查状态ifunsafe{ PQstatus(conn) } !=CONNECTION_OK {
exit_nicely(conn);
    }
//执行sqlletsql=CString::new("select * from test1").unwrap();
letres=unsafe{PQexec(conn, sql.as_ptr())};
//检查执行结果ifunsafe{PQresultStatus(res)} !=PGRES_TUPLES_OK  {
println!("Exec sql failed: {:?}", unsafe{PQerrorMessage(conn)});
unsafe{PQclear(res)};
exit_nicely(conn);
    }
//获取字段名letn_fields=unsafe{PQnfields(res)};
foriin0..n_fields {
unsafe {
letn_field=  &*PQfname(res, i);
letv=CStr::from_ptr(n_field).to_string_lossy();
print!("{:<15}", v);
        }
    }
println!("{}", "");
//打印查询结果letn_tuples=unsafe{PQntuples(res)};
foriin0..n_tuples {
forjin0..n_fields {
unsafe {
letn_tuple= &*PQgetvalue(res, i, j);
letv=CStr::from_ptr(n_tuple).to_string_lossy();
print!("{:<15}", v);
            }
        }
println!("{}", "");
    }
//清理,释放资源unsafe {PQfinish(conn)};
}

整个例子非常简单,如果执行cargo build报错,提示找不到外部符号PQconnectdb之类,是因为rust找不到libpq的位置,这时需要生成一个构建文件build.rs,此文件必须与Cargo.toml位于同级目录,同时还需要在Cargo.toml的package区段里加上build = "build.rs"

构建文件 build.rs

fnmain() {
println!("cargo:rustc-link-search=/usr/local/pgsql15/lib");
println!("cargo:rustc-link-lib=pq");
}

构建文件就是告诉rust编译器去哪里找libpq。构建文件有很多选项,具体可参考Build Scripts

Cargo.toml

[package]
name = "pg_test"
version = "0.1.0"
edition = "2021"
build = "build.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍如何基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
关系型数据库 Linux PostgreSQL
这个错误是因为Flink CDC在尝试访问PostgreSQL的"decoderbufs"文件时,发现该文件不存在
【1月更文挑战第23天】【1月更文挑战第111篇】这个错误是因为Flink CDC在尝试访问PostgreSQL的"decoderbufs"文件时,发现该文件不存在
519 11
|
关系型数据库 开发工具 C语言
PostgreSQL libpq开发入门
简单入门C语言开发基于PostgreSQL libpq应用
|
关系型数据库 Linux PostgreSQL
Linux centos8 docker中安装postgresql12.4及远程访问设置
Linux centos8 docker中安装postgresql12.4及远程访问设置
1213 0
|
7月前
|
Oracle 关系型数据库 数据库
【赵渝强老师】在PostgreSQL中访问Oracle
本文介绍了如何在PostgreSQL中使用oracle_fdw扩展访问Oracle数据库数据。首先需从Oracle官网下载三个Instance Client安装包并解压,设置Oracle环境变量。接着从GitHub下载oracle_fdw扩展,配置pg_config环境变量后编译安装。之后启动PostgreSQL服务器,在数据库中创建oracle_fdw扩展及外部数据库服务,建立用户映射。最后通过创建外部表实现对Oracle数据的访问。文末附有具体操作步骤与示例代码。
237 6
【赵渝强老师】在PostgreSQL中访问Oracle
|
7月前
|
关系型数据库 数据库 PostgreSQL
【赵渝强老师】在PostgreSQL中使用file_fdw访问外部文件系统
本文介绍了PostgreSQL的file_fdw扩展,它支持直接从数据库访问服务器文件系统中的文件,文件格式需为text、csv或binary。内容涵盖从编译安装扩展、配置postgresql.conf参数、重启数据库实例,到创建扩展、外部文件服务及外部表的完整流程,并通过具体示例展示如何查询外部表数据,同时附有视频讲解以帮助理解操作步骤。
222 22
|
7月前
|
关系型数据库 数据库 PostgreSQL
【赵渝强老师】使用postgre_fdw访问外部PostgreSQL
本文介绍了如何使用postgres_fdw扩展让PostgreSQL访问外部远端数据库数据。通过编译安装扩展、修改配置文件、重启数据库、创建扩展及外部服务器对象等步骤,最终实现本地数据库通过外部表访问远程数据。附带视频讲解,详细演示操作流程,并提醒需调整远端PostgreSQL配置以支持远程登录。
172 7
|
关系型数据库 Unix 数据库
PostgreSQL开启远程访问
PostgreSQL开启远程访问
|
关系型数据库 Linux 数据安全/隐私保护
PostgreSQL【部署 02】在线安装PostgreSQL(Some psql features might not work 问题处理+角色密码设置+配置远程访问)
PostgreSQL【部署 02】在线安装PostgreSQL(Some psql features might not work 问题处理+角色密码设置+配置远程访问)
201 0
PostgreSQL【部署 02】在线安装PostgreSQL(Some psql features might not work 问题处理+角色密码设置+配置远程访问)
|
Java 关系型数据库 数据库
Spring Boot 学习研究笔记(七) -使用SpringData JPA访问PostgreSql数据库
Spring Boot 学习研究笔记(七) -使用SpringData JPA访问PostgreSql数据库
1148 0
|
关系型数据库 网络安全 数据库
Windows中Postgresql之远程访问
Windows中Postgresql之远程访问
1058 0

推荐镜像

更多