-1
使用PostgreSQL 9.5。來自plpgsql函數的OUT參數在函數中爲NULL,但在單元測試時顯示
這裏是有問題的代碼,從job_parameters():
SELECT
j.controller_id
, j.model_id
, (
SELECT cp.parameters
FROM commit_schema.controller_parameters cp
WHERE cp.parameters_id = j.controller_parameters_id
AND cp.controller_id = j.controller_id
) AS _ctrl_par
, (
SELECT mp.parameters
FROM commit_schema.model_parameters mp
WHERE mp.parameters_id = j.model_parameters_id
AND mp.model_id = j.model_id
) AS _mod_par
, j.initial_glucose_id
INTO
controller_id
, model_id
, controller_parameters
, model_parameters
, initial_glucose_id
FROM
commit_schema.job j
-- INNER JOIN
-- commit_schema.model_parameters mp
-- ON j.model_parameters_id = mp.parameters_id
-- INNER JOIN
-- commit_schema.controller_parameters cp
-- ON j.controller_parameters_id = cp.parameters_id
WHERE j.sim_id = sim_id;
當運行這個查詢在一個單獨的窗口固定SIM_ID(最後WHERE
子句中使用),我得到的所有行的我希望被退回。 SELECT INTO
將此查詢的結果直接移動到此plpgsql函數的OUT
參數中,但運行此函數時,除sim_id
之外的所有列均爲NULL
,這是由於在函數的前面選擇了sim_id
這一事實。
起初我以爲這是由於我用於Inner Join的鍵導致行顯示爲NULL,所以我選擇了子查詢。這在單獨運行此查詢時起作用,但將其整合到函數的其餘部分會導致其失敗。
我嘗試使用RAISE NOTICE '%'
進行疑難解答,然後是單個參數,但似乎無法打印到控制檯。
所有相關功能完整的代碼是在這裏:
DROP DOMAIN IF EXISTS computer_name CASCADE;
CREATE DOMAIN computer_name AS varchar(50);
DROP TYPE IF EXISTS error_cluster CASCADE;
CREATE TYPE error_cluster AS (
error_code integer
, error_msg varchar(100)
);
DROP FUNCTION IF EXISTS select_client_id(computer_name);
CREATE FUNCTION select_client_id (
IN clean_name computer_name DEFAULT 'none'
, OUT client_id integer
)
AS $$
BEGIN
SELECT c.client_id INTO client_id
FROM commit_schema.client c
WHERE c.client_name = $1
LIMIT 1;
END;
$$ LANGUAGE plpgsql;
DROP FUNCTION IF EXISTS get_client_id(computer_name, error_cluster);
CREATE FUNCTION get_client_id (
IN clean_name computer_name DEFAULT 'none'
, IN error_in error_cluster DEFAULT (0,'')
, OUT _client_id integer
, OUT error_out error_cluster)
AS $$
BEGIN
SELECT client_id INTO _client_id
FROM select_client_id(clean_name);
IF _client_id IS NULL THEN
INSERT INTO commit_schema.client (client_name) VALUES (clean_name);
SELECT client_id INTO _client_id
FROM select_client_id(clean_name);
END IF;
IF _client_id IS NULL THEN
SELECT
-10000
, 'No Client ID found after Client Name insert.'
INTO
error_out.error_code
, error_out.error_msg;
ELSE
SELECT
error_in.error_code
, error_in.error_msg
INTO
error_out.error_code
, error_out.error_msg;
END IF;
END;
$$ LANGUAGE plpgsql;
/*
Get a simulation ID
*/
DROP FUNCTION IF EXISTS get_sim_id(error_cluster);
CREATE FUNCTION get_sim_id(
IN error_in error_cluster
, OUT _sim_id integer
, OUT error_out error_cluster)
AS $$
BEGIN
-- SELECT
-- MIN(j.sim_id)
-- INTO
-- _sim_id
-- FROM commit_schema.job j
-- WHERE j.job_status_id = 0;
UPDATE commit_schema.job j
SET job_status_id = 1
FROM (
SELECT sim_id
FROM commit_schema.job
WHERE job_status_id = 0
ORDER BY sim_id
LIMIT 1
FOR UPDATE SKIP LOCKED
) sub
WHERE j.sim_id = sub.sim_id
RETURNING j.sim_id INTO _sim_id;
IF NOT FOUND THEN
SELECT
-10000
, 'No more jobs left to run!'
, -1
INTO
error_out.error_code
, error_out.error_msg
, _sim_id;
ELSE
SELECT
error_in.error_code
, error_in.error_msg
INTO
error_out.error_code
, error_out.error_msg;
END IF;
END;
$$ LANGUAGE plpgsql;
DROP FUNCTION IF EXISTS set_job_status(integer, smallint, error_cluster);
CREATE FUNCTION set_job_status(
IN sim_id integer
, IN status smallint
, IN error_in error_cluster
, OUT error_out error_cluster)
AS $$
BEGIN
UPDATE commit_schema.job j
SET j.job_status_id = $2
WHERE j.sim_id = $1;
IF NOT FOUND THEN
SELECT
-10000
, 'No job with sim_id='||$1
INTO
error_out.error_code
, error_out.error_msg;
ELSE
SELECT
error_in.error_code
, error_in.error_msg
INTO
error_out.error_code
, error_out.error_msg;
END IF;
END;
$$ LANGUAGE plpgsql;
DROP FUNCTION IF EXISTS set_job_status_to_pending(integer, error_cluster);
CREATE FUNCTION set_job_status_to_pending(
IN sim_id integer
, IN error_in error_cluster
, OUT error_out error_cluster)
AS $$
BEGIN
SELECT
sj.error_out.error_code
, sj.error_out.error_msg
INTO
error_out.error_code
, error_out.error_msg
FROM set_job_status($1, 1, error_in.*) sj;
END;
$$ LANGUAGE plpgsql;
DROP FUNCTION IF EXISTS set_job_status_to_running(integer, error_cluster);
CREATE FUNCTION set_job_status_to_running(
IN sim_id integer
, IN error_in error_cluster
, OUT error_out error_cluster)
AS $$
BEGIN
SELECT
sj.error_out.error_code
, sj.error_out.error_msg
INTO
error_out.error_code
, error_out.error_msg
FROM set_job_status($1, 2, error_in.*) sj;
END;
$$ LANGUAGE plpgsql;
DROP FUNCTION IF EXISTS reset_job_status(integer, error_cluster);
CREATE FUNCTION reset_job_status(
IN sim_id integer
, IN error_in error_cluster
, OUT error_out error_cluster)
AS $$
BEGIN
SELECT
sj.error_out.error_code
, sj.error_out.error_msg
INTO
error_out.error_code
, error_out.error_msg
FROM set_job_status($1, 0, error_in.*) sj;
END;
$$ LANGUAGE plpgsql;
DROP FUNCTION IF EXISTS job_parameters(computer_name);
CREATE FUNCTION job_parameters (
IN computer_id computer_name DEFAULT 'none'
, OUT controller_id integer
, OUT sim_id integer
, OUT controller_parameters integer ARRAY
, OUT model_id integer
, OUT model_parameters integer ARRAY
, OUT initial_glucose_id integer
, OUT final_error_code integer
, OUT final_error_msg varchar(100))
AS $$
DECLARE
-- get rid of garbage in the name we receive
clean_name computer_name := lower(regexp_replace(computer_id, '\W+', '', 'g'));
current_error error_cluster;
error_out error_cluster;
BEGIN
SELECT
0
, ''
INTO
current_error.error_code
, current_error.error_msg;
-- -- See if the incoming client already has a client_id
-- -- If it does, use that. Else give it a new one.
SELECT
error_out.error_msg
, error_out.error_code
INTO
current_error.error_msg
, current_error.error_code
FROM get_client_id(clean_name, current_error.*);
-- Get a simulation ID
SELECT
_sim_id
, error_out.error_msg
, error_out.error_code
INTO
sim_id
, current_error.error_msg
, current_error.error_code
FROM get_sim_id(current_error.*);
IF current_error <> (0,'') THEN
SELECT
current_error.error_code
, current_error.error_msg
INTO
final_error_code
, final_error_msg;
RETURN;
END IF;
-- -- Set the job to pending
-- SELECT
-- error_out.error_code
-- , error_out.error_msg
-- INTO
-- current_error.error_code
-- , current_error.error_msg
-- FROM set_job_status_to_pending(sim_id, current_error.*);
-- IF current_error <> (0,'') THEN
-- SELECT
-- current_error.error_code
-- , current_error.error_msg
-- INTO
-- final_error_code
-- , final_error_msg;
-- RETURN;
-- END IF;
-- Get the parameters
SELECT
j.controller_id
, j.model_id
, (
SELECT cp.parameters
FROM commit_schema.controller_parameters cp
WHERE cp.parameters_id = j.controller_parameters_id
AND cp.controller_id = j.controller_id
) AS _ctrl_par
, (
SELECT mp.parameters
FROM commit_schema.model_parameters mp
WHERE mp.parameters_id = j.model_parameters_id
AND mp.model_id = j.model_id
) AS _mod_par
, j.initial_glucose_id
INTO
controller_id
, model_id
, controller_parameters
, model_parameters
, initial_glucose_id
FROM
commit_schema.job j
-- INNER JOIN
-- commit_schema.model_parameters mp
-- ON j.model_parameters_id = mp.parameters_id
-- INNER JOIN
-- commit_schema.controller_parameters cp
-- ON j.controller_parameters_id = cp.parameters_id
WHERE j.sim_id = sim_id;
RAISE NOTICE 'mp: % cp: % simid: %', model_parameters, controller_parameters, sim_id;
IF NOT FOUND THEN
SELECT
current_error.error_msg || 'No row found for sim_id ' || sim_id ||'. '
, -10000
INTO
final_error_msg
, final_error_code;
RETURN;
END IF;
IF controller_id IS NULL THEN
SELECT
current_error.error_msg || 'No Controller ID found for this sim_id. '
, -10000
INTO
current_error.error_msg
, current_error.error_code;
END IF;
IF model_id IS NULL THEN
SELECT
current_error.error_msg || 'No Model ID found for this sim_id. '
, -10000
INTO
current_error.error_msg
, current_error.error_code;
END IF;
IF controller_parameters IS NULL THEN
SELECT
current_error.error_msg || 'No Controller Parameters found for this sim_id. '
, -10000
INTO
current_error.error_msg
, current_error.error_code;
END IF;
IF model_parameters IS NULL THEN
SELECT
current_error.error_msg || 'No Model Parameters found for this sim_id. '
, -10000
INTO
current_error.error_msg
, current_error.error_code;
END IF;
IF current_error = (0,'') THEN
-- If everything went well, set job to running
SELECT
error_out.error_code
, error_out.error_msg
INTO
current_error.error_code
, current_error.error_msg
FROM set_job_status_to_running(sim_id, current_error.*);
ELSE
-- Otherwise we reset the simid
SELECT
error_out.error_code
INTO current_error
FROM reset_job_status(sim_id, current_error.*);
END IF;
SELECT
current_error.error_msg
, current_error.error_code
INTO
final_error_msg
, final_error_code;
END;
$$ LANGUAGE plpgsql;
你應該真正發佈整個功能,讓任何人都能正確理解問題和解決方案。 – Patrick
用全功能創建腳本更新了OP。警告:它不是很漂亮。 – ijustlovemath
問題中有太多(可能不相關的)代碼。 SO不適用於代碼審查,它是一個Q/A網站。 –