diff --git a/README.md b/README.md index 8f0cf0c7be26736c917a176e8a5f7beb518e1c2d..d43667355836d2bf5cb35a7a591e11efc21c8e40 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,42 @@ pub extern fn sum(x: i32, y: i32) -> i32 { } ``` +For able to compile the rust code to wasm, the rust and wasm toolchain should be installed. +``` +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh +rustup target add wasm32-unknown-unknown + +``` +And also install wasm-opt, which will be used to optimize and compress the .wasm file output +``` +cargo install wasm-opt +``` +Then create a project using cargo +``` +cargo new hello --lib +``` +The file Cargo.toml (aka "manifest") contains the project's configuration. Leave everything, but append a new block called [lib]. The result should look something this +``` +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +[lib] +crate-type = ["cdylib"] +``` +Rust code lives in the src directory. Your new project contains the default file src/lib.rs. Replace its contents with the sum.rs. +And then compile the project to Wasm and shrink the wasm output. + +``` +cargo build --target wasm32-unknown-unknown --release +wasm-opt -Os target/wasm32-unknown-unknown/release/hello.wasm -o hello.wasm +``` + 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, @@ -122,13 +158,14 @@ To get your hands on openGauss with wasm, we recommend using the Docker image. Download the docker image firstlly. ```shell -docker pull opengaussofficial/opengauss-wasmedge:0.1.0 +docker pull opengauss/wasmedge:0.2.0 ``` Then run it. ```shell -docker run -it opengaussofficial/opengauss-wasmedge:0.1.0 bash +docker run -it opengauss/wasmedge:0.2.0 bash ``` -And enjoy it. +The rust and wasm toolchain have already installed in the docker image for quick use. +So just go ahead and enjoy it. ## Inspect a WebAssembly instance diff --git a/docker/Dockerfile b/docker/Dockerfile index 27da78bbd7cfc83f8e9d8cf1ef63e2603ad1eb6b..830d498d24c5b8cf314684466264ea2b99791592 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -2,7 +2,7 @@ FROM openeuler/openeuler:22.03-lts MAINTAINER openGauss-ml@openguass.org LABEL MAIL="heguofeng@huawei.com" \ CREATE_DATE="2022-10" \ - GAUSS_SERVER="openGauss-3.1.0" + GAUSS_SERVER="openGauss-5.0.0" RUN \ sed -i "s/gpgcheck=1/gpgcheck=0/g" /etc/yum.repos.d/openEuler.repo && \ @@ -24,26 +24,30 @@ USER opengauss:opengauss RUN cp -f /home/opengauss/bashrc /home/opengauss/.bashrc && \ cd /home/opengauss && \ if [ "`uname -m`" == "x86_64" ]; then \ - wget -q https://opengauss.obs.cn-south-1.myhuaweicloud.com/3.1.0/binarylibs/openGauss-third_party_binarylibs_openEuler_x86_64.tar.gz -O openGauss_third.tar.gz; \ + wget -q https://opengauss.obs.cn-south-1.myhuaweicloud.com/5.0.0/binarylibs/openGauss-third_party_binarylibs_openEuler_x86_64.tar.gz -O openGauss_third.tar.gz; \ else \ - wget -q https://opengauss.obs.cn-south-1.myhuaweicloud.com/3.1.0/binarylibs/openGauss-third_party_binarylibs_openEuler_arm.tar.gz -O openGauss_third.tar.gz; \ + wget -q https://opengauss.obs.cn-south-1.myhuaweicloud.com/5.0.0/binarylibs/openGauss-third_party_binarylibs_openEuler_arm.tar.gz -O openGauss_third.tar.gz; \ fi && \ tar -xf openGauss_third.tar.gz && mv openGauss-third_party_binarylibs* binarylibs && rm -f openGauss_third.tar.gz && \ curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash -s -- -v 0.11.2 && source /home/opengauss/.wasmedge/env && \ - source /home/opengauss/.bashrc && git clone https://gitee.com/Nelson-He/openGauss-server.git && cd openGauss-server && \ + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && source "$HOME/.cargo/env" && \ + rustup target add wasm32-unknown-unknown && \ + cargo install wasm-gc && source /home/opengauss/.bashrc && \ + wget -q https://gitee.com/opengauss/openGauss-server/repository/archive/v5.0.0.zip && unzip -q v5.0.0.zip && rm -rf v5.0.0.zip && \ + cd openGauss-server-v5.0.0 && \ ./configure --gcc-version=7.3.0 CC=g++ CFLAGS='-O2' \ --prefix=$GAUSSHOME --3rd=$BINARYLIBS \ --enable-cassert --enable-thread-safety \ --without-readline --without-zlib && \ make -sj 8 && make install -sj 8 && \ cd /home/opengauss && git clone https://gitee.com/Nelson-He/openGauss-wasm.git -b wasmedge && \ - cp -rf openGauss-wasm/wasm openGauss-server/contrib && \ - cd openGauss-server/contrib/wasm && make && make install && \ + cp -rf openGauss-wasm/wasm openGauss-server-v5.0.0/contrib && \ + cd openGauss-server-v5.0.0/contrib/wasm && make && make install && \ cd /home/opengauss && \ chmod +x /home/opengauss/entrypoint.sh && \ - cp /home/opengauss/openGauss-server/contrib/wasm/examples/* /home/opengauss && \ + cp /home/opengauss/openGauss-server-v5.0.0/contrib/wasm/examples/* /home/opengauss && \ sudo rm -rf /home/opengauss/binarylibs && \ - sudo rm -rf /home/opengauss/openGauss-server && \ + sudo rm -rf /home/opengauss/openGauss-server-v5.0.0 && \ sudo rm -rf /home/opengauss/openGauss-wasm && \ sudo yum remove -y make cmake git && \ sudo yum clean all diff --git a/wasm/examples/encrypt_decrypt/Cargo.toml b/wasm/examples/encrypt_decrypt/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..68cc4249424efbae67c1e6f7676b02ed12b00262 --- /dev/null +++ b/wasm/examples/encrypt_decrypt/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "opengauss_encrypt_decrypt" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +opengauss_bindgen = { version = "0", path = "../../bindgen" } +magic-crypt = "3.1" + +[lib] +crate-type = ["cdylib"] diff --git a/wasm/examples/encrypt_decrypt/README b/wasm/examples/encrypt_decrypt/README new file mode 100644 index 0000000000000000000000000000000000000000..a8d595098268dc3b4e0b998305941958e3325412 --- /dev/null +++ b/wasm/examples/encrypt_decrypt/README @@ -0,0 +1,28 @@ +CREATE EXTENSION wasm_executor; + +SELECT wasm_new_instance('/home/opengauss/encrypt_decrypt.wasm', 'gs'); + +CREATE TABLE users ( +username TEXT PRIMARY KEY, +email TEXT, +passwd TEXT +); + +CREATE TABLE secrets(secret text); +INSERT INTO secrets VALUES ('s3cretk3y'); + +CREATE OR REPLACE FUNCTION encrypt_password() RETURNS TRIGGER AS +$$ + DECLARE + BEGIN + UPDATE users SET passwd = gs_encrypt(NEW.passwd, (SELECT secret FROM secrets LIMIT 1)) WHERE username = NEW.username; + RETURN NEW; + END +$$LANGUAGE PLPGSQL; + +CREATE TRIGGER encrypt_passwd_trigger AFTER INSERT ON users FOR EACH ROW EXECUTE PROCEDURE encrypt_password(); + +INSERT INTO users VALUES ('peter', 'peter@huawei.com', 'roe-deer'); +INSERT INTO users VALUES ('josh', 'josh@huawei.com', 'turso'); + +SELECT username, passwd, gs_decrypt(passwd, (SELECT secret FROM secrets LIMIT 1)) AS decrypted FROM users; diff --git a/wasm/examples/encrypt_decrypt/encrypt_decrypt.wasm b/wasm/examples/encrypt_decrypt/encrypt_decrypt.wasm new file mode 100644 index 0000000000000000000000000000000000000000..2179154507dcd5cf426deece6b6f4760ecac8d9e Binary files /dev/null and b/wasm/examples/encrypt_decrypt/encrypt_decrypt.wasm differ diff --git a/wasm/examples/encrypt_decrypt/gen_wasm.sh b/wasm/examples/encrypt_decrypt/gen_wasm.sh new file mode 100755 index 0000000000000000000000000000000000000000..558691b33b018228160b9ada926b38599a3af467 --- /dev/null +++ b/wasm/examples/encrypt_decrypt/gen_wasm.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -e + +OPENGAUSS_EXPORTED_FUNC=$1 +OPENGAUSS_COMPILED_WASM=opengauss-target/wasm32-unknown-unknown/release/encrypt_decrypt.wasm +OPENGAUSS_OPTIMIZED_WASM=opengauss-target/encrypt_decrypt.wasm + +CARGO_TARGET_DIR=opengauss-target cargo build --release --target wasm32-unknown-unknown +wasm-opt -Os $OPENGAUSS_COMPILED_WASM -o $OPENGAUSS_OPTIMIZED_WASM || : + diff --git a/wasm/examples/encrypt_decrypt/src/lib.rs b/wasm/examples/encrypt_decrypt/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..847e89a8b904ea9eb82457a1393be51304b711f7 --- /dev/null +++ b/wasm/examples/encrypt_decrypt/src/lib.rs @@ -0,0 +1,15 @@ +use opengauss_bindgen::*; +use magic_crypt::{new_magic_crypt, MagicCryptTrait}; + +#[opengauss_bindgen::opengauss_bindgen] +pub fn encrypt(data: String, key: String) -> String { + let mc = new_magic_crypt!(key, 256); + mc.encrypt_str_to_base64(data) +} + +#[opengauss_bindgen::opengauss_bindgen] +pub fn decrypt(data: String, key: String) -> String { + let mc = new_magic_crypt!(key, 256); + mc.decrypt_base64_to_string(data) + .unwrap_or("[ACCESS DENIED]".to_owned()) +} diff --git a/wasm/wasm_executor--1.0.sql b/wasm/wasm_executor--1.0.sql index ff2d52cacfe70465dc5ed10438124a8afd9992e9..6c5ffa1535357ea8d70a959477bbd7c1bc1ddc3e 100644 --- a/wasm/wasm_executor--1.0.sql +++ b/wasm/wasm_executor--1.0.sql @@ -12,7 +12,8 @@ CREATE TABLE wasm.instances( ); CREATE TABLE wasm.exported_functions( - instanceid bigint, + instanceid bigint, + namespace text, funcname text, inputs text, outputs text @@ -41,59 +42,49 @@ RETURNS int8 AS 'MODULE_PATHNAME', 'wasm_create_instance' LANGUAGE C STRICT; -CREATE FUNCTION wasm_invoke_function_0(text, text) -RETURNS int8 -AS 'MODULE_PATHNAME', 'wasm_invoke_function_0' +CREATE FUNCTION wasm_drop_instance(int8) +RETURNS text +AS 'MODULE_PATHNAME', 'wasm_drop_instance' LANGUAGE C STRICT; -CREATE FUNCTION wasm_invoke_function_1(text, text, int8) +CREATE FUNCTION wasm_invoke_function_int8_0(text, text) RETURNS int8 -AS 'MODULE_PATHNAME', 'wasm_invoke_function_1' +AS 'MODULE_PATHNAME', 'wasm_invoke_function_int8_0' LANGUAGE C STRICT; -CREATE FUNCTION wasm_invoke_function_2(text, text, int8, int8) +CREATE FUNCTION wasm_invoke_function_int8_1(text, text, int8) RETURNS int8 -AS 'MODULE_PATHNAME', 'wasm_invoke_function_2' +AS 'MODULE_PATHNAME', 'wasm_invoke_function_int8_1' LANGUAGE C STRICT; -CREATE FUNCTION wasm_invoke_function_3(text, text, int8, int8, int8) +CREATE FUNCTION wasm_invoke_function_int8_2(text, text, int8, int8) RETURNS int8 -AS 'MODULE_PATHNAME', 'wasm_invoke_function_3' +AS 'MODULE_PATHNAME', 'wasm_invoke_function_int8_2' LANGUAGE C STRICT; -CREATE FUNCTION wasm_invoke_function_4(text, text, int8, int8, int8, int8) +CREATE FUNCTION wasm_invoke_function_int8_3(text, text, int8, int8, int8) RETURNS int8 -AS 'MODULE_PATHNAME', 'wasm_invoke_function_4' +AS 'MODULE_PATHNAME', 'wasm_invoke_function_int8_3' LANGUAGE C STRICT; -CREATE FUNCTION wasm_invoke_function_5(text, text, int8, int8, int8, int8, int8) +CREATE FUNCTION wasm_invoke_function_int8_4(text, text, int8, int8, int8, int8) RETURNS int8 -AS 'MODULE_PATHNAME', 'wasm_invoke_function_5' +AS 'MODULE_PATHNAME', 'wasm_invoke_function_int8_4' LANGUAGE C STRICT; -CREATE FUNCTION wasm_invoke_function_6(text, text, int8, int8, int8, int8, int8, int8) +CREATE FUNCTION wasm_invoke_function_int8_5(text, text, int8, int8, int8, int8, int8) RETURNS int8 -AS 'MODULE_PATHNAME', 'wasm_invoke_function_6' +AS 'MODULE_PATHNAME', 'wasm_invoke_function_int8_5' LANGUAGE C STRICT; -CREATE FUNCTION wasm_invoke_function_7(text, text, int8, int8, int8, int8, int8, int8, int8) -RETURNS int8 -AS 'MODULE_PATHNAME', 'wasm_invoke_function_7' -LANGUAGE C STRICT; - -CREATE FUNCTION wasm_invoke_function_8(text, text, int8, int8, int8, int8, int8, int8, int8, int8) -RETURNS int8 -AS 'MODULE_PATHNAME', 'wasm_invoke_function_8' +CREATE FUNCTION wasm_invoke_function_text_1(text, text, text) +RETURNS text +AS 'MODULE_PATHNAME', 'wasm_invoke_function_text_1' LANGUAGE C STRICT; -CREATE FUNCTION wasm_invoke_function_9(text, text, int8, int8, int8, int8, int8, int8, int8, int8, int8) -RETURNS int8 -AS 'MODULE_PATHNAME', 'wasm_invoke_function_9' -LANGUAGE C STRICT; - -CREATE FUNCTION wasm_invoke_function_10(text, text, int8, int8, int8, int8, int8, int8, int8, int8, int8, int8) -RETURNS int8 -AS 'MODULE_PATHNAME', 'wasm_invoke_function_10' +CREATE FUNCTION wasm_invoke_function_text_2(text, text, text, text) +RETURNS text +AS 'MODULE_PATHNAME', 'wasm_invoke_function_text_2' LANGUAGE C STRICT; CREATE OR REPLACE FUNCTION wasm_new_instance(module_pathname text, namespace text) RETURNS text AS $$ @@ -102,13 +93,14 @@ DECLARE exported_function RECORD; exported_function_generated_inputs text; exported_function_generated_outputs text; + exported_function_bind_outputs text; BEGIN -- Create a new instance, and stores its ID in `current_instance_id`. SELECT wasm_create_new_instance(module_pathname) INTO STRICT current_instance_id; -- Insert the wasm information to gloable table INSERT INTO wasm.instances SELECT id, wasm_file FROM wasm_get_instances() WHERE id = current_instance_id; - INSERT INTO wasm.exported_functions SELECT current_instance_id, funcname, inputs, outputs FROM wasm_get_exported_functions(current_instance_id); + INSERT INTO wasm.exported_functions SELECT current_instance_id, namespace, funcname, inputs, outputs FROM wasm_get_exported_functions(current_instance_id); -- Generate functions for each exported functions from the WebAssembly instance. FOR @@ -126,14 +118,15 @@ BEGIN (SELECT * FROM wasm_get_exported_functions(current_instance_id)) LOOP IF exported_function.input_arity > 10 THEN - RAISE EXCEPTION 'WebAssembly exported function `%` has an arity greater than 10, which is not supported yet.', exported_function.funcname; + RAISE EXCEPTION 'WebAssembly exported function `%` has an arity greater than 5, which is not supported yet.', exported_function.funcname; END IF; exported_function_generated_inputs := ''; exported_function_generated_outputs := ''; + exported_function_bind_outputs :=''; FOR nth IN 1..exported_function.input_arity LOOP - exported_function_generated_inputs := exported_function_generated_inputs || format(', CAST($%s AS int8)', nth); + exported_function_generated_inputs := exported_function_generated_inputs || format(', $%s', nth); END LOOP; IF length(exported_function.outputs) > 0 THEN @@ -142,12 +135,18 @@ BEGIN exported_function_generated_outputs := 'integer'; END IF; + IF exported_function_generated_outputs = 'text' THEN + exported_function_bind_outputs := 'text'; + ELSE + exported_function_bind_outputs := 'int8'; + END IF; + EXECUTE format( 'CREATE OR REPLACE FUNCTION %I_%I(%3$s) RETURNS %5$s AS $F$' || 'DECLARE' || ' output %5$s;' || 'BEGIN' || - ' SELECT wasm_invoke_function_%4$s(%6$L, %2$L%7$s) INTO STRICT output;' || + ' SELECT wasm_invoke_function_%8$s_%4$s(%6$L, %2$L%7$s) INTO STRICT output;' || ' RETURN output;' || 'END;' || '$F$ LANGUAGE plpgsql;', @@ -157,10 +156,46 @@ BEGIN exported_function.input_arity, -- 4 exported_function_generated_outputs, -- 5 current_instance_id, -- 6 - exported_function_generated_inputs -- 7 + exported_function_generated_inputs, -- 7 + exported_function_bind_outputs --8 ); END LOOP; RETURN current_instance_id; END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION wasm_delete_instance(delete_instance int8) RETURNS text AS $$ +DECLARE + instance_module_path text; + exported_function RECORD; +BEGIN + -- Create a new instance, and stores its ID in `current_instance_id`. + SELECT wasm_drop_instance(delete_instance) INTO STRICT instance_module_path; + + -- Generate functions for each exported functions from the WebAssembly instance. + FOR + exported_function + IN + SELECT + namespace, + funcname, + inputs + FROM + wasm.exported_functions WHERE instanceid = delete_instance + LOOP + + EXECUTE format( + 'DROP FUNCTION %I_%I(%3$s)', + exported_function.namespace, -- 1 + exported_function.funcname, -- 2 + exported_function.inputs + ); + END LOOP; + + DELETE FROM wasm.instances WHERE id = delete_instance; + DELETE FROM wasm.exported_functions WHERE instanceid = delete_instance; + + RETURN instance_module_path; +END; $$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/wasm/wasm_executor.cpp b/wasm/wasm_executor.cpp index 00df1a823086d22065dc7d34a3d96562f1aefff6..87513aa1eb61e1d71d022e31552690cf0b85c839 100644 --- a/wasm/wasm_executor.cpp +++ b/wasm/wasm_executor.cpp @@ -13,19 +13,20 @@ PG_MODULE_MAGIC; extern "C" Datum wasm_create_instance(PG_FUNCTION_ARGS); +extern "C" Datum wasm_drop_instance(PG_FUNCTION_ARGS); extern "C" Datum wasm_get_instances(PG_FUNCTION_ARGS); extern "C" Datum wasm_get_exported_functions(PG_FUNCTION_ARGS); -extern "C" Datum wasm_invoke_function_0(PG_FUNCTION_ARGS); -extern "C" Datum wasm_invoke_function_1(PG_FUNCTION_ARGS); -extern "C" Datum wasm_invoke_function_2(PG_FUNCTION_ARGS); -extern "C" Datum wasm_invoke_function_3(PG_FUNCTION_ARGS); -extern "C" Datum wasm_invoke_function_4(PG_FUNCTION_ARGS); -extern "C" Datum wasm_invoke_function_5(PG_FUNCTION_ARGS); -extern "C" Datum wasm_invoke_function_6(PG_FUNCTION_ARGS); -extern "C" Datum wasm_invoke_function_7(PG_FUNCTION_ARGS); -extern "C" Datum wasm_invoke_function_8(PG_FUNCTION_ARGS); -extern "C" Datum wasm_invoke_function_9(PG_FUNCTION_ARGS); -extern "C" Datum wasm_invoke_function_10(PG_FUNCTION_ARGS); +extern "C" Datum wasm_invoke_function_int8_0(PG_FUNCTION_ARGS); +extern "C" Datum wasm_invoke_function_int8_1(PG_FUNCTION_ARGS); +extern "C" Datum wasm_invoke_function_int8_2(PG_FUNCTION_ARGS); +extern "C" Datum wasm_invoke_function_int8_3(PG_FUNCTION_ARGS); +extern "C" Datum wasm_invoke_function_int8_4(PG_FUNCTION_ARGS); +extern "C" Datum wasm_invoke_function_int8_5(PG_FUNCTION_ARGS); +extern "C" Datum wasm_invoke_function_text_1(PG_FUNCTION_ARGS); +extern "C" Datum wasm_invoke_function_text_2(PG_FUNCTION_ARGS); + +static const char * const malloc_func = "opengauss_malloc"; +static const char OPENGAUSS_TEXT = 3; typedef struct TupleInstanceState { TupleDesc tupd; @@ -46,7 +47,7 @@ typedef struct TupleFuncState { } TupleFuncState; #define BUF_LEN 256 -#define MAX_PARAMS 10 +#define MAX_PARAMS 5 #define MAX_RETURNS 1 // Store the wasm file info globally @@ -81,22 +82,6 @@ static std::vector* find_exported_func_list(int64 instanceid) return NULL; } -static WasmFuncInfo* find_exported_func(int64 instanceid, std::string funcname) -{ - std::vector* functions = find_exported_func_list(instanceid); - if (functions == NULL) { - ereport(ERROR, (errmsg("wasm_executor: function infos of instance %ld is not find", instanceid))); - } - for (std::vector::iterator curr = functions->begin(); curr != functions->end(); curr++) { - if ((*curr)->funcname == funcname) { - return *curr; - } - } - - ereport(ERROR, (errmsg("wasm_executor: function %s not exist in instance %ld ", funcname.c_str(), instanceid))); - return NULL; -} - static int64 generate_uuid(Datum input) { Datum uuid = DirectFunctionCall1(hashtext, input); @@ -110,7 +95,6 @@ static int64 wasm_invoke_function(char *instanceid_str, char* funcname, std::vec if (wasm_file == "") { ereport(ERROR, (errmsg("wasm_executor: instance with id %ld is not find", instanceid))); } - WasmFuncInfo *funcinfo = find_exported_func(instanceid, funcname); WasmEdge_ConfigureContext *config_context = WasmEdge_ConfigureCreate(); WasmEdge_ConfigureAddHostRegistration(config_context, WasmEdge_HostRegistration_Wasi); @@ -118,11 +102,7 @@ static int64 wasm_invoke_function(char *instanceid_str, char* funcname, std::vec WasmEdge_Value params[args.size()]; for (unsigned int i = 0; i < args.size(); ++i) { - if (funcinfo->inputs[i] == "integer") { - params[i] = WasmEdge_ValueGenI32(args[i]); - } else { - params[i] = WasmEdge_ValueGenI64(args[i]); - } + params[i] = WasmEdge_ValueGenI64(args[i]); } WasmEdge_Value result[1]; @@ -135,11 +115,7 @@ static int64 wasm_invoke_function(char *instanceid_str, char* funcname, std::vec ereport(ERROR, (errmsg("wasm_executor: call func %s failed", funcname))); } int64 ret_val = 0; - if (funcinfo->outputs == "integer") { - ret_val = WasmEdge_ValueGetI32(result[0]); - } else { - ret_val = WasmEdge_ValueGetI64(result[0]); - } + ret_val = WasmEdge_ValueGetI64(result[0]); /* Resources deallocations. */ WasmEdge_VMDelete(vm_conext); WasmEdge_ConfigureDelete(config_context); @@ -148,6 +124,98 @@ static int64 wasm_invoke_function(char *instanceid_str, char* funcname, std::vec return ret_val; } +static char* wasm_invoke_function2(char *instanceid_str, char* funcname, std::vector args) +{ + int64 instanceid = atol(instanceid_str); + std::string wasm_file = find_wasm_file(instanceid); + if (wasm_file == "") { + ereport(ERROR, (errmsg("wasm_executor: instance with id %ld is not find", instanceid))); + } + + WasmEdge_ConfigureContext *config_context = WasmEdge_ConfigureCreate(); + WasmEdge_ConfigureAddHostRegistration(config_context, WasmEdge_HostRegistration_Wasi); + WasmEdge_ConfigureAddHostRegistration(config_context, WasmEdge_HostRegistration_WasiNN); + WasmEdge_VMContext *vm_conext = WasmEdge_VMCreate(config_context, NULL); + + WasmEdge_Result res = WasmEdge_VMLoadWasmFromFile(vm_conext, wasm_file.c_str()); + if (!WasmEdge_ResultOK(res)) { + ereport(ERROR, (errmsg("wasm_executor: wasm vm load failed: %s", WasmEdge_ResultGetMessage(res)))); + } + + res = WasmEdge_VMValidate(vm_conext); + if (!WasmEdge_ResultOK(res)) { + ereport(ERROR, (errmsg("wasm_executor: wasm vm validate failed: %s", WasmEdge_ResultGetMessage(res)))); + } + + res = WasmEdge_VMInstantiate(vm_conext); + if (!WasmEdge_ResultOK(res)) { + ereport(ERROR, (errmsg("wasm_executor: wasm vm initialize failed: %s", WasmEdge_ResultGetMessage(res)))); + } + + const WasmEdge_ModuleInstanceContext* instance_ctx = WasmEdge_VMGetActiveModule(vm_conext); + WasmEdge_String mem_name = WasmEdge_StringCreateByCString("memory"); + WasmEdge_MemoryInstanceContext* mem_ctx = WasmEdge_ModuleInstanceFindMemory(instance_ctx, mem_name); + WasmEdge_StringDelete(mem_name); + + WasmEdge_Value results[1]; + WasmEdge_Value malloc_param[1]; + WasmEdge_Value params[args.size()]; + + int mem_size = WasmEdge_MemoryInstanceGetPageSize(mem_ctx) * 65536; + int mem_offset = mem_size; + + for (unsigned int i = 0; i < args.size(); ++i) { + int text_len = strlen(args[i]); + const char *text = args[i]; + malloc_param[0] = WasmEdge_ValueGenI32(text_len + 2); + WasmEdge_String wasmedge_func_name = WasmEdge_StringCreateByCString("opengauss_malloc"); + res = WasmEdge_VMExecute(vm_conext, wasmedge_func_name, malloc_param, 1, results, 1); + WasmEdge_StringDelete(wasmedge_func_name); + if (!WasmEdge_ResultOK(res)) { + ereport(ERROR, (errmsg("wasm_executor: call opengauss malloc failed"))); + } + mem_offset = WasmEdge_ValueGetI32(results[0]); + + uint8_t *data = WasmEdge_MemoryInstanceGetPointer(mem_ctx, mem_offset, text_len + 2); + data[0] = OPENGAUSS_TEXT; + memcpy(data + 1, text, text_len); + data[1 + text_len] = '\0'; + params[i] = WasmEdge_ValueGenI32(mem_offset); + } + + WasmEdge_String wasmedge_func_name = WasmEdge_StringCreateByCString(funcname); + res = WasmEdge_VMExecute(vm_conext, wasmedge_func_name, params, args.size(), results, 1); + WasmEdge_StringDelete(wasmedge_func_name); + if (!WasmEdge_ResultOK(res)) { + ereport(ERROR, (errmsg("wasm_executor: call func %s failed", funcname))); + } + + int type_offset = WasmEdge_ValueGetI32(results[0]); + char *type_ptr = (char *)WasmEdge_MemoryInstanceGetPointer(mem_ctx, type_offset, 1); + if (!type_ptr) { + ereport(ERROR, (errmsg("Unexpected end of Wasm memory when trying to fetch results"))); + } + char type = *type_ptr; + if (type != OPENGAUSS_TEXT) { + ereport(ERROR, (errmsg("Unsupported type of wasm: %d", type))); + } + + const char *wasm_result = type_ptr + 1; + size_t wasm_result_len = strlen(wasm_result); + char *result = (char *)pg_malloc(wasm_result_len + 1); + if (!result) { + ereport(ERROR, (errmsg("malloc memory for result failed, size: %ld", wasm_result_len))); + } + memcpy(result, wasm_result, wasm_result_len); + result[wasm_result_len] = '\0'; + + /* Resources deallocations. */ + WasmEdge_VMDelete(vm_conext); + WasmEdge_ConfigureDelete(config_context); + + return result; +} + static void wasm_export_funcs_query(int64 instanceid, TupleFuncState* inter_call_data) { std::string wasm_file = find_wasm_file(instanceid); @@ -181,9 +249,13 @@ static void wasm_export_funcs_query(int64 instanceid, TupleFuncState* inter_call */ uint32_t rel_func_num = WasmEdge_VMGetFunctionList(vm_cxt, func_name_list, func_type_list, BUF_LEN); for (unsigned int i = 0; i < rel_func_num && i < BUF_LEN; ++i) { - char tmp_buffer[BUF_LEN]; + char tmp_buffer[BUF_LEN] = {0}; uint32_t func_name_len = WasmEdge_StringCopy(func_name_list[i], tmp_buffer, sizeof(tmp_buffer)); elog(DEBUG1, "wasm_executor: exported function string length: %u, name: %s\n", func_name_len, tmp_buffer); + if (strcmp(tmp_buffer, malloc_func) == 0) { + elog(DEBUG1, "wasm_executor: opengauss_malloc is not need to export to user\n"); + continue; + } uint32_t param_nums = WasmEdge_FunctionTypeGetParametersLength(func_type_list[i]); if (param_nums > MAX_PARAMS) { @@ -201,11 +273,11 @@ static void wasm_export_funcs_query(int64 instanceid, TupleFuncState* inter_call WasmFuncInfo *funcinfo = new(std::nothrow)WasmFuncInfo(); - enum WasmEdge_ValType param_buffer[10]; // we allow max 10 parameters - param_nums = WasmEdge_FunctionTypeGetParameters(func_type_list[i], param_buffer, 10); + enum WasmEdge_ValType param_buffer[MAX_PARAMS]; // we allow max 10 parameters + param_nums = WasmEdge_FunctionTypeGetParameters(func_type_list[i], param_buffer, MAX_PARAMS); for (unsigned int j = 0; j < param_nums; ++j) { if (param_buffer[j] == WasmEdge_ValType_I32) { - funcinfo->inputs.push_back("integer"); + funcinfo->inputs.push_back("text"); } else if (param_buffer[j] == WasmEdge_ValType_I64) { funcinfo->inputs.push_back("bigint"); } else { @@ -217,7 +289,7 @@ static void wasm_export_funcs_query(int64 instanceid, TupleFuncState* inter_call return_num = WasmEdge_FunctionTypeGetReturns(func_type_list[i], param_buffer, 10); if (param_buffer[0] == WasmEdge_ValType_I32) { - funcinfo->outputs = "integer"; + funcinfo->outputs = "text"; } else if (param_buffer[0] == WasmEdge_ValType_I64) { funcinfo->outputs = "bigint"; } else { @@ -281,6 +353,34 @@ Datum wasm_create_instance(PG_FUNCTION_ARGS) return Int64GetDatum(uuid); } +PG_FUNCTION_INFO_V1(wasm_drop_instance); +Datum wasm_drop_instance(PG_FUNCTION_ARGS) +{ + int64 instanceid = PG_GETARG_INT64(0); + Datum module_path; + + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("wasm_executor: must be system admin to delete wasm instance")))); + + std::map::iterator institor = instances.begin(); + while (institor != instances.end() && institor->first != instanceid) { + institor++; + } + if (institor == instances.end()) { + ereport(ERROR, (errmsg("wasm_executor:instance with id=%ld not exist", instanceid))); + } + module_path = CStringGetTextDatum((institor->second).c_str()); + instances.erase(institor); + + std::map*>::iterator funcitor = exported_functions.begin(); + while (funcitor != exported_functions.end() && funcitor->first == instanceid) { + exported_functions.erase(funcitor++); + } + + return module_path; +} + PG_FUNCTION_INFO_V1(wasm_get_instances); Datum wasm_get_instances(PG_FUNCTION_ARGS) { @@ -393,8 +493,8 @@ Datum wasm_get_exported_functions(PG_FUNCTION_ARGS) } } -PG_FUNCTION_INFO_V1(wasm_invoke_function_0); -Datum wasm_invoke_function_0(PG_FUNCTION_ARGS) +PG_FUNCTION_INFO_V1(wasm_invoke_function_int8_0); +Datum wasm_invoke_function_int8_0(PG_FUNCTION_ARGS) { char* instanceid = TextDatumGetCString(PG_GETARG_DATUM(0)); char* funcname = TextDatumGetCString(PG_GETARG_DATUM(1)); @@ -404,8 +504,8 @@ Datum wasm_invoke_function_0(PG_FUNCTION_ARGS) return Int64GetDatum(result); } -PG_FUNCTION_INFO_V1(wasm_invoke_function_1); -Datum wasm_invoke_function_1(PG_FUNCTION_ARGS) +PG_FUNCTION_INFO_V1(wasm_invoke_function_int8_1); +Datum wasm_invoke_function_int8_1(PG_FUNCTION_ARGS) { char* instanceid = TextDatumGetCString(PG_GETARG_DATUM(0)); char* funcname = TextDatumGetCString(PG_GETARG_DATUM(1)); @@ -416,8 +516,8 @@ Datum wasm_invoke_function_1(PG_FUNCTION_ARGS) return Int64GetDatum(result); } -PG_FUNCTION_INFO_V1(wasm_invoke_function_2); -Datum wasm_invoke_function_2(PG_FUNCTION_ARGS) +PG_FUNCTION_INFO_V1(wasm_invoke_function_int8_2); +Datum wasm_invoke_function_int8_2(PG_FUNCTION_ARGS) { char* instanceid = TextDatumGetCString(PG_GETARG_DATUM(0)); char* funcname = TextDatumGetCString(PG_GETARG_DATUM(1)); @@ -429,8 +529,8 @@ Datum wasm_invoke_function_2(PG_FUNCTION_ARGS) return Int64GetDatum(result); } -PG_FUNCTION_INFO_V1(wasm_invoke_function_3); -Datum wasm_invoke_function_3(PG_FUNCTION_ARGS) +PG_FUNCTION_INFO_V1(wasm_invoke_function_int8_3); +Datum wasm_invoke_function_int8_3(PG_FUNCTION_ARGS) { char* instanceid = TextDatumGetCString(PG_GETARG_DATUM(0)); char* funcname = TextDatumGetCString(PG_GETARG_DATUM(1)); @@ -443,8 +543,8 @@ Datum wasm_invoke_function_3(PG_FUNCTION_ARGS) return Int64GetDatum(result); } -PG_FUNCTION_INFO_V1(wasm_invoke_function_4); -Datum wasm_invoke_function_4(PG_FUNCTION_ARGS) +PG_FUNCTION_INFO_V1(wasm_invoke_function_int8_4); +Datum wasm_invoke_function_int8_4(PG_FUNCTION_ARGS) { char* instanceid = TextDatumGetCString(PG_GETARG_DATUM(0)); char* funcname = TextDatumGetCString(PG_GETARG_DATUM(1)); @@ -458,8 +558,8 @@ Datum wasm_invoke_function_4(PG_FUNCTION_ARGS) return Int64GetDatum(result); } -PG_FUNCTION_INFO_V1(wasm_invoke_function_5); -Datum wasm_invoke_function_5(PG_FUNCTION_ARGS) +PG_FUNCTION_INFO_V1(wasm_invoke_function_int8_5); +Datum wasm_invoke_function_int8_5(PG_FUNCTION_ARGS) { char* instanceid = TextDatumGetCString(PG_GETARG_DATUM(0)); char* funcname = TextDatumGetCString(PG_GETARG_DATUM(1)); @@ -474,97 +574,29 @@ Datum wasm_invoke_function_5(PG_FUNCTION_ARGS) return Int64GetDatum(result); } -PG_FUNCTION_INFO_V1(wasm_invoke_function_6); -Datum wasm_invoke_function_6(PG_FUNCTION_ARGS) +PG_FUNCTION_INFO_V1(wasm_invoke_function_text_1); +Datum wasm_invoke_function_text_1(PG_FUNCTION_ARGS) { char* instanceid = TextDatumGetCString(PG_GETARG_DATUM(0)); char* funcname = TextDatumGetCString(PG_GETARG_DATUM(1)); - std::vector params; - - params.push_back(PG_GETARG_INT64(2)); - params.push_back(PG_GETARG_INT64(3)); - params.push_back(PG_GETARG_INT64(4)); - params.push_back(PG_GETARG_INT64(5)); - params.push_back(PG_GETARG_INT64(6)); - params.push_back(PG_GETARG_INT64(7)); - int64 result = wasm_invoke_function(instanceid, funcname, params); - return Int64GetDatum(result); -} -PG_FUNCTION_INFO_V1(wasm_invoke_function_7); -Datum wasm_invoke_function_7(PG_FUNCTION_ARGS) -{ - char* instanceid = TextDatumGetCString(PG_GETARG_DATUM(0)); - char* funcname = TextDatumGetCString(PG_GETARG_DATUM(1)); - std::vector params; - - params.push_back(PG_GETARG_INT64(2)); - params.push_back(PG_GETARG_INT64(3)); - params.push_back(PG_GETARG_INT64(4)); - params.push_back(PG_GETARG_INT64(5)); - params.push_back(PG_GETARG_INT64(6)); - params.push_back(PG_GETARG_INT64(7)); - params.push_back(PG_GETARG_INT64(8)); - int64 result = wasm_invoke_function(instanceid, funcname, params); - return Int64GetDatum(result); -} - -PG_FUNCTION_INFO_V1(wasm_invoke_function_8); -Datum wasm_invoke_function_8(PG_FUNCTION_ARGS) -{ - char* instanceid = TextDatumGetCString(PG_GETARG_DATUM(0)); - char* funcname = TextDatumGetCString(PG_GETARG_DATUM(1)); - std::vector params; + std::vector params; + params.push_back(TextDatumGetCString(PG_GETARG_DATUM(2))); - params.push_back(PG_GETARG_INT64(2)); - params.push_back(PG_GETARG_INT64(3)); - params.push_back(PG_GETARG_INT64(4)); - params.push_back(PG_GETARG_INT64(5)); - params.push_back(PG_GETARG_INT64(6)); - params.push_back(PG_GETARG_INT64(7)); - params.push_back(PG_GETARG_INT64(8)); - params.push_back(PG_GETARG_INT64(9)); - int64 result = wasm_invoke_function(instanceid, funcname, params); - return Int64GetDatum(result); + char* result = wasm_invoke_function2(instanceid, funcname, params); + return CStringGetTextDatum(result); } -PG_FUNCTION_INFO_V1(wasm_invoke_function_9); -Datum wasm_invoke_function_9(PG_FUNCTION_ARGS) +PG_FUNCTION_INFO_V1(wasm_invoke_function_text_2); +Datum wasm_invoke_function_text_2(PG_FUNCTION_ARGS) { char* instanceid = TextDatumGetCString(PG_GETARG_DATUM(0)); char* funcname = TextDatumGetCString(PG_GETARG_DATUM(1)); - std::vector params; - - params.push_back(PG_GETARG_INT64(2)); - params.push_back(PG_GETARG_INT64(3)); - params.push_back(PG_GETARG_INT64(4)); - params.push_back(PG_GETARG_INT64(5)); - params.push_back(PG_GETARG_INT64(6)); - params.push_back(PG_GETARG_INT64(7)); - params.push_back(PG_GETARG_INT64(8)); - params.push_back(PG_GETARG_INT64(9)); - params.push_back(PG_GETARG_INT64(10)); - int64 result = wasm_invoke_function(instanceid, funcname, params); - return Int64GetDatum(result); -} -PG_FUNCTION_INFO_V1(wasm_invoke_function_10); -Datum wasm_invoke_function_10(PG_FUNCTION_ARGS) -{ - char* instanceid = TextDatumGetCString(PG_GETARG_DATUM(0)); - char* funcname = TextDatumGetCString(PG_GETARG_DATUM(1)); - std::vector params; + std::vector params; + params.push_back(TextDatumGetCString(PG_GETARG_DATUM(2))); + params.push_back(TextDatumGetCString(PG_GETARG_DATUM(3))); - params.push_back(PG_GETARG_INT64(2)); - params.push_back(PG_GETARG_INT64(3)); - params.push_back(PG_GETARG_INT64(4)); - params.push_back(PG_GETARG_INT64(5)); - params.push_back(PG_GETARG_INT64(6)); - params.push_back(PG_GETARG_INT64(7)); - params.push_back(PG_GETARG_INT64(8)); - params.push_back(PG_GETARG_INT64(9)); - params.push_back(PG_GETARG_INT64(10)); - params.push_back(PG_GETARG_INT64(11)); - int64 result = wasm_invoke_function(instanceid, funcname, params); - return Int64GetDatum(result); -} + char* result = wasm_invoke_function2(instanceid, funcname, params); + return CStringGetTextDatum(result); +} \ No newline at end of file