78次发布
0.7.4 | 2023年3月14日 |
---|---|
0.7.2 | 2023年2月23日 |
0.6.1 | 2022年12月6日 |
0.6.0-alpha.2 | 2022年11月18日 |
0.0.8 | 2020年7月28日 |
在数据库接口中排名第54位
每月下载量305次
在 8 crates中使用
10MB
338K SLoC
pgx
用Rust构建Postgres扩展!
pgx
是一个用于在Rust中开发PostgreSQL扩展的框架,并力求在尽可能的方面保持惯用性和安全性。
pgx
支持Postgres v11-v15。
欢迎加入我们的Discord服务器。
主要功能
- 一个完全管理的开发环境,包括
cargo-pgx
cargo pgx new
:快速创建新扩展cargo pgx init
:安装新的(或注册现有的)PostgreSQL安装cargo pgx run
:运行您的扩展并在psql
(或pgcli
)中进行交互式测试cargo pgx test
:跨多个PostgreSQL版本对您的扩展进行单元测试cargo pgx package
:为您的扩展创建安装包- 更多详情请查看
README.md
!
- 支持多个Postgres版本
- 从相同的代码库支持Postgres v11-v15
- 使用Rust功能门控来使用特定版本的API
- 无缝测试所有版本
- 自动模式生成
- 完全使用Rust实现扩展
- 自动将许多Rust类型映射到PostgreSQL
- 自动生成SQL模式(或通过
cargo pgx schema
手动生成) - 使用
extension_sql!
和extension_sql_file!
包含自定义SQL
- 安全优先
- 将Rust的
panic!
转换为Postgres的ERROR
,终止事务而不是进程 - 内存管理遵循Rust的drop语义,即使在
panic!
和elog(ERROR)
的情况下也是如此。 - 使用
#[pg_guard]
过程宏来确保上述内容 - Postgres的
Datum
是Option<T> where T: FromDatum
NULL
Datum以安全的方式表示为Option::<T>::None
- 将Rust的
- 第一类UDF支持
- 使用
#[pg_extern]
注解函数以将其暴露给Postgres - 对于
RETURNS SETOF
,返回pgx::iter::SetOfIterator<'a, T>
- 对于
RETURNS TABLE (...)
,返回pgx::iter::TableIterator<'a, T>
- 使用
#[pg_trigger]
创建触发函数
- 使用
- 易于自定义类型
- 使用
#[derive(PostgresType)]
将Rust结构体用作Postgres类型- 默认情况下,在内存/磁盘上以CBOR编码的对象形式表示,并以JSON作为可读格式
- 提供自定义的内存/磁盘/可读表示
- 使用
#[derive(PostgresEnum)]
将Rust枚举用作Postgres枚举 - 支持使用
pgx::composite_type!("Sample")
宏进行组合类型
- 使用
- 服务器编程接口(SPI)
- 安全访问SPI
- 从SPI上下文中透明地返回所有权的Datum
- 高级功能
- 通过
pgx::PgMemoryContexts
安全访问Postgres的MemoryContext
系统 - Executor/planner/transaction/subtransaction钩子
- 安全使用Postgres提供的指针,与
pgx::PgBox<T>
(类似于alloc::boxed::Box<T>
) #[pg_guard]
宏用于保护需要传递给Postgres的Rust函数中的extern "C"
- 通过类似于
eprintln!
的宏访问Postgres的日志系统 - 通过
pgx::pg_sys
模块直接访问Postgres内部的大部分内容(不安全操作) - 定期添加新功能!
- 通过
系统需求
- Rust工具链:
rustc
、cargo
和rustfmt
。推荐从https://rustup.rs获取这些工具† git
libclang
5.0或更高版本(bindgen需要)- Ubuntu:使用
apt install libclang-dev
或apt install clang
- RHEL:使用
yum install clang
- Ubuntu:使用
tar
bzip2
- GCC 7或更高版本
- PostgreSQL的构建依赖项†
† PGX没有MSRV策略,因此可能需要通过Rustup获取最新的稳定版Rust†
† 不需要本地PostgreSQL服务器安装。使用cargo pgx
可以下载并编译PostgreSQL版本。
如何在CentOS 7上安装GCC 7
为了使用GCC 7,安装scl
并进入GCC 7开发环境
yum install centos-release-scl
yum install devtoolset-7
scl enable devtoolset-7 bash
入门
首先安装cargo-pgx
子命令并初始化开发环境
cargo install --locked cargo-pgx
cargo pgx init
init
命令会下载当前支持的PostgreSQL版本,将它们编译到~/.pgx/
,并运行initdb
。也可以使用现有的(用户可写)PostgreSQL安装,或者安装版本子集,请参阅README.md
中的详细说明。
cargo pgx new my_extension
cd my_extension
这将创建一个用于扩展crate的新目录。
$ tree
.
├── Cargo.toml
├── my_extension.control
├── sql
└── src
└── lib.rs
2 directories, 3 files
新扩展包括一个示例,因此您可以立即运行它。
cargo pgx run
这会将扩展编译为共享库,将其复制到指定的Postgres安装中,启动该Postgres实例并将您连接到与扩展同名的数据库。
一旦cargo-pgx
将我们放入psql
,我们就可以加载扩展并在示例函数上执行SELECT。
my_extension=# CREATE EXTENSION my_extension;
CREATE EXTENSION
my_extension=# SELECT hello_my_extension();
hello_my_extension
---------------------
Hello, my_extension
(1 row)
有关如何管理pgx扩展的更多详细信息,请参阅管理pgx扩展。
升级
您可以通过在cargo install
中传递--force
标志来升级您的当前cargo-pgx
安装
cargo install --force --locked cargo-pgx
随着新版本的Postgres被pgx
支持,您可以重新运行pgx init
过程以下载和编译它们
cargo pgx init
Postgres类型到Rust的映射
Postgres类型 | Rust类型(作为Option<T> ) |
---|---|
bytea |
Vec<u8> 或&[u8] (零拷贝) |
text |
String 或&str (零拷贝) |
varchar |
String 或&str (零拷贝)或char |
"char" |
i8 |
smallint |
i16 |
integer |
i32 |
bigint |
i64 |
oid |
u32 |
real |
f32 |
double precision |
f64 |
bool |
bool |
json |
pgx::Json(serde_json::Value) |
jsonb |
pgx::JsonB(serde_json::Value) |
date |
pgx::Date |
time |
pgx::Time |
timestamp |
pgx::Timestamp |
time with time zone |
pgx::TimeWithTimeZone |
timestamp with time zone |
pgx::TimestampWithTimeZone |
anyarray |
pgx::AnyArray |
anyelement |
pgx::AnyElement |
box |
pgx::pg_sys::BOX |
point |
pgx::pgx_sys::Point |
tid |
pgx::pg_sys::ItemPointerData |
cstring |
&core::ffi::CStr |
inet |
pgx::Inet(String) -- TODO: needs better support |
numeric |
pgx::Numeric<P, S>或pgx::AnyNumeric |
void |
() |
ARRAY[]::<type> |
Vec<Option<T>> 或pgx::Array<T> (零拷贝) |
int4range |
pgx::Range<i32> |
int8range |
pgx::Range<i64> |
numrange |
pgx::Range<Numeric<P, S>> 或pgx::Range<AnyRange> |
daterange |
pgx::Range<pgx::Date> |
tsrange |
pgx::Range<pgx::Timestamp> |
tstzrange |
pgx::Range<pgx::TimestampWithTimeZone> |
NULL |
Option::None |
internal |
pgx::PgBox<T> 其中T 是任何Rust/Postgres结构体 |
uuid |
pgx::Uuid([u8; 16]) |
还有 IntoDatum
和 FromDatum
特性,用于实现额外的类型转换,以及用于自动转换自定义类型的 #[derive(PostgresType)]
和 #[derive(PostgresEnum)]
。
深入了解
注意事项和已知问题
可能还有更多,但值得关注的主要是
- 线程支持不充分。Postgres 实行严格单线程。因此,如果您冒险使用线程,这些线程绝对不能调用任何内部 Postgres 函数,或者使用任何 Postgres 提供的指针。还有关于 Postgres 使用
sigprocmask
的潜在问题。这已经在 -hackers 列表中讨论过,甚至提供了一个补丁,但对话似乎已经停滞了(https://postgresql.ac.cn/message-id/flat/5EF20168.2040508%40anastigmatix.net#4533edb74194d30adfa04a6a2ce635ba)。 - 如何在
async
上下文中正确与 Postgres 交互尚未探索。 pgx
包裹了大量的unsafe
代码,其中一些安全性条件定义得不好。即使是从安全代码中,使用pgx
也可能很容易引起不合理和不受欢迎的行为,并且其中一些包装可能根本不安全。请报告任何可能出现的问题。- 并非所有 Postgres 的内部组件都被包含或包装起来。这并非因为不可能,而是因为这是一项极其庞大的任务。如果您确定了需要使用的内部 Postgres API,请创建一个问题,我们将通过
pgx::pg_sys
模块公开它们。 - 不支持 Windows。它可以,但需要与
cargo-pgx
一起进行一些工作,并找出如何编译pgx
的 "cshim" 静态库。 - 在
ALTER EXTENSION my_extension UPDATE;
之前启动的会话将继续看到my_extension
的旧版本。新会话将看到扩展的更新版本。 pgx
被许多 "生产环境" 使用,但它不是 "1.0.0" 或更高版本,尽管 SemVer 推荐生产质量软件使用该版本。这是因为还有许多未解决的安全性问题和用户体验问题,这些问题可能需要通过破坏性更改来解决,在某些情况下可能需要使用最前沿的 Rust 功能来公开安全的接口。虽然计划在某个时候发布 1.0.0 版本,但似乎明智地等待,直到看起来下周不需要 2.0.0 版本,并且剩余的问题可以延迟处理。
待办事项
我们的待办事项列表上有几件事情
- 基于先前 git 标签和 HEAD 的差异,自动生成扩展架构升级脚本。很可能,这将构建到
cargo-pgx
子命令中,并使用 https://github.com/zombodb/postgres-parser。 - 更多示例 -- 尤其是关于内存管理和各种 derive 宏
#[derive(PostgresType/Enum)]
功能标志
PGX 为 Rust 代码提供了可选的功能标志,这些标志不涉及配置使用的 Postgres 版本,而是扩展了对其他类型 Rust 代码的支持。这些标志默认不包含在内。
"time-crate": 与 time
crate 的互操作性
pgx
曾经使用与出色的 time crate 的直接互操作性。然而,由于性能和与 Postgres 精确互操作的问题,现在认为这个特性已被弃用,转而使用低开销的互操作性。您仍然可以通过启用 "time-crate"
功能来请求 TryFrom<time::Type> for pgx::MatchingType
和 From<time::Type> for pgx::MatchingType
的实现。
"unsafe-postgres": 允许为具有不同 ABI 的 Postgres 分支进行编译
截至 Postgres v15,分支允许指定它们使用与规范 Postgres 不同的 ABI。由于 pgx 对 Postgres 内部 ABI 做了无数假设,因此它无法保证编译的 pgx 扩展可以在这样的 Postgres 分支中执行。您,尊敬的编译器运行者,可以通过指定 unsafe-postgres
功能标志来自行保证这一点。否则,pgx 扩展将无法编译并出现类似于的错误
error[E0080]: evaluation of constant value failed
--> pgx/src/lib.rs:151:5
|
151 | / assert!(
152 | | same_slice(pg_sys::FMGR_ABI_EXTRA, b"xPostgreSQL\0"),
153 | | "Unsupported Postgres ABI. Perhaps you need `--features unsafe-postgres`?",
154 | | );
| |_____^ the evaluated program panicked at 'Unsupported Postgres ABI. Perhaps you need `--features unsafe-postgres`?', pgx/src/lib.rs:151:5
|
贡献
我们绝对欢迎任何形式的贡献。错误报告、功能请求、文档,甚至 赞助。
如果您想通过拉取请求贡献代码,请将其针对我们的 develop
分支。master
分支旨在表示当前在 crates.io 上的内容。
提供 Postgres 内部的包装器不是一项简单任务,并且完全包装它将花费相当多的时间。现在 pgx
通常已经准备好使用,并且随着时间的推移将继续开发。我们非常感谢您对 pgx
可以做什么的反馈。
黑客攻击
如果您正在对 pgx
进行黑客攻击并希望确保您的测试可以正确运行,您需要将当前 cargo-pgx
(您正在工作的修订版)的实现放入您的 PATH
。
一种简单的方法是安装 cargo-local-install
cargo install cargo-local-install
然后运行 cargo local-install
以按顶级 Cargo.toml 中指定的方式安装 cargo-pgx
。
别忘了将 /path/to/pgx/bin
预先添加到您的 PATH
!
此方法还可以用于扩展,以确保使用匹配版本的 cargo-pgx
。
许可证
Portions Copyright 2019-2021 ZomboDB, LLC.
Portions Copyright 2021-2022 Technology Concepts & Design, Inc. <support@tcdi.com>.
All rights reserved.
Use of this source code is governed by the MIT license that can be found in the LICENSE file.
依赖关系
~7–11MB
~194K SLoC