Hereโs a well-structured draft for your technical blog post based on the provided Rust + pgrx Foreign Data Wrapper (FDW) code.
๐ Building a Simple PostgreSQL FDW with Rust and pgrx
PostgreSQL Foreign Data Wrappers (FDW) enable PostgreSQL to query external data sources as if they were regular tables. Traditionally, FDWs are written in C, but with pgrx
, we can now build PostgreSQL extensions โ including FDWs โ in Rust, unlocking safety and modern tooling.
In this post, weโll walk through creating a simple FDW using Rust and pgrx
that simulates reading rows from an external source (e.g., Redis or API). While itโs a stub, it demonstrates how to implement the core FDW lifecycle.
๐ ๏ธ What Can You Build with pgrx
?
- โ SQL Functions: Scalar, aggregate, and set-returning functions.
- โ Custom Types: Define composite types or enums in Rust.
- โ Foreign Data Wrappers (FDWs): Like the one in your example โ connect PostgreSQL to external systems (Redis, APIs, file systems, etc.).
- โ Index Access Methods: Implement new index types.
- โ Background Workers: Run tasks in the background inside PostgreSQL.
- โ Hooks: Intercept or modify PostgreSQL internal behavior (like planner or executor hooks).
๐ Under the hood:
- PostgreSQL communicates via C APIs.
pgrx
provides Rust-safe bindings to these APIs.- Memory management is handled carefully via
PgMemoryContexts
, matching PostgreSQLโs memory context model. - Rust functions are exposed to PostgreSQL as SQL-callable functions with the
#[pg_extern]
macro.
๐๏ธ Key Components of an default_fdw
PostgreSQL FDWs consist of several callback functions that handle different phases of query planning and execution:
Example extension default_fdw
Planning Phase:
GetForeignRelSize
: Estimate rows.GetForeignPaths
: Generate access paths.GetForeignPlan
: Create the scan plan.
Execution Phase:
BeginForeignScan
: Initialize the scan.IterateForeignScan
: Produce each row.ReScanForeignScan
: Restart the scan if needed.EndForeignScan
: Cleanup.
How to use
1 | create foreign data wrapper default_wrapper |
Then we can select hello table.
1 | select * from hello; |
๐ง Setting Up the FDW Handler
The entry point is the FDW handler function, which PostgreSQL calls to retrieve a set of function pointers.
1 |
|
๐ฆ Extracting Foreign Table Options
PostgreSQL allows specifying options like hostnames or credentials when creating a foreign table. This function retrieves those options:
1 | unsafe fn get_foreign_table_options(relid: pg_sys::Oid) -> HashMap<String, String> { |
This is crucial when your FDW needs to connect to external systems like Redis, REST APIs, or filesystems.
๐ Planner Callbacks
1๏ธโฃ GetForeignRelSize
Estimates the number of rows in the foreign table.
1 |
|
2๏ธโฃ GetForeignPaths
Defines possible access paths for the planner.
1 |
|
3๏ธโฃ GetForeignPlan
Generates the actual execution plan.
1 |
|
โถ๏ธ Execution Callbacks
๐ BeginForeignScan
Initializes the scan.
1 |
|
๐ IterateForeignScan
Produces rows one at a time.
1 |
|
This example emits five rows with (id, name)
pairs like (1, hello_1)
.
๐ ReScanForeignScan
Handles rescan requests.
1 |
|
๐ EndForeignScan
Frees resources.
1 |
|
๐๏ธ Utilities
Tuple clearing is handled by this helper:
1 | unsafe fn exec_clear_tuple(slot: *mut pg_sys::TupleTableSlot) { |
๐ Conclusion
This post walked you through the basics of building a PostgreSQL FDW using Rust and pgrx
. While this example generates dummy data, the same structure can be extended to connect with real-world systems like Redis, REST APIs, or message queues.
๐ Next Steps
- Add connection logic to Redis or any backend.
- Support
INSERT
,UPDATE
,DELETE
by implementing the modification callbacks. - Package and distribute as a PostgreSQL extension.
๐ References
If youโd like, I can help refine this post further, format it for Medium/Dev.to, or extend it with Redis connection examples. Would you like that?
__ๆญคๆไฝ่
__๏ผDaniel Shih(็ณ้ ญ)
__ๆญคๆๅฐๅ__๏ผ https://isdaniel.github.io/rust-pgrx-extension-fdw/
__็ๆฌ่ฒๆ__๏ผๆฌๅๅฎขๆๆๆ็ซ ้ค็นๅฅ่ฒๆๅค๏ผๅๆก็จ CC BY-NC-SA 3.0 TW ่จฑๅฏๅ่ญฐใ่ฝ่ผ่ซ่จปๆๅบ่๏ผ