Commit | Line | Data |
---|---|---|
97df14cd JM |
1 | BEGIN |
2 | EXECUTE IMMEDIATE 'DROP TABLE stream'; | |
3 | EXCEPTION | |
4 | WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; | |
5 | END; | |
6 | / | |
7 | ||
8 | CREATE TABLE stream ( | |
9 | stream_id integer, | |
10 | open number(1,0), -- stream open (1) or closed (0) | |
11 | data varchar2(4000), -- queued stream data | |
12 | rl_prompt varchar2(4000) -- prompt for readline input | |
13 | ); | |
14 | ||
15 | -- stdin | |
16 | INSERT INTO stream (stream_id, open, data, rl_prompt) | |
17 | VALUES (0, 0, '', ''); | |
18 | -- stdout | |
19 | INSERT INTO stream (stream_id, open, data, rl_prompt) | |
20 | VALUES (1, 0, '', ''); | |
21 | ||
22 | -- --------------------------------------------------------- | |
23 | ||
24 | CREATE OR REPLACE PROCEDURE stream_open(sid integer) AS | |
25 | BEGIN | |
26 | -- DBMS_OUTPUT.PUT_LINE('stream_open(' || sid || ') start'); | |
27 | UPDATE stream SET data = '', rl_prompt = '', open = 1 | |
28 | WHERE stream_id = sid; | |
29 | COMMIT; | |
30 | -- DBMS_OUTPUT.PUT_LINE('stream_open(' || sid || ') done'); | |
31 | END; | |
32 | / | |
33 | ||
34 | CREATE OR REPLACE PROCEDURE stream_close(sid integer) AS | |
35 | BEGIN | |
36 | -- DBMS_OUTPUT.PUT_LINE('stream_close(' || sid || ') start'); | |
37 | UPDATE stream SET rl_prompt = '', open = 0 | |
38 | WHERE stream_id = sid; | |
39 | COMMIT; | |
40 | -- DBMS_OUTPUT.PUT_LINE('stream_close(' || sid || ') done'); | |
41 | END; | |
42 | / | |
43 | ||
44 | -- stream_read: | |
45 | -- read from stream stream_id in stream table. Waits until there is | |
46 | -- either data to return or the stream closes (NULL data). Returns | |
47 | -- NULL when stream is closed. | |
48 | CREATE OR REPLACE FUNCTION stream_read(sid integer DEFAULT 0) | |
49 | RETURN varchar IS | |
50 | PRAGMA AUTONOMOUS_TRANSACTION; | |
51 | input varchar(4000); | |
52 | isopen integer; | |
53 | sleep real; | |
54 | BEGIN | |
55 | sleep := 0.05; | |
56 | -- poll / wait for input | |
57 | WHILE true | |
58 | LOOP | |
59 | -- atomic get and set to empty | |
60 | -- LOCK TABLE stream IN EXCLUSIVE MODE; | |
61 | SELECT data, open INTO input, isopen FROM stream | |
62 | WHERE stream_id = sid; | |
63 | IF isopen = 1 AND input IS NOT NULL THEN | |
64 | UPDATE stream SET data = '' WHERE stream_id = sid; | |
65 | COMMIT; | |
66 | RETURN trim(TRAILING chr(10) FROM input); | |
67 | END IF; | |
68 | -- '' -> no input, NULL -> stream closed | |
69 | --RAISE NOTICE 'read input: [%] %', input, stream_id; | |
70 | IF isopen = 0 THEN | |
71 | raise_application_error( | |
72 | -20000, 'stream_read: stream ''' || sid || ''' is closed', TRUE); | |
73 | END IF; | |
74 | SYS.DBMS_LOCK.SLEEP(sleep); | |
75 | IF sleep < 0.5 THEN | |
76 | sleep := sleep * 1.1; -- backoff | |
77 | END IF; | |
78 | END LOOP; | |
79 | END; | |
80 | / | |
81 | ||
82 | -- stream_readline: | |
83 | -- set prompt and wait for readline style input on the stream | |
84 | CREATE OR REPLACE FUNCTION stream_readline(prompt varchar, sid integer DEFAULT 0) | |
85 | RETURN varchar IS | |
86 | PRAGMA AUTONOMOUS_TRANSACTION; | |
87 | BEGIN | |
88 | -- set prompt / request readline style input | |
89 | -- LOCK TABLE stream IN EXCLUSIVE MODE; | |
90 | UPDATE stream SET rl_prompt = prompt WHERE stream_id = sid; | |
91 | COMMIT; | |
92 | ||
93 | RETURN stream_read(sid); | |
94 | END; | |
95 | / | |
96 | ||
97 | CREATE OR REPLACE PROCEDURE stream_write(input varchar, sid integer DEFAULT 1) AS | |
98 | PRAGMA AUTONOMOUS_TRANSACTION; | |
99 | BEGIN | |
100 | -- LOCK TABLE stream IN EXCLUSIVE MODE; | |
101 | UPDATE stream SET data = data || input WHERE stream_id = sid; | |
102 | COMMIT; | |
103 | END; | |
104 | / | |
105 | ||
106 | CREATE OR REPLACE PROCEDURE stream_writeline(data varchar, sid integer DEFAULT 1) AS | |
107 | PRAGMA AUTONOMOUS_TRANSACTION; | |
108 | BEGIN | |
109 | stream_write(data || chr(10), sid); | |
110 | END; | |
111 | / | |
112 | ||
113 | -- --------------------------------------------------------- | |
114 | ||
115 | -- wait_rl_prompt: | |
116 | -- wait for rl_prompt to be set on the given stream and return the | |
117 | -- rl_prompt value. Errors if stream is already closed. | |
118 | CREATE OR REPLACE FUNCTION stream_wait_rl_prompt(sid integer DEFAULT 0) | |
119 | RETURN varchar IS | |
120 | PRAGMA AUTONOMOUS_TRANSACTION; | |
121 | isopen integer; | |
122 | prompt varchar(4000); | |
123 | sleep real; | |
124 | datas integer; | |
125 | BEGIN | |
126 | sleep := 0.05; | |
127 | WHILE true | |
128 | LOOP | |
9fc524f1 | 129 | LOCK TABLE stream IN EXCLUSIVE MODE; |
97df14cd JM |
130 | SELECT open, rl_prompt INTO isopen, prompt |
131 | FROM stream WHERE stream_id = sid; | |
132 | SELECT count(data) INTO datas FROM stream WHERE data IS NOT NULL; | |
9fc524f1 JM |
133 | |
134 | IF isopen = 0 THEN | |
135 | raise_application_error( | |
136 | -20000, 'stream_wait_rl_prompt: stream ''' || sid || ''' is closed', TRUE); | |
97df14cd | 137 | END IF; |
9fc524f1 JM |
138 | |
139 | -- wait until all channels have flushed | |
140 | IF datas = 0 AND prompt IS NOT NULL THEN | |
97df14cd JM |
141 | UPDATE stream SET rl_prompt = '' WHERE stream_id = sid; |
142 | COMMIT; | |
143 | -- Prompt is returned single-quoted because sqlplus trims | |
144 | -- trailing whitespace in select output. | |
145 | RETURN '''' || prompt || ''''; | |
146 | END IF; | |
9fc524f1 | 147 | COMMIT; |
97df14cd JM |
148 | |
149 | DBMS_LOCK.SLEEP(sleep); | |
150 | IF sleep < 0.5 THEN | |
151 | sleep := sleep * 1.1; -- backoff | |
152 | END IF; | |
153 | END LOOP; | |
154 | END; | |
155 | / | |
156 | ||
157 | CREATE OR REPLACE PROCEDURE stream_wait_flushed(sid integer DEFAULT 1) AS | |
158 | PRAGMA AUTONOMOUS_TRANSACTION; | |
159 | pending integer; | |
160 | sleep real; | |
161 | BEGIN | |
162 | sleep := 0.05; | |
163 | WHILE true | |
164 | LOOP | |
165 | SELECT count(data) INTO pending FROM stream | |
166 | WHERE stream_id = sid AND data IS NOT NULL AND data <> ''; | |
167 | IF pending = 0 THEN RETURN; END IF; | |
168 | DBMS_LOCK.SLEEP(sleep); | |
169 | IF sleep < 0.5 THEN | |
170 | sleep := sleep * 1.1; -- backoff | |
171 | END IF; | |
172 | END LOOP; | |
173 | END; | |
174 | / |