首页 > 其他分享 >使用pgrx开发postgre插件

使用pgrx开发postgre插件

时间:2024-11-12 17:41:55浏览次数:1  
标签:插件 postgre init pg key pgrx panic

pg插件开发建议在linux环境下进行, windows可以采用虚拟机的方式开发.

安装虚拟机环境

  1. 准备虚拟机, 使用的是ubuntu22.04, 太新的版本会依赖拉取有问题
  2. 安装开发工具和依赖:
    ​sudo apt-get update sudo apt-get install -y git clang gcc make build-essential libz-dev zlib1g-dev strace libssl-dev pkg-config libreadline-dev libpg-dev flex bison libxml2-dev libxslt-dev libxml2-utils xsltproc​
  3. 安装rust: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh​
  4. 安装cargo: sudo apt-get install cargo​
  5. 安装pgrx: cargo install cargo-pgrx​
  6. 初始化pgrx: cargo pgrx init​ 这会安装12 - 17版本的pg.
    耐心等待所有步骤完成后, 就可以使用pgrx新建模板来写插件了

hello pgrx

执行命令新建pg扩展项目: cargo pgrx new <project_name>​
使用生成的项目模板进行插件开发

调试

如果有需要, 可以修改自己要用的pg版本配置文件来方便调试, 例如要用pg16就改.pgrx/data-16

  1. pg_hba.conf和pg_ident.conf 支持外部工具连接pg
  2. postgresql.conf设置日志输出级别
    修改log_min_messages和client_min_messages

运行默认模板插件的函数

进入pgrx新建的项目目录后, 在控制台执行cargo pgrx run pg16表示在postgre16版本运行该插件.
默认端口起始是28800, 因此pg16开放的端口是28816(pg17就是28817),如果开放允许外部连接可以使用这个端口进去(pgrx run命令会自动接入到pg控制台模式)
执行sql安装pg扩展:

create extension <project_name>;
SELECT extname AS "Extension Name", extversion AS "Version"
FROM pg_extension;

<project_name>的来源是自己建立的项目名称.

调试用的宏

例: use pgrx::{debug1, debug5}
按照pg级别使用, 有:

  1. debug5!
  2. debug4!
  3. debug3!
  4. debug2!
  5. debug1!
  6. info!
  7. notice!
  8. warning!
  9. error!
  10. log!
  11. FATAL!
  12. PANIC!

自定义类型

see: 自定义类型官方示例
自定义类型需要实现序列化和反序列化:

#[derive(PostgresType, Deserialize, Serialize)]
pub struct MyType {}

重载运算符

see: 重载运算符官方示例

#[pg_operator(immutable, parallel_safe)]
#[opname(||)]
fn mytype_concact(mut left: MyType, right: MyType) -> MyType {
    left.0.push_str(&right.0);
    left
}

处理panic

官方提供了一个叫做PgTryBuilder的实现, 用来捕获rust中的panic.

#[pg_extern]
fn maybe_panic(panic: bool, trap_it: bool, message: &str) {
    PgTryBuilder::new(|| {
        if panic {
            panic!("panic says: {}", message)
            // std::panic::panic_any(42)
        }
    })
    .catch_rust_panic(|cause| {
        // we can catch general Rust panics.  The `error` argument is a pg_sys::panic::CaughtError::RustPanic
        // enum variant with the payload from the originating panic
        if trap_it {
            if let CaughtError::RustPanic { ereport, payload } = &cause {
                warning!("{:#?}", ereport);
                if let Some(s) = payload.downcast_ref::<String>() {
                    // we have access to the panic!() message
                    warning!("{}", s);
                    return;
                } else {
                    // this won't happen with this example, but say the `panic_any(42)` was used
                    // instead.  Then we'd be here, and we can just raise another `panic!()`, which
                    // will be what's ultimately reported to Postgres.
                    //
                    // In this case, Postgres' LOCATION error slot will be this line, and the CONTEXT
                    // slot will show the line number of the original `panic_any(42)` above
                    panic!("panic payload not a `String`");
                }
            }
            unreachable!("internal error:  `CaughtError` not a `::RustPanic`");
        } else {
            cause.rethrow()
        }
    })
    // finally block always runs after the catch handlers finish (even if they rethrow or raise
    // their own panic, like in this case)
    .finally(|| warning!("FINALLY!"))
    .execute()
}

在插件中执行SQL

see: 官方spi示例
see: hook列表(没有试过)
执行SQL需要用到pgrx提供的spi接口
这是一个在hook中执行sql的示例:

#[pg_guard]
pub unsafe extern "C" fn _PG_init() {
        PgTryBuilder::new(|| {
            let vec = generate_rsa_key().unwrap();
            Spi::connect(move |mut client| {
                let init_schema = format!(
                    r#"
                    create schema if not exists  {};
                "#,
                    PROJECT_SCHEMA
                );

                match client.update(init_schema.as_str(), None, None) {
                    Ok(_) => {}
                    Err(_) => {
                        return;
                    }
                };

                let init_sql = format!(
                    r#"
                create table if not exists  {}.t_rsa_key(
                    id serial8 not null primary key,
                    public_key text,
                    private_key text
                );
            "#,
                    PROJECT_SCHEMA
                );

                client.update(init_sql.as_str(), None, None).unwrap();
                let insert_sql = format!(
                    r#"
            insert into {}.t_rsa_key (public_key,private_key) values ('{}','{}');
            "#,
                    PROJECT_SCHEMA, vec[0], vec[1]
                );

                client.update(insert_sql.as_str(), None, None).unwrap();
            })
        })
        .execute();
}

