mirror of
https://github.com/kanaka/mal.git
synced 2024-09-21 10:37:58 +03:00
175 lines
5.1 KiB
SQL
175 lines
5.1 KiB
SQL
BEGIN
|
|
EXECUTE IMMEDIATE 'DROP TABLE stream';
|
|
EXCEPTION
|
|
WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF;
|
|
END;
|
|
/
|
|
|
|
CREATE TABLE stream (
|
|
stream_id integer,
|
|
open number(1,0), -- stream open (1) or closed (0)
|
|
data varchar2(4000), -- queued stream data
|
|
rl_prompt varchar2(4000) -- prompt for readline input
|
|
);
|
|
|
|
-- stdin
|
|
INSERT INTO stream (stream_id, open, data, rl_prompt)
|
|
VALUES (0, 0, '', '');
|
|
-- stdout
|
|
INSERT INTO stream (stream_id, open, data, rl_prompt)
|
|
VALUES (1, 0, '', '');
|
|
|
|
-- ---------------------------------------------------------
|
|
|
|
CREATE OR REPLACE PROCEDURE stream_open(sid integer) AS
|
|
BEGIN
|
|
-- DBMS_OUTPUT.PUT_LINE('stream_open(' || sid || ') start');
|
|
UPDATE stream SET data = '', rl_prompt = '', open = 1
|
|
WHERE stream_id = sid;
|
|
COMMIT;
|
|
-- DBMS_OUTPUT.PUT_LINE('stream_open(' || sid || ') done');
|
|
END;
|
|
/
|
|
|
|
CREATE OR REPLACE PROCEDURE stream_close(sid integer) AS
|
|
BEGIN
|
|
-- DBMS_OUTPUT.PUT_LINE('stream_close(' || sid || ') start');
|
|
UPDATE stream SET rl_prompt = '', open = 0
|
|
WHERE stream_id = sid;
|
|
COMMIT;
|
|
-- DBMS_OUTPUT.PUT_LINE('stream_close(' || sid || ') done');
|
|
END;
|
|
/
|
|
|
|
-- stream_read:
|
|
-- read from stream stream_id in stream table. Waits until there is
|
|
-- either data to return or the stream closes (NULL data). Returns
|
|
-- NULL when stream is closed.
|
|
CREATE OR REPLACE FUNCTION stream_read(sid integer DEFAULT 0)
|
|
RETURN varchar IS
|
|
PRAGMA AUTONOMOUS_TRANSACTION;
|
|
input varchar(4000);
|
|
isopen integer;
|
|
sleep real;
|
|
BEGIN
|
|
sleep := 0.05;
|
|
-- poll / wait for input
|
|
WHILE true
|
|
LOOP
|
|
-- atomic get and set to empty
|
|
-- LOCK TABLE stream IN EXCLUSIVE MODE;
|
|
SELECT data, open INTO input, isopen FROM stream
|
|
WHERE stream_id = sid;
|
|
IF isopen = 1 AND input IS NOT NULL THEN
|
|
UPDATE stream SET data = '' WHERE stream_id = sid;
|
|
COMMIT;
|
|
RETURN trim(TRAILING chr(10) FROM input);
|
|
END IF;
|
|
-- '' -> no input, NULL -> stream closed
|
|
--RAISE NOTICE 'read input: [%] %', input, stream_id;
|
|
IF isopen = 0 THEN
|
|
raise_application_error(
|
|
-20000, 'stream_read: stream ''' || sid || ''' is closed', TRUE);
|
|
END IF;
|
|
SYS.DBMS_LOCK.SLEEP(sleep);
|
|
IF sleep < 0.5 THEN
|
|
sleep := sleep * 1.1; -- backoff
|
|
END IF;
|
|
END LOOP;
|
|
END;
|
|
/
|
|
|
|
-- stream_readline:
|
|
-- set prompt and wait for readline style input on the stream
|
|
CREATE OR REPLACE FUNCTION stream_readline(prompt varchar, sid integer DEFAULT 0)
|
|
RETURN varchar IS
|
|
PRAGMA AUTONOMOUS_TRANSACTION;
|
|
BEGIN
|
|
-- set prompt / request readline style input
|
|
-- LOCK TABLE stream IN EXCLUSIVE MODE;
|
|
UPDATE stream SET rl_prompt = prompt WHERE stream_id = sid;
|
|
COMMIT;
|
|
|
|
RETURN stream_read(sid);
|
|
END;
|
|
/
|
|
|
|
CREATE OR REPLACE PROCEDURE stream_write(input varchar, sid integer DEFAULT 1) AS
|
|
PRAGMA AUTONOMOUS_TRANSACTION;
|
|
BEGIN
|
|
-- LOCK TABLE stream IN EXCLUSIVE MODE;
|
|
UPDATE stream SET data = data || input WHERE stream_id = sid;
|
|
COMMIT;
|
|
END;
|
|
/
|
|
|
|
CREATE OR REPLACE PROCEDURE stream_writeline(data varchar, sid integer DEFAULT 1) AS
|
|
PRAGMA AUTONOMOUS_TRANSACTION;
|
|
BEGIN
|
|
stream_write(data || chr(10), sid);
|
|
END;
|
|
/
|
|
|
|
-- ---------------------------------------------------------
|
|
|
|
-- wait_rl_prompt:
|
|
-- wait for rl_prompt to be set on the given stream and return the
|
|
-- rl_prompt value. Errors if stream is already closed.
|
|
CREATE OR REPLACE FUNCTION stream_wait_rl_prompt(sid integer DEFAULT 0)
|
|
RETURN varchar IS
|
|
PRAGMA AUTONOMOUS_TRANSACTION;
|
|
isopen integer;
|
|
prompt varchar(4000);
|
|
sleep real;
|
|
datas integer;
|
|
BEGIN
|
|
sleep := 0.05;
|
|
WHILE true
|
|
LOOP
|
|
LOCK TABLE stream IN EXCLUSIVE MODE;
|
|
SELECT open, rl_prompt INTO isopen, prompt
|
|
FROM stream WHERE stream_id = sid;
|
|
SELECT count(data) INTO datas FROM stream WHERE data IS NOT NULL;
|
|
|
|
IF isopen = 0 THEN
|
|
raise_application_error(
|
|
-20000, 'stream_wait_rl_prompt: stream ''' || sid || ''' is closed', TRUE);
|
|
END IF;
|
|
|
|
-- wait until all channels have flushed
|
|
IF datas = 0 AND prompt IS NOT NULL THEN
|
|
UPDATE stream SET rl_prompt = '' WHERE stream_id = sid;
|
|
COMMIT;
|
|
-- Prompt is returned single-quoted because sqlplus trims
|
|
-- trailing whitespace in select output.
|
|
RETURN '''' || prompt || '''';
|
|
END IF;
|
|
COMMIT;
|
|
|
|
DBMS_LOCK.SLEEP(sleep);
|
|
IF sleep < 0.5 THEN
|
|
sleep := sleep * 1.1; -- backoff
|
|
END IF;
|
|
END LOOP;
|
|
END;
|
|
/
|
|
|
|
CREATE OR REPLACE PROCEDURE stream_wait_flushed(sid integer DEFAULT 1) AS
|
|
PRAGMA AUTONOMOUS_TRANSACTION;
|
|
pending integer;
|
|
sleep real;
|
|
BEGIN
|
|
sleep := 0.05;
|
|
WHILE true
|
|
LOOP
|
|
SELECT count(data) INTO pending FROM stream
|
|
WHERE stream_id = sid AND data IS NOT NULL AND data <> '';
|
|
IF pending = 0 THEN RETURN; END IF;
|
|
DBMS_LOCK.SLEEP(sleep);
|
|
IF sleep < 0.5 THEN
|
|
sleep := sleep * 1.1; -- backoff
|
|
END IF;
|
|
END LOOP;
|
|
END;
|
|
/
|