因此,我在plpgsql上遇到了一些问题,我不知道自己可能做错了什么。我创建了一个复合类型,该类型在plpgsql函数中用作返回值,以便在另一个函数中获取它。问题在于,这与我预期的方式不符。
这是我的复合类型:
CREATE TYPE sync.sync_conn_data AS (
sync_conn_name VARCHAR,
sync_active BOOLEAN,
sync_use_ssl BOOLEAN,
lcl_ctry VARCHAR,
lcl_dbhostaddr VARCHAR,
lcl_dbname VARCHAR,
lcl_dbuser VARCHAR,
lcl_dbpasswd VARCHAR,
rmte_ctry VARCHAR,
rmte_dbhostaddr VARCHAR,
rmte_dbname VARCHAR,
rmte_dbuser VARCHAR,
rmte_dbpasswd VARCHAR,
timezone VARCHAR
);
这是返回它的函数:
CREATE OR REPLACE FUNCTION sync.sync_connect (
param_name VARCHAR = 'sync_db'::VARCHAR
)
RETURNS sync.sync_conn_data AS
$body$
DECLARE
sync_connrcd sync.sync_conn_data;
BEGIN
WITH all_conn_prms AS (
SELECT (CASE WHEN param_name = 'local_country' THEN param_value ELSE NULL END) AS local_country,
(CASE WHEN param_name = 'sync_active' THEN param_value ELSE NULL END) AS sync_active,
(CASE WHEN param_name = 'sync_use_ssl' THEN param_value ELSE NULL END) AS sync_use_ssl,
(CASE WHEN param_name = 'ago_dbhostaddr' THEN param_value ELSE NULL END) AS ago_dbhostaddr,
(CASE WHEN param_name = 'ago_dbname' THEN param_value ELSE NULL END) AS ago_dbname,
(CASE WHEN param_name = 'ago_dbuser' THEN param_value ELSE NULL END) AS ago_dbuser,
(CASE WHEN param_name = 'ago_dbpasswd' THEN param_value ELSE NULL END) AS ago_dbpasswd,
(CASE WHEN param_name = 'cub_dbhostaddr' THEN param_value ELSE NULL END) AS cub_dbhostaddr,
(CASE WHEN param_name = 'cub_dbname' THEN param_value ELSE NULL END) AS cub_dbname,
(CASE WHEN param_name = 'cub_dbuser' THEN param_value ELSE NULL END) AS cub_dbuser,
(CASE WHEN param_name = 'cub_dbpasswd' THEN param_value ELSE NULL END) AS cub_dbpasswd
FROM sync.sync_config_params
WHERE param_name IN ('local_country','sync_active','sync_use_ssl','ago_dbhostaddr','ago_dbname','ago_dbuser','ago_dbpasswd','cub_dbhostaddr','cub_dbname','cub_dbuser','cub_dbpasswd')
),
fltd_conn_prms AS (
SELECT string_agg(all_conn_prms.local_country, ',') AS local_country,
string_agg(all_conn_prms.sync_active, ',') AS sync_active,
string_agg(all_conn_prms.sync_use_ssl, ',') AS sync_use_ssl,
string_agg(all_conn_prms.ago_dbhostaddr, ',') AS ago_dbhostaddr,
string_agg(all_conn_prms.ago_dbname, ',') AS ago_dbname,
string_agg(all_conn_prms.ago_dbuser, ',') AS ago_dbuser,
string_agg(all_conn_prms.ago_dbpasswd, ',') AS ago_dbpasswd,
string_agg(all_conn_prms.cub_dbhostaddr, ',') AS cub_dbhostaddr,
string_agg(all_conn_prms.cub_dbname, ',') AS cub_dbname,
string_agg(all_conn_prms.cub_dbuser, ',') AS cub_dbuser,
string_agg(all_conn_prms.cub_dbpasswd, ',') AS cub_dbpasswd
FROM all_conn_prms
)
SELECT coalesce(sync_conn_name, 'sync_db') AS sync_conn_name,
fltd_conn_prms.sync_active,
fltd_conn_prms.sync_use_ssl,
fltd_conn_prms.local_country AS lcl_ctry,
(CASE fltd_conn_prms.local_country WHEN 'AGO' THEN fltd_conn_prms.ago_dbhostaddr WHEN 'CUB' THEN fltd_conn_prms.cub_dbhostaddr ELSE NULL END) AS lcl_dbhostaddr,
(CASE fltd_conn_prms.local_country WHEN 'AGO' THEN fltd_conn_prms.ago_dbname WHEN 'CUB' THEN fltd_conn_prms.cub_dbname ELSE NULL END) AS lcl_dbname,
(CASE fltd_conn_prms.local_country WHEN 'AGO' THEN fltd_conn_prms.ago_dbuser WHEN 'CUB' THEN fltd_conn_prms.cub_dbuser ELSE NULL END) AS lcl_dbuser,
(CASE fltd_conn_prms.local_country WHEN 'AGO' THEN fltd_conn_prms.ago_dbpasswd WHEN 'CUB' THEN fltd_conn_prms.cub_dbpasswd ELSE NULL END) AS lcl_dbpasswd,
(CASE fltd_conn_prms.local_country WHEN 'AGO' THEN 'CUB' WHEN 'CUB' THEN 'AGO' ELSE NULL END) AS rmte_ctry,
(CASE fltd_conn_prms.local_country WHEN 'AGO' THEN fltd_conn_prms.cub_dbhostaddr WHEN 'CUB' THEN fltd_conn_prms.ago_dbhostaddr ELSE NULL END) AS rmte_dbhostaddr,
(CASE fltd_conn_prms.local_country WHEN 'AGO' THEN fltd_conn_prms.cub_dbname WHEN 'CUB' THEN fltd_conn_prms.ago_dbname ELSE NULL END) AS rmte_dbname,
(CASE fltd_conn_prms.local_country WHEN 'AGO' THEN fltd_conn_prms.cub_dbuser WHEN 'CUB' THEN fltd_conn_prms.ago_dbuser ELSE NULL END) AS rmte_dbuser,
(CASE fltd_conn_prms.local_country WHEN 'AGO' THEN fltd_conn_prms.cub_dbpasswd WHEN 'CUB' THEN fltd_conn_prms.ago_dbpasswd ELSE NULL END) AS rmte_dbpasswd,
current_setting('TIMEZONE') AS timezone
INTO sync_connrcd
FROM fltd_conn_prms;
IF NOT FOUND THEN
RAISE EXCEPTION 'Exception text...';
END IF;
RETURN sync_connrcd;
EXCEPTION
WHEN others THEN
RAISE NOTICE 'SQLERRM -> %', quote_nullable(SQLERRM);
INSERT INTO sync.sync_exec_log (log_type, log_msg) VALUES (1, SQLERRM);
RETURN sync_connrcd;
END;
$body$
LANGUAGE 'plpgsql'
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER
COST 100;
这是我期望结果的功能:
CREATE OR REPLACE FUNCTION sync.validate_config (
// input params...
)
RETURNS pg_catalog.void AS
$body$
DECLARE
conn_data sync.sync_conn_data;
// ...
BEGIN
SELECT sync.sync_connect('sync_cfg_mgmt') INTO conn_data;
IF conn_data.lcl_ctry IS NULL OR conn_data.lcl_dbname IS NULL OR conn_data.lcl_dbhostaddr IS NULL OR conn_data.lcl_dbuser IS NULL OR conn_data.lcl_dbpasswd IS NULL OR conn_data.rmte_ctry IS NULL OR conn_data.rmte_dbname IS NULL OR conn_data.rmte_dbhostaddr IS NULL OR conn_data.rmte_dbuser IS NULL OR conn_data.rmte_dbpasswd IS NULL THEN
RAISE EXCEPTION 'No data obtained';
END IF;
// more code ...
EXCEPTION
WHEN others THEN
RAISE NOTICE 'SQLERRM -> %', quote_nullable(SQLERRM);
INSERT INTO sync.sync_exec_log (log_type, log_msg) VALUES (1, quote_nullable(SQLERRM));
END;
$body$
LANGUAGE 'plpgsql'
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER
COST 100;
一个有趣的事实是,使用PostgreSQL的EMS SQL Manager进行调试,此代码可以完美地工作,但是当通过任何客户端执行功能sync.validate_config()
时,都会抛出未获得任何数据的异常,“导致所有conn_data
对象中的字段为null,但第一个字段除外,该字段包含所有对象信息。这是在函数中得到结果后将这个倍数RAISE NOTICE
放入的结果:
RAISE NOTICE '%', conn_data.sync_conn_name;
RAISE NOTICE '%', conn_data.sync_active;
RAISE NOTICE '%', conn_data.sync_use_ssl;
RAISE NOTICE '%', conn_data.lcl_ctry;
RAISE NOTICE '%', conn_data.lcl_dbhostaddr;
RAISE NOTICE '%', conn_data.lcl_dbname;
RAISE NOTICE '%', conn_data.lcl_dbuser;
RAISE NOTICE '%', conn_data.lcl_dbpasswd;
RAISE NOTICE '%', conn_data.rmte_ctry;
RAISE NOTICE '%', conn_data.rmte_dbhostaddr;
RAISE NOTICE '%', conn_data.rmte_dbname;
RAISE NOTICE '%', conn_data.rmte_dbuser;
RAISE NOTICE '%', conn_data.rmte_dbpasswd;
RAISE NOTICE '%', conn_data.timezone;
谢谢。
答案 0 :(得分:0)
由于没有人回答我的问题,并且我有点着急,因此我寻找解决该问题的替代方法。我现在分享我找到的解决方案,以防其他任何人遇到这种问题。
我将de plpgsql hstore module用于sync.sync_connect()
函数的返回类型,以这种方式:
CREATE OR REPLACE FUNCTION sync.sync_connect (
sync_conn_name VARCHAR = 'sync_db'::VARCHAR
)
RETURNS hstore AS
$body$
DECLARE
sync_connrcd sync.sync_conn_data;
BEGIN
/* Same code as before, where sync_connrcd is filled */
RAISE NOTICE 'conn_data -> %', row_to_json(sync_connrcd);
RETURN hstore(sync_connrcd);
EXCEPTION
WHEN others THEN
RAISE NOTICE 'SQLERRM -> %', quote_nullable(SQLERRM);
INSERT INTO sync.sync_exec_log (log_type, log_msg) VALUES (1, SQLERRM);
RETURN hstore(sync_connrcd);
END;
$body$
LANGUAGE 'plpgsql'
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER
COST 100;
然后,在sync.validate_config()
函数中,通过以下方式将结果存储到hstore
对象中:
CREATE OR REPLACE FUNCTION sync.validate_config (
/* input params */
)
RETURNS pg_catalog.void AS
$body$
DECLARE
conn_data hstore;
/* more variables */
BEGIN
SELECT sync.sync_connect('sync_cfg_mgmt') INTO conn_data;
IF NOT exist(conn_data, 'lcl_ctry') OR NOT defined(conn_data, 'lcl_ctry') OR
NOT exist(conn_data, 'lcl_dbname') OR NOT defined(conn_data, 'lcl_dbname') OR
NOT exist(conn_data, 'lcl_dbhostaddr') OR NOT defined(conn_data, 'lcl_dbhostaddr') OR
NOT exist(conn_data, 'lcl_dbuser') OR NOT defined(conn_data, 'lcl_dbuser') OR
NOT exist(conn_data, 'lcl_dbpasswd') OR NOT defined(conn_data, 'lcl_dbpasswd') OR
NOT exist(conn_data, 'rmte_ctry') OR NOT defined(conn_data, 'rmte_ctry') OR
NOT exist(conn_data, 'rmte_dbname') OR NOT defined(conn_data, 'rmte_dbname') OR
NOT exist(conn_data, 'rmte_dbhostaddr') OR NOT defined(conn_data, 'rmte_dbhostaddr') OR
NOT exist(conn_data, 'rmte_dbuser') OR NOT defined(conn_data, 'rmte_dbuser') OR
NOT exist(conn_data, 'rmte_dbpasswd') OR NOT defined(conn_data, 'rmte_dbpasswd') THEN
RAISE EXCEPTION 'No data obtained';
END IF;
/* more code */
EXCEPTION
WHEN others THEN
RAISE NOTICE 'SQLERRM -> %', quote_nullable(SQLERRM);
INSERT INTO sync.sync_exec_log (log_type, log_msg) VALUES (1, SQLERRM);
END;
$body$
LANGUAGE 'plpgsql'
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER
COST 100;
要访问对象中的任何值,请按照conn_data->'rmte_dbname'
进行操作。
仅此而已,对我来说一切正常。