DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;
CREATE TABLE primes
( pos SERIAL NOT NULL PRIMARY KEY
, val INTEGER NOT NULL
, CONSTRAINT primes_alt UNIQUE (val)
);
CREATE FUNCTION is_prime(_val INTEGER)
RETURNS BOOLEAN
AS $func$
DECLARE ret BOOLEAN ;
BEGIN
SELECT False INTO ret
WHERE EXISTS (SELECT *
FROM primes ex
WHERE ex.val = $1
OR ( (ex.val * ex.val) <= $1 AND ($1 % ex.val) = 0 )
);
RETURN COALESCE(ret, True);
END;
$func$ LANGUAGE plpgsql STABLE;
CREATE VIEW vw_prime_step AS (
-- Note when the table is empty we return {2,3,1} as a bootstrap
SELECT
COALESCE(MAX(val) +2,2) AS start
, COALESCE((MAX(val) * MAX(val))-1, 3) AS stop
, COALESCE(min(val), 1) AS step
FROM primes
);
SELECT * FROM vw_prime_step;
-- The same as a function.
-- Works, but is not usable in a query that alters the primes table.
-- ; even not with the TEMP TABLE construct
CREATE FUNCTION fnc_prime_step ( OUT start INTEGER, OUT stop INTEGER, OUT step INTEGER)
RETURNS RECORD
AS $func$
BEGIN
/***
CREATE TEMP TABLE tmp_limits
ON COMMIT DROP
AS SELECT ps.start,ps.stop,ps.step FROM vw_prime_step ps
;
-- RETURN QUERY
SELECT tl.start,tl.stop,tl.step INTO $1,$2,$3
FROM tmp_limits tl
LIMIT 1
;
***/
SELECT tl.start,tl.stop,tl.step INTO $1,$2,$3
FROM vw_prime_step tl
LIMIT 1;
END;
$func$
-- Try lying ...
-- IMMUTABLE LANGUAGE plpgsql;
-- Try lying ...
Stable LANGUAGE plpgsql;
-- This works
SELECT * FROM fnc_prime_step();
INSERT INTO primes (val)
SELECT gs FROM fnc_prime_step() sss
, generate_series( 2, 3, 1 ) gs
WHERE is_prime(gs) = True
;
-- This works
SELECT * FROM fnc_prime_step();
INSERT INTO primes (val)
SELECT gs FROM fnc_prime_step() sss
, generate_series( 5, 24, 2 ) gs
WHERE is_prime(gs) = True
;
-- This does not work
-- ERROR: function expression in FROM cannot refer to other relations of same query level:1
SELECT * FROM fnc_prime_step();
INSERT INTO primes (val)
SELECT gs FROM fnc_prime_step() sss
, generate_series( sss.start, sss.stop, sss.step ) gs
WHERE is_prime(gs) = True
;
SELECT * FROM primes;
SELECT * FROM fnc_prime_step();
当然,这个问题纯粹是假设性的,我还没有愚蠢到试图在 DBMS 中计算素数表。但问题仍然存在:有没有一种干净的方法来解决没有 的问题LATERAL
?
正如你所看到的,我尝试了一个视图(不起作用),围绕这个视图的函数(也不起作用),这个函数中的一个临时表(njet),并调整了函数的属性。
下一步可能是一些触发黑客(但我真的非常讨厌触发器,主要是因为它们对于 DBMS 模式的严格性是不可见的)