mirror of
https://github.com/postgres/postgres.git
synced 2026-07-08 09:10:57 -04:00
Commit 0b7719f74 added regression tests that spell the language name
as plpython3u. That works on the master branch, but on v14 the
plpython tests must use the unversioned name plpythonu: the plpython3u
extension is built only in Python 3 builds, and for those builds
regress-python3-mangle.mk rewrites plpythonu to plpython3u in the test
files. In a Python 2 build the new tests instead failed with
"language \"plpython3u\" does not exist".
Spell the language as plpythonu in the new tests, matching every other
plpython test in this branch, so they work in both Python 2 and Python
3 builds. This is needed only in v14; later branches no longer
support Python 2 and have dropped the mangling step.
Per buildfarm member hippopotamus.
195 lines
3.8 KiB
PL/PgSQL
195 lines
3.8 KiB
PL/PgSQL
CREATE EXTENSION hstore_plpython2u CASCADE;
|
|
|
|
|
|
-- test hstore -> python
|
|
CREATE FUNCTION test1(val hstore) RETURNS int
|
|
LANGUAGE plpythonu
|
|
TRANSFORM FOR TYPE hstore
|
|
AS $$
|
|
assert isinstance(val, dict)
|
|
plpy.info(sorted(val.items()))
|
|
return len(val)
|
|
$$;
|
|
|
|
SELECT test1('aa=>bb, cc=>NULL'::hstore);
|
|
|
|
|
|
-- the same with the versioned language name
|
|
CREATE FUNCTION test1n(val hstore) RETURNS int
|
|
LANGUAGE plpython2u
|
|
TRANSFORM FOR TYPE hstore
|
|
AS $$
|
|
assert isinstance(val, dict)
|
|
plpy.info(sorted(val.items()))
|
|
return len(val)
|
|
$$;
|
|
|
|
SELECT test1n('aa=>bb, cc=>NULL'::hstore);
|
|
|
|
|
|
-- test that a non-mapping result is correctly rejected
|
|
CREATE FUNCTION test1bad() RETURNS hstore
|
|
LANGUAGE plpythonu
|
|
TRANSFORM FOR TYPE hstore
|
|
AS $$
|
|
return "foo"
|
|
$$;
|
|
|
|
SELECT test1bad();
|
|
|
|
|
|
-- A mapping whose items() raises should be reported as an error, not crash
|
|
-- the backend
|
|
CREATE FUNCTION test1broken() RETURNS hstore
|
|
LANGUAGE plpythonu
|
|
TRANSFORM FOR TYPE hstore
|
|
AS $$
|
|
class C(dict):
|
|
def items(self):
|
|
raise ValueError('items failed')
|
|
d = C()
|
|
d['x'] = 1
|
|
return d
|
|
$$;
|
|
|
|
SELECT test1broken();
|
|
|
|
|
|
-- Likewise for a mapping whose items() does not return key/value pairs
|
|
CREATE FUNCTION test1malformed() RETURNS hstore
|
|
LANGUAGE plpythonu
|
|
TRANSFORM FOR TYPE hstore
|
|
AS $$
|
|
class C(dict):
|
|
def items(self):
|
|
return [42]
|
|
d = C()
|
|
d['x'] = 1
|
|
return d
|
|
$$;
|
|
|
|
SELECT test1malformed();
|
|
|
|
|
|
-- Likewise for a mapping whose items() yields fewer pairs than its length
|
|
CREATE FUNCTION test1short() RETURNS hstore
|
|
LANGUAGE plpythonu
|
|
TRANSFORM FOR TYPE hstore
|
|
AS $$
|
|
class C(dict):
|
|
def items(self):
|
|
return []
|
|
d = C()
|
|
d['x'] = 1
|
|
return d
|
|
$$;
|
|
|
|
SELECT test1short();
|
|
|
|
|
|
-- Likewise for a mapping whose __len__() raises
|
|
CREATE FUNCTION test1brokenlen() RETURNS hstore
|
|
LANGUAGE plpythonu
|
|
TRANSFORM FOR TYPE hstore
|
|
AS $$
|
|
class C(dict):
|
|
def __len__(self):
|
|
raise ValueError('len failed')
|
|
d = C()
|
|
d['x'] = 1
|
|
return d
|
|
$$;
|
|
|
|
SELECT test1brokenlen();
|
|
|
|
|
|
-- test hstore[] -> python
|
|
CREATE FUNCTION test1arr(val hstore[]) RETURNS int
|
|
LANGUAGE plpythonu
|
|
TRANSFORM FOR TYPE hstore
|
|
AS $$
|
|
assert(val == [{'aa': 'bb', 'cc': None}, {'dd': 'ee'}])
|
|
return len(val)
|
|
$$;
|
|
|
|
SELECT test1arr(array['aa=>bb, cc=>NULL'::hstore, 'dd=>ee']);
|
|
|
|
|
|
-- test python -> hstore
|
|
CREATE FUNCTION test2(a int, b text) RETURNS hstore
|
|
LANGUAGE plpythonu
|
|
TRANSFORM FOR TYPE hstore
|
|
AS $$
|
|
val = {'a': a, 'b': b, 'c': None}
|
|
return val
|
|
$$;
|
|
|
|
SELECT test2(1, 'boo');
|
|
|
|
--- test ruleutils
|
|
\sf test2
|
|
|
|
|
|
-- test python -> hstore[]
|
|
CREATE FUNCTION test2arr() RETURNS hstore[]
|
|
LANGUAGE plpythonu
|
|
TRANSFORM FOR TYPE hstore
|
|
AS $$
|
|
val = [{'a': 1, 'b': 'boo', 'c': None}, {'d': 2}]
|
|
return val
|
|
$$;
|
|
|
|
SELECT test2arr();
|
|
|
|
|
|
-- test python -> domain over hstore
|
|
CREATE DOMAIN hstore_foo AS hstore CHECK(VALUE ? 'foo');
|
|
|
|
CREATE FUNCTION test2dom(fn text) RETURNS hstore_foo
|
|
LANGUAGE plpythonu
|
|
TRANSFORM FOR TYPE hstore
|
|
AS $$
|
|
return {'a': 1, fn: 'boo', 'c': None}
|
|
$$;
|
|
|
|
SELECT test2dom('foo');
|
|
SELECT test2dom('bar'); -- fail
|
|
|
|
|
|
-- test as part of prepare/execute
|
|
CREATE FUNCTION test3() RETURNS void
|
|
LANGUAGE plpythonu
|
|
TRANSFORM FOR TYPE hstore
|
|
AS $$
|
|
rv = plpy.execute("SELECT 'aa=>bb, cc=>NULL'::hstore AS col1")
|
|
assert(rv[0]["col1"] == {'aa': 'bb', 'cc': None})
|
|
|
|
val = {'a': 1, 'b': 'boo', 'c': None}
|
|
plan = plpy.prepare("SELECT $1::text AS col1", ["hstore"])
|
|
rv = plpy.execute(plan, [val])
|
|
assert(rv[0]["col1"] == '"a"=>"1", "b"=>"boo", "c"=>NULL')
|
|
$$;
|
|
|
|
SELECT test3();
|
|
|
|
|
|
-- test trigger
|
|
CREATE TABLE test1 (a int, b hstore);
|
|
INSERT INTO test1 VALUES (1, 'aa=>bb, cc=>NULL');
|
|
SELECT * FROM test1;
|
|
|
|
CREATE FUNCTION test4() RETURNS trigger
|
|
LANGUAGE plpythonu
|
|
TRANSFORM FOR TYPE hstore
|
|
AS $$
|
|
assert(TD["new"] == {'a': 1, 'b': {'aa': 'bb', 'cc': None}})
|
|
if TD["new"]["a"] == 1:
|
|
TD["new"]["b"] = {'a': 1, 'b': 'boo', 'c': None}
|
|
|
|
return "MODIFY"
|
|
$$;
|
|
|
|
CREATE TRIGGER test4 BEFORE UPDATE ON test1 FOR EACH ROW EXECUTE PROCEDURE test4();
|
|
|
|
UPDATE test1 SET a = a;
|
|
SELECT * FROM test1;
|