关于_PG_init被调用多次的解决方式

https://stackoverflow.com/questions/28037300/in-postgresql-why-is-pg-init-called-twice
https://github.com/pgcentralfoundation/pgrx/blob/develop/pgrx-examples/shmem/README.md
(TODO: 其实我也没去处理这个问题)

标签:插件,postgre,init,pg,key,pgrx,panic
From: https://www.cnblogs.com/gan601/p/18542352

相关文章

  • MapReduce解析简历存储到Postgres数据库
    目录一、功能描述二、代码实现1、代码结构2、ResumeDBWritable代码3、ResumeWritable代码4、ResumeSDK代码 5、ResumeDBMapper代码6、ResumeDBReducer代码7、ResumeDBPartationer代码8、ResumeDBDriver代码一、功能描述简历数据经过ETL流程,已经上传到HDFS上,需要针......
  • ubuntu下配置vim插件,实现轻量级代码编辑器
    背景因为需要用虚拟机做实验,然后虚拟机配置的内存很小,如果使用vscode编辑器,内存占用太高,所以放弃,远程使用vscode通过sftp链接也会有很多bug,所以也放弃,鉴于以上。只能考虑使用vimvim的优点轻量级不需要gui的支持,可以在server和desktop版本之间不限制是使用vim插件安装cu......
  • H.264/H.265播放器EasyPlayer.js无插件直播流媒体音视频播放器延迟丢帧的原因
    EasyPlayer.jsH5播放器,是一款能够同时支持HTTP、HTTP-FLV、HLS(m3u8)、WS、WEBRTC、FMP4视频直播与视频点播等多种协议,支持H.264、H.265、AAC、G711A、Mp3等多种音视频编码格式,支持MSE、WASM、WebCodec等多种解码方式,支持Windows、Linux、Android、iOS全平台终端的H5播放器,使用简单......
  • 搭建 PostgreSQL 主从架构
    操作场景PostgreSQL是一个开源对象关系型数据库管理系统,并侧重于可扩展性和标准的符合性。PostgreSQL面向企业复杂SQL处理的OLTP在线事务处理场景,支持NoSQL数据类型(JSON/XML/hstore),支持GIS(GeographicInformationSystem或Geo-Informationsystem)地理信息处理,在可靠......
  • 让文献管理更轻松:Zotero10大插件指南
                       还在为海量文献管理头疼吗?还在为找不到合适的插件犯愁吗?别急,今天我就要带你解锁Zotero的终极武器-那些让你爱不释手的必备插件!作为一个从小白到文献管理达人的过来人,我可以负责任地说:没有这些插件,你的Zotero只能发挥一半功力!......
  • 插件工厂和AOP拦截器机制
    一.插件工厂基于接口机制的插件工厂是一种设计模式,用于创建和管理插件。插件是独立的模块,可以动态加载和卸载,以扩展应用程序的功能。通过使用接口,插件工厂可以提供一种统一的方式来创建和管理这些插件,而不需要了解插件的具体实现细节。具体实现来说,实现一个插件工厂通过哈希记......
  • 【Playwright + Python】系列(九)Playwright 调用 Chrome 插件,小白也能事半功倍
    哈喽,大家好,我是六哥!今天我来给大家分享一下如何使用playwight调用chrome插件,面向对象为功能测试及零基础小白,我尽量用大白话的方式举例讲解,力求所有人都能看懂,建议大家先收藏,以免后面找不到。......
  • 【教程】第四章:任务与评论插件 —— 如虎添翼,顺利掌握
    回顾上一节小伙伴们还记得上一节的挑战任务吗?我们要为任务表配置状态和附件字段,并在任务列表里展示它们。别急,咱们先揭晓答案!状态字段的配置:选择下拉菜单(单选)字段,填写选项标签:未开始、进行中、待审核、已完成、已取消、已归档。颜色根据你的喜好自由设置,给任务增添一点......
  • PostgreSQL流复制主从监控和自动故障转移的轻量级实现
    如何实现PostgreSQL的高可用,之前研究过repmgr以及pg_auto_failover,起作用都是起到主节点故障时,实现“自动故障转移”的目的。但是repmgr以及pg_auto_failover得缺点是对数据库侵入过多,需要在监控的数据库内部进行一系列的配置操作,同时需要启动第三方服务实现节点的可用性监控,这又......
  • OMV安装文件管理器filebrowser和照片管理photoprism插件时Pull不了镜像的解决办法
    OMV安装文件管理器filebrowser和照片管理photoprism插件安装后不能启动服务或者PULL不了镜像卡着不动都是因为现在国内pull不了镜像的原因这里有个迷惑的人的地方是很多朋友认为是用docker来pull的镜像,于是增加了docker国内加速源后发现OMV还是拉取不了镜像。解决方法如下:因为OM......