{"id":13478438,"url":"https://github.com/pgcentralfoundation/pgrx","last_synced_at":"2025-05-06T01:33:19.693Z","repository":{"id":37077254,"uuid":"228908078","full_name":"pgcentralfoundation/pgrx","owner":"pgcentralfoundation","description":"Build Postgres Extensions with Rust!","archived":false,"fork":false,"pushed_at":"2025-04-13T17:45:33.000Z","size":34687,"stargazers_count":3969,"open_issues_count":304,"forks_count":277,"subscribers_count":39,"default_branch":"develop","last_synced_at":"2025-05-04T23:47:56.228Z","etag":null,"topics":["postgres","postgresql","postgresql-extension","rust","rustlang"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pgcentralfoundation.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["eeeebbbbrrrr","workingjubilee"]}},"created_at":"2019-12-18T19:30:29.000Z","updated_at":"2025-05-04T11:41:43.000Z","dependencies_parsed_at":"2023-11-23T05:40:27.229Z","dependency_job_id":"cfc99217-25a8-44ea-9a1e-a79cd306a963","html_url":"https://github.com/pgcentralfoundation/pgrx","commit_stats":{"total_commits":1863,"total_committers":112,"mean_commits":"16.633928571428573","dds":"0.44068706387546963","last_synced_commit":"4bb1ccce4b34f5a424ef2c416b5ae82874efde2b"},"previous_names":["tcdi/pgx","tcdi/pgrx"],"tags_count":136,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pgcentralfoundation%2Fpgrx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pgcentralfoundation%2Fpgrx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pgcentralfoundation%2Fpgrx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pgcentralfoundation%2Fpgrx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pgcentralfoundation","download_url":"https://codeload.github.com/pgcentralfoundation/pgrx/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252553230,"owners_count":21766853,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["postgres","postgresql","postgresql-extension","rust","rustlang"],"created_at":"2024-07-31T16:01:57.033Z","updated_at":"2025-05-06T01:33:19.642Z","avatar_url":"https://github.com/pgcentralfoundation.png","language":"Rust","readme":"![Logo](art/pgrx-logo-color-transparent-475x518.png)\n\n# `pgrx`\n\n\u003e Build Postgres Extensions with Rust!\n\n![GitHub Actions badge](https://github.com/pgcentralfoundation/pgrx/actions/workflows/tests.yml/badge.svg)\n[![crates.io badge](https://img.shields.io/crates/v/pgrx.svg)](https://crates.io/crates/pgrx)\n[![docs.rs badge](https://docs.rs/pgrx/badge.svg)](https://docs.rs/pgrx)\n[![Twitter Follow](https://img.shields.io/twitter/follow/pgrx_rs.svg?style=flat)](https://twitter.com/pgrx_rs)\n[![Discord Chat](https://img.shields.io/discord/710918545906597938.svg)][Discord]\n\n\n`pgrx` is a framework for developing PostgreSQL extensions in Rust and strives to be as idiomatic and safe as possible.\n\n`pgrx` supports Postgres 13 through Postgres 17.\n\n## Want to chat with us or get a question answered?\n\n   + **Please join our [Discord Server][Discord].**\n\n   + **We are also in need of financial [sponsorship](https://checkout.square.site/merchant/MLHG5M9GAXQPV/checkout/2OW2SULDQBSZ2JLHSLRZQLZH).**\n\n## Key Features\n\n- **A fully managed development environment with [`cargo-pgrx`](cargo-pgrx/README.md)**\n   + `cargo pgrx new`: Create new extensions quickly\n   + `cargo pgrx init`: Install new (or register existing) PostgreSQL installs\n   + `cargo pgrx run`: Run your extension and interactively test it in `psql` (or `pgcli`)\n   + `cargo pgrx test`: Unit-test your extension across multiple PostgreSQL versions\n   + `cargo pgrx package`: Create installation packages for your extension\n   + More in the [`README.md`](cargo-pgrx/README.md)!\n- **Target Multiple Postgres Versions**\n   + Support from Postgres 13 to Postgres 17 from the same codebase\n   + Use Rust feature gating to use version-specific APIs\n   + Seamlessly test against all versions\n- **Automatic Schema Generation**\n   + Implement extensions entirely in Rust\n   + [Automatic mapping for many Rust types into PostgreSQL](#mapping-of-postgres-types-to-rust)\n   + SQL schemas generated automatically (or manually via `cargo pgrx schema`)\n   + Include custom SQL with `extension_sql!` \u0026 `extension_sql_file!`\n- **Safety First**\n   + Translates Rust `panic!`s into Postgres `ERROR`s that abort the transaction, not the process\n   + Memory Management follows Rust's drop semantics, even in the face of `panic!` and `elog(ERROR)`\n   + `#[pg_guard]` procedural macro to ensure the above\n   + Postgres `Datum`s are `Option\u003cT\u003e where T: FromDatum`\n      - `NULL` Datums are safely represented as `Option::\u003cT\u003e::None`\n- **First-class UDF support**\n   + Annotate functions with `#[pg_extern]` to expose them to Postgres\n   + Return `pgrx::iter::SetOfIterator\u003c'a, T\u003e` for `RETURNS SETOF`\n   + Return `pgrx::iter::TableIterator\u003c'a, T\u003e` for `RETURNS TABLE (...)`\n   + Create trigger functions with `#[pg_trigger]`\n- **Easy Custom Types**\n   + `#[derive(PostgresType)]` to use a Rust struct as a Postgres type\n      - By default, represented as a CBOR-encoded object in-memory/on-disk, and JSON as human-readable\n      - Provide custom in-memory/on-disk/human-readable representations\n   + `#[derive(PostgresEnum)]` to use a Rust enum as a Postgres enum\n   + Composite types supported with the `pgrx::composite_type!(\"Sample\")` macro\n- **Server Programming Interface (SPI)**\n   + Safe access into SPI\n   + Transparently return owned Datums from an SPI context\n- **Advanced Features**\n   + Safe access to Postgres' `MemoryContext` system via `pgrx::PgMemoryContexts`\n   + Executor/planner/transaction/subtransaction hooks\n   + Safely use Postgres-provided pointers with `pgrx::PgBox\u003cT\u003e` (akin to `alloc::boxed::Box\u003cT\u003e`)\n   + `#[pg_guard]` proc-macro for guarding `extern \"C-unwind\"` Rust functions that need to be passed into Postgres\n   + Access Postgres' logging system through `eprintln!`-like macros\n   + Direct `unsafe` access to large parts of Postgres internals via the `pgrx::pg_sys` module\n   + New features added regularly!\n\n## System Requirements\n\nPGRX has been tested to work on x86_64⹋ and aarch64⹋ Linux and aarch64 macOS and x86_64⹋ Windows targets.\nIt is currently expected to work on other \"Unix\" OS with possible small changes, but those remain untested.\n\n- A Rust toolchain: `rustc`, `cargo`, and `rustfmt`. The recommended way to get these is from https://rustup.rs †\n- `git`\n- `libclang` 11 or greater (for bindgen)\n   - Debian-likes: `apt install libclang-dev` or `apt install clang`\n   - RHEL-likes: `yum install clang`\n   - Windows: download installers from https://github.com/llvm/llvm-project/releases\n- C compiler\n   - Linux and MacOS: GCC or Clang if `cshim` feature is enabled, and no need if the `cshim` feature is disabled\n   - Windows: MSVC or Clang\n- [PostgreSQL's build dependencies](https://wiki.postgresql.org/wiki/Compile_and_Install_from_source_code) ‡\n   - Debian-likes: `sudo apt-get install build-essential libreadline-dev zlib1g-dev flex bison libxml2-dev libxslt-dev libssl-dev libxml2-utils xsltproc ccache pkg-config`\n   - RHEL-likes: `sudo yum install -y bison-devel readline-devel zlib-devel openssl-devel wget ccache \u0026\u0026 sudo yum groupinstall -y 'Development Tools'`\n\n † PGRX has no MSRV policy, thus may require the latest stable version of Rust, available via Rustup\n\n ‡ A local PostgreSQL server installation is not required. On Linux and MacOS, `cargo pgrx` can download and compile PostgreSQL versions on its own. On Windows, `cargo pgrx` downloads precompiled PostgreSQL versions from EnterpriseDB.\n\n ⹋ PGRX has not been tested to work on 32-bit, but the library attempts to handle conversion of `pg_sys::Datum`\nto and from `int8` and `double` types. Use it only for your own risk. We do not plan to add official support\nwithout considerable ongoing technical and financial contributions.\n\n### macOS\n\nRunning PGRX on a Mac requires some additional setup.\n\nThe Mac C compiler (clang) and related tools are bundled with [XCode](https://developer.apple.com/xcode/). \nXCode can be installed from the Mac App Store.\n\nFor additional C libraries, it's easiest to use [Homebrew](https://brew.sh/). In particular, \nyou will probably need these if you don't have them already:\n\n```zsh\nbrew install git icu4c pkg-config\n```\nThe config script that Postgres 17 uses in its build process does not automatically detect \nthe Homebrew install directory. (Earlier versions of Postgres do not have this problem.) \nYou may see this error:\n\n```configure: error: ICU library not found```\n\nTo fix it, run\n```\nexport PKG_CONFIG_PATH=/opt/homebrew/opt/icu4c/lib/pkgconfig\n```\non the command line before you run ```cargo pgrx init```\n\nEvery once in a while, XCode will update itself and move the directory that contains\nthe C compiler. When the Postgres ./config process runs during the build, it grabs the current directory\nand stores it, which means that there will be build errors if you do a full rebuild of your\nproject and the old directory has disappeared. The solution is re-run `cargo pgrx init` so the\nPostgres installs get rebuilt.\n\n### Windows\n\nRunning PGRX on Windows requires MSVC prerequisites.\n\nOn Windows, please follow https://rust-lang.github.io/rustup/installation/windows-msvc.html to set up it.\n\n## Getting Started\n\nBefore anything else, install the [system dependencies](#system-requirements).\n\nNow install the `cargo-pgrx` sub-command.\n\n```bash\ncargo install --locked cargo-pgrx\n```\n\nOnce `cargo-pgrx` is ready you can initialize the \"PGRX Home\" directory:\n\n```bash\ncargo pgrx init\n```\n\nThe `init` command downloads all currently supported PostgreSQL versions, compiles them\nto `${PGRX_HOME}`, and runs `initdb`.\n\nIt's also possible to use an existing (user-writable) PostgreSQL install, or install a subset of versions, see the [`README.md` of `cargo-pgrx` for details](cargo-pgrx/README.md#first-time-initialization).\n\nNow you can begin work on a specific pgrx extension:\n\n```bash\ncargo pgrx new my_extension\ncd my_extension\n```\n\nThis will create a new directory for the extension crate.\n\n```\n$ tree \n.\n├── Cargo.toml\n├── my_extension.control\n├── sql\n└── src\n    └── lib.rs\n\n2 directories, 3 files\n```\n\nThe new extension includes an example, so you can go ahead and run it right away.\n\n```bash\ncargo pgrx run\n```\n\nThis compiles the extension to a shared library, copies it to the specified Postgres installation, starts that Postgres instance and connects you to a database named the same as the extension.\n\nOnce `cargo-pgrx` drops us into `psql` we can [load the extension](https://www.postgresql.org/docs/13/sql-createextension.html) and do a SELECT on the example function.\n\n```sql\nmy_extension=# CREATE EXTENSION my_extension;\nCREATE EXTENSION\n\nmy_extension=# SELECT hello_my_extension();\n hello_my_extension\n---------------------\n Hello, my_extension\n(1 row)\n```\n\nFor more details on how to manage pgrx extensions see [Managing pgrx extensions](cargo-pgrx/README.md).\n\n## Cross-compiling\n\nSo far, cross-compiling extensions with pgrx has only been demonstrated under [nix](https://nixos.org/).\nProper support in nixpkgs is still in flux, so watch this space.\n\nIn order to cross-compile outside of nix, you will need two ingredients:\n\n1) A sysroot for the cross architecture, with rust configured to invoke the linker with flags to link against this sysroot.\n2) A `pg_config` program that provides values associated with postgres compiled for the desired cross architecture.\n   This can be achieved by either emulating pg_config with qemu-user or similar, or replicating pg_config with a shell script.\n\nThen, modify the standard build process in the following ways:\n\n1) Pass `--no-run` to `cargo pgrx init`, since we cannot run postgres for the cross machine.\n2) Pass one of the `--pgXX` flags to `cargo pgrx init` with the aforementioned `pg_config`.\n3) Pass the `--pg-config` flag to `cargo pgrx package` with the aforementioned `pg_config`.\n4) Pass the `--target` flag to `cargo pgrx package` with the rust triple of the cross machine.\n\n`cargo pgrx run` will not not work.\n\n## Upgrading\n\nAs new Postgres versions are supported by `pgrx`, you can re-run the `pgrx init` process to download and compile them:\n\n```bash\ncargo pgrx init\n```\n\n## Mapping of Postgres types to Rust\n\n| Postgres Type              | Rust Type (as `Option\u003cT\u003e`)                              |\n|----------------------------|---------------------------------------------------------|\n| `bytea`                    | `Vec\u003cu8\u003e` or `\u0026[u8]` (zero-copy)                        |\n| `text`                     | `String` or `\u0026str` (zero-copy)                          |\n| `varchar`                  | `String` or `\u0026str` (zero-copy) or `char`                |\n| `\"char\"`                   | `i8`                                                    |\n| `smallint`                 | `i16`                                                   |\n| `integer`                  | `i32`                                                   |\n| `bigint`                   | `i64`                                                   |\n| `oid`                      | `u32`                                                   |\n| `real`                     | `f32`                                                   |\n| `double precision`         | `f64`                                                   |\n| `bool`                     | `bool`                                                  |\n| `json`                     | `pgrx::Json(serde_json::Value)`                         |\n| `jsonb`                    | `pgrx::JsonB(serde_json::Value)`                        |\n| `date`                     | `pgrx::Date`                                            |\n| `time`                     | `pgrx::Time`                                            |\n| `timestamp`                | `pgrx::Timestamp`                                       |\n| `time with time zone`      | `pgrx::TimeWithTimeZone`                                |\n| `timestamp with time zone` | `pgrx::TimestampWithTimeZone`                           |\n| `anyarray`                 | `pgrx::AnyArray`                                        |\n| `anyelement`               | `pgrx::AnyElement`                                      |\n| `box`                      | `pgrx::pg_sys::BOX`                                     |\n| `point`                    | `pgrx::pg_sys::Point`                                   |\n| `tid`                      | `pgrx::pg_sys::ItemPointerData`                         |\n| `cstring`                  | `\u0026core::ffi::CStr`                                      |\n| `inet`                     | `pgrx::Inet(String)` -- TODO: needs better support      |\n| `numeric`                  | `pgrx::Numeric\u003cP, S\u003e or pgrx::AnyNumeric`               |\n| `void`                     | `()`                                                    |\n| `ARRAY[]::\u003ctype\u003e`          | `Vec\u003cOption\u003cT\u003e\u003e` or `pgrx::Array\u003cT\u003e` (zero-copy)        |\n| `int4range`                | `pgrx::Range\u003ci32\u003e`                                      |\n| `int8range`                | `pgrx::Range\u003ci64\u003e`                                      |\n| `numrange`                 | `pgrx::Range\u003cNumeric\u003cP, S\u003e\u003e` or `pgrx::Range\u003cAnyRange\u003e` |\n| `daterange`                | `pgrx::Range\u003cpgrx::Date\u003e`                               |\n| `tsrange`                  | `pgrx::Range\u003cpgrx::Timestamp\u003e`                          |\n| `tstzrange`                | `pgrx::Range\u003cpgrx::TimestampWithTimeZone\u003e`              |\n| `NULL`                     | `Option::None`                                          |\n| `internal`                 | `pgrx::PgBox\u003cT\u003e` where `T` is any Rust/Postgres struct  |\n| `uuid`                     | `pgrx::Uuid([u8; 16])`                                  |\n\nThere are also `IntoDatum` and `FromDatum` traits for implementing additional type conversions,\nalong with `#[derive(PostgresType)]` and `#[derive(PostgresEnum)]` for automatic conversion of\ncustom types.\n\nNote that `text` and `varchar` are converted to `\u0026str` or `String`, so PGRX\nassumes any Postgres database you use it with has UTF-8-compatible encoding.\nCurrently, PGRX will panic if it detects this is incorrect, to inform you, the\nprogrammer, that you were wrong. However, it is best to not rely on this\nbehavior, as UTF-8 validation can be a performance hazard. This problem was\npreviously assumed to simply not happen, and PGRX may decide to change the\ndetails of how it does UTF-8 validation checks in the future in order to\nmitigate performance hazards.\n\nThe default Postgres server encoding is `SQL_ASCII`, and it guarantees neither\nASCII nor UTF-8 (as Postgres will then accept but ignore non-ASCII bytes).\nFor best results, always use PGRX with UTF-8, and set database encodings\nexplicitly upon database creation.\n\n## Digging Deeper\n\n - [cargo-pgrx sub-command](cargo-pgrx/)\n - [Custom Types](pgrx-examples/custom_types/)\n - [Postgres Operator Functions and Operator Classes/Families](pgrx-examples/operators/)\n - [Shared Memory Support](pgrx-examples/shmem/)\n - [various examples](pgrx-examples/)\n\n## Caveats \u0026 Known Issues\n\nThere's probably more than are listed here, but a primary things of note are:\n\n - Threading is not really supported.  Postgres is strictly single-threaded.  As such, if you do venture into using threads, those threads **MUST NOT** call *any* internal Postgres function, or otherwise use any Postgres-provided pointer.  There's also a potential problem with Postgres' use of `sigprocmask`.  This was being discussed on the -hackers list, even with a patch provided, but the conversation seems to have stalled (https://www.postgresql.org/message-id/flat/5EF20168.2040508%40anastigmatix.net#4533edb74194d30adfa04a6a2ce635ba).\n - How to correctly interact with Postgres in an `async` context remains unexplored.\n - `pgrx` wraps a lot of `unsafe` code, some of which has poorly-defined safety conditions. It may be easy to induce illogical and undesirable behaviors even from safe code with `pgrx`, and some of these wrappers may be fundamentally unsound. Please report any issues that may arise.\n - Not all of Postgres' internals are included or even wrapped.  This isn't due to it not being possible, it's simply due to it being an incredibly large task.  If you identify internal Postgres APIs you need, open an issue and we'll get them exposed, at least through the `pgrx::pg_sys` module.\n - Sessions started before `ALTER EXTENSION my_extension UPDATE;` will continue to see the old version of `my_extension`. New sessions will see the updated version of the extension.\n - `pgrx` is used by many \"in production\", but it is not \"1.0.0\" or above, despite that being recommended by SemVer for production-quality software. This is because there are many unresolved soundness and ergonomics questions that will likely require breaking changes to resolve, in some cases requiring cutting-edge Rust features to be able to expose sound interfaces. While a 1.0.0 release is intended at some point, it seems prudent to wait until it seems like a 2.0.0 release would not be needed the next week and the remaining questions can be deferred.\n\n## TODO\n\nThere's a few things on our immediate TODO list\n\n - Automatic extension schema upgrade scripts\n - Improved unit testing framework\n - Better/Safer API for Datum management\n - Improved generated bindings organization\n - Safely wrap more Postgres internal APIs\n - More examples -- especially around memory management and the various derive macros `#[derive(PostgresType/Enum)]`\n\n\n## Feature Flags\nPGRX has optional feature flags for Rust code that do not involve configuring the version of Postgres used,\nbut rather extend additional support for other kinds of Rust code. These are not included by default.\n\n\n### \"unsafe-postgres\": Allow compilation for Postgres forks that have a different ABI\n\nAs of Postgres 15, forks are allowed to specify they use a different ABI than canonical Postgres.\nSince pgrx makes countless assumptions about Postgres' internal ABI it is not possible for it to \nguarantee that a compiled pgrx extension will probably execute within such a Postgres fork.  You,\ndear compiler runner, can make this guarantee for yourself by specifying the `unsafe-postgres` \nfeature flag.  Otherwise, a pgrx extension will fail to compile with an error similar to:\n\n```\nerror[E0080]: evaluation of constant value failed\n   --\u003e pgrx/src/lib.rs:151:5\n    |\n151 | /     assert!(\n152 | |         same_slice(pg_sys::FMGR_ABI_EXTRA, b\"xPostgreSQL\\0\"),\n153 | |         \"Unsupported Postgres ABI. Perhaps you need `--features unsafe-postgres`?\",\n154 | |     );\n    | |_____^ the evaluated program panicked at 'Unsupported Postgres ABI. Perhaps you need `--features unsafe-postgres`?', pgrx/src/lib.rs:151:5\n    |\n```\n\n\n## Contributing\n\nWe are most definitely open to contributions of any kind.  Bug Reports, Feature Requests, and Documentation.\n\nIf you'd like to contribute code via a Pull Request, please make it against our `develop` branch.  The `master` branch is no longer used.\n\nProviding wrappers for Postgres' internals is not a straightforward task, and completely wrapping it is going\nto take quite a bit of time.  `pgrx` is generally ready for use now, and it will continue to be developed as\ntime goes on.  Your feedback about what you'd like to be able to do with `pgrx` is greatly appreciated.\n\n## Hacking\n\nIf you're hacking on `pgrx` and want to ensure your test will run correctly, you need to have the current\nimplementation of `cargo-pgrx` (from the revision you're working on) in your `PATH`.\n\nAn easy way would be to install [cargo-local-install](https://github.com/MaulingMonkey/cargo-local-install):\n\n```shell\ncargo install cargo-local-install\n```\n\nand then run `cargo local-install` to install `cargo-pgrx` as specified in top-level's Cargo.toml.\n\nDon't forget to prepend `/path/to/pgrx/bin` to your `PATH`!\n\nThis approach can also be used in extensions to ensure a matching version of `cargo-pgrx` is used.\n\n## License\n\n```\nPortions Copyright 2019-2021 ZomboDB, LLC.  \nPortions Copyright 2021-2023 Technology Concepts \u0026 Design, Inc.\nPortions Copyright 2023 PgCentral Foundation, Inc.\n\nAll rights reserved.\nUse of this source code is governed by the MIT license that can be found in the LICENSE file.\n```\n\n[Discord]: https://discord.gg/PMrpdJsqcJ\n[timecrate]: https://crates.io/crates/time\n","funding_links":["https://github.com/sponsors/eeeebbbbrrrr","https://github.com/sponsors/workingjubilee"],"categories":["Rust","Extension Hacking","\u003ca name=\"Rust\"\u003e\u003c/a\u003eRust"],"sub_categories":["Tools"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpgcentralfoundation%2Fpgrx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpgcentralfoundation%2Fpgrx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpgcentralfoundation%2Fpgrx/lists"}