PostgreSQL distinguishes itself from other relational databases through its extensibility and support for object-oriented design. This allows you to create custom types, functions, and more. Amazon Relational Database Service (Amazon RDS) for PostgreSQL supports the PL/Rust extension, enabling developers to build safe and performant database functions in the Rust programming language. As an additional improvement to this process, Amazon RDS for PostgreSQL also supports PGRX, a framework that can map PostgreSQL types to their Rust counterparts, making it easier to work with PostgreSQL data in PL/Rust functions.
JSON objects use human-readable text to store and transmit data objects consisting of attribute–value pairs and arrays or other serializable values. Their versatility and readability make them widely used for exchanging data between clients and servers in web applications. However, PostgreSQL only supports four basic data types when working with JSON, and creating one with many attributes by hand, or converting them to text and back, can be greatly inefficient and tedious. Today, this can all be resolved in a single function with the newly added Serde crate support.
In this post, we showcase how to use PGRX and PL/Rust to efficiently access and manipulate all built-in PostgreSQL data types in Rust. We demonstrate how to write performant functions that create and serialize JSON objects that include these built-in types. These functions are directly usable in your database and use the newly supported serde
and serde_json
crates. We also walk through deploying an Amazon RDS for PostgreSQL instance with PL/Rust enabled, and how PGRX type mapping allows you to use all built-in PostgreSQL types in a JSON object.
Solutions overview
PGRX supports PostgreSQL major versions 12 through 17. This post demonstrates the solution using version 17.2.
Prerequisites
To run the example in this post, you need to provision an RDS for PostgreSQL instance or Multi-AZ DB cluster running PostgreSQL 13.12 or higher, 14.9 or higher, 15.2 or higher, 16.1 or higher, or 17.1 or higher. Additionally, you need to add plrust
to the shared_preload_libraries
parameter into a DB parameter group and assign the DB parameter group to your PostgreSQL database instance.
You can use the AWS Command Line Interface (AWS CLI) to create a DB parameter group:
Modify your parameter group to add plrust
to the shared_preload_libraries
parameter:
To create a PostgreSQL database instance with the parameter group:
If you modify the shared_preload_libraries
parameter on an existing database instance, the changes will not take effect until the instance is rebooted. You can also modify the parameter group directly from the AWS Management Console. If you create an instance directly with your custom parameter group, you can start using plrust
when the instance is available. For more information, see Working with DB parameter groups.
Install the PL/Rust extension
Connect to the database and verify that PL/Rust is enabled in shared_preload_libraries:
Create the PL/Rust extension:
You should see successful extension creation:
PGRX PostgreSQL type mapping
In this section, we discuss PGRX PostgreSQL type mapping.
PostgreSQL built-in data types
PostgreSQL has built-in time functions. For example, run the following query:
You should see the following output with a timestamp:
You can also retrieve the underlying PostgreSQL type of this timestamp:
You should see that this is a timestamp with time zone
type:
Run the following query to get the current year in SQL:
You should see the year:
Access built-in data types in PL/Rust
PGRX provides a Rust mapping to PostgreSQL data types, allowing you to work with PostgreSQL types directly in your Rust functions. Let’s look at an example where we manipulate the timestamp with time zone type in PL/Rust using PGRX.
Create the following function:
You should see successful function creation:
Provide this function with a timestamp and run the following query:
You should see the year of the timestamp you provided:
We can see here that through PGRX type mapping pgrx::TimestampWithTimeZone
, we were able to access a PostgreSQL type in PL/Rust. In the next section, we serialize this type into JSON, which was not possible previously, because PostgreSQL only supports string, number, boolean, and null. PGRX has a type mapping for nearly every PostgreSQL built-in type, as well as related functions. For more information, refer to the PGRX official documentation.
Custom types serialization
In this section, we demonstrate how to build a PL/Rust function to define a custom type, and serialize it into JSON using the Serde crates. This function uses TimestampWithTimeZone
, which is a type unsupported by PostgreSQL JSON objects.
Create the following function in your database, public.my_serialize()
, which returns text
:
You should see successful function creation:
Execute the function with the following query:
You should see the following output:
timetz
might be different depending on the current time of your AWS Region.
Breaking down the function
Run the following query to view all PL/Rust allowed dependencies. Though this post focuses on serde/serde_json, note that Amazon RDS for PostgreSQL supports many other crates:
You need to declare serde and serde_json as dependencies that you want use in the PL/Rust function:
In the code section, import what you need from the crates:
Declare your custom type. Note the macro that makes this type visible to serde and serde_json. This custom type can be scaled to include more fields based on your needs:
Create an instance of your custom type based on what was passed in, and return a JSON in the form of text:
Cleanup
To clean up your resources, run the following query to remove anything PL/Rust related:
See the following output, dropping the extension and function you created:
You can delete your RDS for PostgreSQL instance if you no longer need to use it.
Conclusion
In this post, we covered how PGRX type mappings can help you access PostgreSQL built-in types when writing a PL/Rust function. We also demonstrated how crates supported by Amazon RDS, serde
and serde_json
, can be used to serialize Rust custom types into different forms, specifically a JSON string. We broke down the example associated with doing so, and explained how the example can be scaled to meet your needs.
Try this solution with your own use case, and let us know your thoughts in the comments.
About the author
Michael You is a Software Development Engineer on the Amazon RDS for PostgreSQL team. He focuses on bringing in open-source technologies to managed PostgreSQL at AWS.
Source: Read More