Fix PL/Python for recursion and interleaved set-returning functions.
[pgsql.git] / src / pl / plpython / expected / plpython_spi.out
blobdbde36f8412e76bbdfce196f0dd06a73036dd6a2
1 --
2 -- nested calls
3 --
4 CREATE FUNCTION nested_call_one(a text) RETURNS text
5         AS
6 'q = "SELECT nested_call_two(''%s'')" % a
7 r = plpy.execute(q)
8 return r[0]'
9         LANGUAGE plpythonu ;
10 CREATE FUNCTION nested_call_two(a text) RETURNS text
11         AS
12 'q = "SELECT nested_call_three(''%s'')" % a
13 r = plpy.execute(q)
14 return r[0]'
15         LANGUAGE plpythonu ;
16 CREATE FUNCTION nested_call_three(a text) RETURNS text
17         AS
18 'return a'
19         LANGUAGE plpythonu ;
20 -- some spi stuff
21 CREATE FUNCTION spi_prepared_plan_test_one(a text) RETURNS text
22         AS
23 'if "myplan" not in SD:
24         q = "SELECT count(*) FROM users WHERE lname = $1"
25         SD["myplan"] = plpy.prepare(q, [ "text" ])
26 try:
27         rv = plpy.execute(SD["myplan"], [a])
28         return "there are " + str(rv[0]["count"]) + " " + str(a) + "s"
29 except Exception, ex:
30         plpy.error(str(ex))
31 return None
33         LANGUAGE plpythonu;
34 CREATE FUNCTION spi_prepared_plan_test_nested(a text) RETURNS text
35         AS
36 'if "myplan" not in SD:
37         q = "SELECT spi_prepared_plan_test_one(''%s'') as count" % a
38         SD["myplan"] = plpy.prepare(q)
39 try:
40         rv = plpy.execute(SD["myplan"])
41         if len(rv):
42                 return rv[0]["count"]
43 except Exception, ex:
44         plpy.error(str(ex))
45 return None
47         LANGUAGE plpythonu;
48 CREATE FUNCTION join_sequences(s sequences) RETURNS text
49         AS
50 'if not s["multipart"]:
51         return s["sequence"]
52 q = "SELECT sequence FROM xsequences WHERE pid = ''%s''" % s["pid"]
53 rv = plpy.execute(q)
54 seq = s["sequence"]
55 for r in rv:
56         seq = seq + r["sequence"]
57 return seq
59         LANGUAGE plpythonu;
60 CREATE FUNCTION spi_recursive_sum(a int) RETURNS int
61         AS
62 'r = 0
63 if a > 1:
64     r = plpy.execute("SELECT spi_recursive_sum(%d) as a" % (a-1))[0]["a"]
65 return a + r
67         LANGUAGE plpythonu;
69 -- spi and nested calls
71 select nested_call_one('pass this along');
72                          nested_call_one                         
73 -----------------------------------------------------------------
74  {'nested_call_two': "{'nested_call_three': 'pass this along'}"}
75 (1 row)
77 select spi_prepared_plan_test_one('doe');
78  spi_prepared_plan_test_one 
79 ----------------------------
80  there are 3 does
81 (1 row)
83 select spi_prepared_plan_test_one('smith');
84  spi_prepared_plan_test_one 
85 ----------------------------
86  there are 1 smiths
87 (1 row)
89 select spi_prepared_plan_test_nested('smith');
90  spi_prepared_plan_test_nested 
91 -------------------------------
92  there are 1 smiths
93 (1 row)
95 SELECT join_sequences(sequences) FROM sequences;
96  join_sequences 
97 ----------------
98  ABCDEFGHIJKL
99  ABCDEF
100  ABCDEF
101  ABCDEF
102  ABCDEF
103  ABCDEF
104 (6 rows)
106 SELECT join_sequences(sequences) FROM sequences
107         WHERE join_sequences(sequences) ~* '^A';
108  join_sequences 
109 ----------------
110  ABCDEFGHIJKL
111  ABCDEF
112  ABCDEF
113  ABCDEF
114  ABCDEF
115  ABCDEF
116 (6 rows)
118 SELECT join_sequences(sequences) FROM sequences
119         WHERE join_sequences(sequences) ~* '^B';
120  join_sequences 
121 ----------------
122 (0 rows)
124 SELECT spi_recursive_sum(10);
125  spi_recursive_sum 
126 -------------------
127                 55
128 (1 row)
131 -- plan and result objects
133 CREATE FUNCTION result_metadata_test(cmd text) RETURNS int
134 AS $$
135 plan = plpy.prepare(cmd)
136 plpy.info(plan.status()) # not really documented or useful
137 result = plpy.execute(plan)
138 if result.status() > 0:
139    plpy.info(result.colnames())
140    plpy.info(result.coltypes())
141    plpy.info(result.coltypmods())
142    return result.nrows()
143 else:
144    return None
145 $$ LANGUAGE plpythonu;
146 SELECT result_metadata_test($$SELECT 1 AS foo, '11'::text AS bar UNION SELECT 2, '22'$$);
147 INFO:  True
148 INFO:  ['foo', 'bar']
149 INFO:  [23, 25]
150 INFO:  [-1, -1]
151  result_metadata_test 
152 ----------------------
153                     2
154 (1 row)
156 SELECT result_metadata_test($$CREATE TEMPORARY TABLE foo1 (a int, b text)$$);
157 INFO:  True
158 ERROR:  plpy.Error: command did not produce a result set
159 CONTEXT:  Traceback (most recent call last):
160   PL/Python function "result_metadata_test", line 6, in <module>
161     plpy.info(result.colnames())
162 PL/Python function "result_metadata_test"
163 CREATE FUNCTION result_nrows_test(cmd text) RETURNS int
164 AS $$
165 result = plpy.execute(cmd)
166 return result.nrows()
167 $$ LANGUAGE plpythonu;
168 SELECT result_nrows_test($$SELECT 1$$);
169  result_nrows_test 
170 -------------------
171                  1
172 (1 row)
174 SELECT result_nrows_test($$CREATE TEMPORARY TABLE foo2 (a int, b text)$$);
175  result_nrows_test 
176 -------------------
177                  0
178 (1 row)
180 SELECT result_nrows_test($$INSERT INTO foo2 VALUES (1, 'one'), (2, 'two')$$);
181  result_nrows_test 
182 -------------------
183                  2
184 (1 row)
186 SELECT result_nrows_test($$UPDATE foo2 SET b = '' WHERE a = 2$$);
187  result_nrows_test 
188 -------------------
189                  1
190 (1 row)
192 CREATE FUNCTION result_len_test(cmd text) RETURNS int
193 AS $$
194 result = plpy.execute(cmd)
195 return len(result)
196 $$ LANGUAGE plpythonu;
197 SELECT result_len_test($$SELECT 1$$);
198  result_len_test 
199 -----------------
200                1
201 (1 row)
203 SELECT result_len_test($$CREATE TEMPORARY TABLE foo3 (a int, b text)$$);
204  result_len_test 
205 -----------------
206                0
207 (1 row)
209 SELECT result_len_test($$INSERT INTO foo3 VALUES (1, 'one'), (2, 'two')$$);
210  result_len_test 
211 -----------------
212                0
213 (1 row)
215 SELECT result_len_test($$UPDATE foo3 SET b= '' WHERE a = 2$$);
216  result_len_test 
217 -----------------
218                0
219 (1 row)
221 CREATE FUNCTION result_subscript_test() RETURNS void
222 AS $$
223 result = plpy.execute("SELECT 1 AS c UNION SELECT 2 "
224                       "UNION SELECT 3 UNION SELECT 4")
226 plpy.info(result[1]['c'])
227 plpy.info(result[-1]['c'])
229 plpy.info([item['c'] for item in result[1:3]])
230 plpy.info([item['c'] for item in result[::2]])
232 result[-1] = {'c': 1000}
233 result[:2] = [{'c': 10}, {'c': 100}]
234 plpy.info([item['c'] for item in result[:]])
236 # raises TypeError, but the message differs on Python 2.6, so silence it
237 try:
238     plpy.info(result['foo'])
239 except TypeError:
240     pass
241 else:
242     assert False, "TypeError not raised"
244 $$ LANGUAGE plpythonu;
245 SELECT result_subscript_test();
246 INFO:  2
247 INFO:  4
248 INFO:  [2, 3]
249 INFO:  [1, 3]
250 INFO:  [10, 100, 3, 1000]
251  result_subscript_test 
252 -----------------------
254 (1 row)
256 CREATE FUNCTION result_empty_test() RETURNS void
257 AS $$
258 result = plpy.execute("select 1 where false")
260 plpy.info(result[:])
262 $$ LANGUAGE plpythonu;
263 SELECT result_empty_test();
264 INFO:  []
265  result_empty_test 
266 -------------------
268 (1 row)
270 CREATE FUNCTION result_str_test(cmd text) RETURNS text
271 AS $$
272 plan = plpy.prepare(cmd)
273 result = plpy.execute(plan)
274 return str(result)
275 $$ LANGUAGE plpythonu;
276 SELECT result_str_test($$SELECT 1 AS foo UNION SELECT 2$$);
277                       result_str_test                       
278 ------------------------------------------------------------
279  <PLyResult status=5 nrows=2 rows=[{'foo': 1}, {'foo': 2}]>
280 (1 row)
282 SELECT result_str_test($$CREATE TEMPORARY TABLE foo1 (a int, b text)$$);
283            result_str_test            
284 --------------------------------------
285  <PLyResult status=4 nrows=0 rows=[]>
286 (1 row)
288 -- cursor objects
289 CREATE FUNCTION simple_cursor_test() RETURNS int AS $$
290 res = plpy.cursor("select fname, lname from users")
291 does = 0
292 for row in res:
293     if row['lname'] == 'doe':
294         does += 1
295 return does
296 $$ LANGUAGE plpythonu;
297 CREATE FUNCTION double_cursor_close() RETURNS int AS $$
298 res = plpy.cursor("select fname, lname from users")
299 res.close()
300 res.close()
301 $$ LANGUAGE plpythonu;
302 CREATE FUNCTION cursor_fetch() RETURNS int AS $$
303 res = plpy.cursor("select fname, lname from users")
304 assert len(res.fetch(3)) == 3
305 assert len(res.fetch(3)) == 1
306 assert len(res.fetch(3)) == 0
307 assert len(res.fetch(3)) == 0
308 try:
309     # use next() or __next__(), the method name changed in
310     # http://www.python.org/dev/peps/pep-3114/
311     try:
312         res.next()
313     except AttributeError:
314         res.__next__()
315 except StopIteration:
316     pass
317 else:
318     assert False, "StopIteration not raised"
319 $$ LANGUAGE plpythonu;
320 CREATE FUNCTION cursor_mix_next_and_fetch() RETURNS int AS $$
321 res = plpy.cursor("select fname, lname from users order by fname")
322 assert len(res.fetch(2)) == 2
324 item = None
325 try:
326     item = res.next()
327 except AttributeError:
328     item = res.__next__()
329 assert item['fname'] == 'rick'
331 assert len(res.fetch(2)) == 1
332 $$ LANGUAGE plpythonu;
333 CREATE FUNCTION fetch_after_close() RETURNS int AS $$
334 res = plpy.cursor("select fname, lname from users")
335 res.close()
336 try:
337     res.fetch(1)
338 except ValueError:
339     pass
340 else:
341     assert False, "ValueError not raised"
342 $$ LANGUAGE plpythonu;
343 CREATE FUNCTION next_after_close() RETURNS int AS $$
344 res = plpy.cursor("select fname, lname from users")
345 res.close()
346 try:
347     try:
348         res.next()
349     except AttributeError:
350         res.__next__()
351 except ValueError:
352     pass
353 else:
354     assert False, "ValueError not raised"
355 $$ LANGUAGE plpythonu;
356 CREATE FUNCTION cursor_fetch_next_empty() RETURNS int AS $$
357 res = plpy.cursor("select fname, lname from users where false")
358 assert len(res.fetch(1)) == 0
359 try:
360     try:
361         res.next()
362     except AttributeError:
363         res.__next__()
364 except StopIteration:
365     pass
366 else:
367     assert False, "StopIteration not raised"
368 $$ LANGUAGE plpythonu;
369 CREATE FUNCTION cursor_plan() RETURNS SETOF text AS $$
370 plan = plpy.prepare(
371     "select fname, lname from users where fname like $1 || '%' order by fname",
372     ["text"])
373 for row in plpy.cursor(plan, ["w"]):
374     yield row['fname']
375 for row in plpy.cursor(plan, ["j"]):
376     yield row['fname']
377 $$ LANGUAGE plpythonu;
378 CREATE FUNCTION cursor_plan_wrong_args() RETURNS SETOF text AS $$
379 plan = plpy.prepare("select fname, lname from users where fname like $1 || '%'",
380                     ["text"])
381 c = plpy.cursor(plan, ["a", "b"])
382 $$ LANGUAGE plpythonu;
383 CREATE TYPE test_composite_type AS (
384   a1 int,
385   a2 varchar
387 CREATE OR REPLACE FUNCTION plan_composite_args() RETURNS test_composite_type AS $$
388 plan = plpy.prepare("select $1 as c1", ["test_composite_type"])
389 res = plpy.execute(plan, [{"a1": 3, "a2": "label"}])
390 return res[0]["c1"]
391 $$ LANGUAGE plpythonu;
392 SELECT simple_cursor_test();
393  simple_cursor_test 
394 --------------------
395                   3
396 (1 row)
398 SELECT double_cursor_close();
399  double_cursor_close 
400 ---------------------
401                     
402 (1 row)
404 SELECT cursor_fetch();
405  cursor_fetch 
406 --------------
407              
408 (1 row)
410 SELECT cursor_mix_next_and_fetch();
411  cursor_mix_next_and_fetch 
412 ---------------------------
413                           
414 (1 row)
416 SELECT fetch_after_close();
417  fetch_after_close 
418 -------------------
419                   
420 (1 row)
422 SELECT next_after_close();
423  next_after_close 
424 ------------------
425                  
426 (1 row)
428 SELECT cursor_fetch_next_empty();
429  cursor_fetch_next_empty 
430 -------------------------
431                         
432 (1 row)
434 SELECT cursor_plan();
435  cursor_plan 
436 -------------
437  willem
438  jane
439  john
440 (3 rows)
442 SELECT cursor_plan_wrong_args();
443 ERROR:  TypeError: Expected sequence of 1 argument, got 2: ['a', 'b']
444 CONTEXT:  Traceback (most recent call last):
445   PL/Python function "cursor_plan_wrong_args", line 4, in <module>
446     c = plpy.cursor(plan, ["a", "b"])
447 PL/Python function "cursor_plan_wrong_args"
448 SELECT plan_composite_args();
449  plan_composite_args 
450 ---------------------
451  (3,label)
452 (1 row)