A complete and mature WebAssembly runtime for openGauss based on WasmEdge. It's an original way to extend your favorite database capabilities.
Note This project is inspired by wasmer-postgres
Features:
- Easy to use: The
wasmedge
API mimics the standard WebAssembly API, - Fast:
wasmedge
executes the WebAssembly modules as fast as possible, close to native speed, - Safe: All calls to WebAssembly will be fast, but more importantly, completely safe and sandboxed.
Note: The project is still in heavy development. This is a 0.1.0 version. Some API are missing and are under implementation. But it's fun to play with it.
The project comes in two parts:
- A shared library, and
- A PL/pgSQL extension.
To compile the former, the wasmedge should have been installed. You can install the wasmedge as simple as
Refer to https://wasmedge.org/book/en/quick_start/install.html for more details.
After that, run CREATE EXTENSION wasm_executor
in a
openGauss shell. One new function will appear: wasm_new_instance
; It must be
called with the absolute path to the shared library. It looks like
this:
$ # Build the shared library.
$ make
$ # Install the extension in the opengauss
$ make install
$ # Activate and initialize the extension.
$ gsql -d postgres -c 'CREATE EXTENSION wasm_executor'
And you are ready to go!
Consider the examples/sum.rs
program:
#[no_mangle]
pub extern fn sum(x: i32, y: i32) -> i32 {
x + y
}
Once compiled to WebAssembly, one obtains a similar WebAssembly binary
to examples/sum.wasm
. To use the sum
exported function, first,
create a new instance of the WebAssembly module, and second,
call the sum
function.
To instantiate a WebAssembly module, the wasm_new_instance
function
must be used. It has two arguments:
- The absolute path to the WebAssembly module, and
- A namespace used to prefix exported functions in SQL.
For instance, calling
wasm_new_instance('/path/to/sum.wasm', 'wasm')
will create the
wasm_sum
function that is a direct call to the sum
exported function
of the WebAssembly instance. Thus:
-- New instance of the `sum.wasm` WebAssembly module.
SELECT wasm_new_instance('/absolute/path/to/sum.wasm', 'wasm');
-- Call a WebAssembly exported function!
SELECT wasm_sum(1, 2);
-- wasm_sum
-- --------
-- 3
-- (1 row)
Isn't it awesome? Calling Rust from openGauss through WebAssembly!
Let's inspect a little bit further the wasm_sum
function:
\x
\df+ wasm_sum
Schema | public
Name | wasm_sum
Result data type | integer
Argument data types | integer, integer
Type | normal
Volatility | volatile
Parallel | unsafe
Owner | ...
Language | plpgsql
Source code | ...
Description |
fencedmode | f
propackage | f
prokind | f
The openGauss wasm_sum
signature is (integer, integer) -> integer
,
which maps the Rust sum
signature (i32, i32) -> i32
.
So far, only the WebAssembly types i32
and i64
are
supported; they respectively map to integer
and bigint
in openGauss. Floats are partly implemented for the moment.
To get your hands on openGauss with wasm, we recommend using the Docker image. Download the docker image firstlly.
docker pull opengaussofficial/opengauss-wasmedge:0.1.0
Then run it.
docker run -it opengaussofficial/opengauss-wasmedge:0.1.0 bash
And enjoy it.
The extension provides two ways to initilize a WebAssembly instance. As you can
see from the functions name show above, one way is to use wasm_new_instance
from
.wasm file compiled from other languages.
And, the extension provides two tables, gathered together in
the wasm
foreign schema:
wasm.instances
is a table with theid
andwasm_file
columns, respectively for the instance ID, and the path of the WebAssembly module,wasm.exported_functions
is a table with theinstanceid
,funcname
,inputs
andoutput
columns, respectively for the instance ID of the exported function, its name, its input types (already formatted for openGauss), and its output types (already formatted for openGauss).
Let's see:
-- Select all WebAssembly instances.
SELECT * FROM wasm.instances;
-- id | wasm_file
-- ---------------+-------------------------------
-- 2785875771 | /absolute/path/to/sum.wasm
-- (1 row)
-- Select all exported functions for a specific instance.
SELECT
funcname,
inputs,
outputs
FROM
wasm.exported_functions
WHERE
instanceid = 2785875771;
-- name | inputs | outputs
-- --------+-----------------+---------
-- wasm_sum | integer,integer | integer
-- (1 row)
Benchmarks are useless most of the time, but it shows that WebAssembly can be a credible alternative to procedural languages such as PL/pgSQL. Please, don't take those numbers for granted, it can change at any time, but it shows promising results:
Benchmark | Runtime | Time (ms) | Ratio |
---|---|---|---|
Fibonacci (n = 50) | openGauss-wasm-executor |
0.765 | 1× |
PL/pgSQL | 1.714 | 2× | |
Fibonacci (n = 500) | openGauss-wasm-executor |
0.794 | 1× |
PL/pgSQL | 9.746 | 12× | |
Fibonacci (n = 5000) | openGauss-wasm-executor |
0.820 | 1× |
PL/pgSQL | 92.720 | 113× |
The entire project is under the MulanPSL2 License. Please read the LICENSE
file.